Timeout outgoing connections in 10 seconds, reduce memory allocations, use sync.Pool for storing allocations

This commit is contained in:
DataHoarder 2022-11-07 23:59:52 +01:00
parent cec700beac
commit 7929753c40
Signed by: DataHoarder
SSH key fingerprint: SHA256:OLTRf6Fl87G52SiR7sWLGNzlJt4WOX+tfI2yxo0z7xk
24 changed files with 267 additions and 150 deletions

View file

@ -7,6 +7,7 @@ import (
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/crypto"
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
"log"
"sync/atomic"
"testing"
)
@ -53,19 +54,26 @@ func TestSort(t *testing.T) {
}
func BenchmarkCoinbaseDerivation(b *testing.B) {
b.ReportAllocs()
packed := testAddress3.ToPackedAddress()
txKey := crypto.PrivateKeyFromScalar(privateKey)
for i := 0; i < b.N; i++ {
GetEphemeralPublicKey(packed, txKey, uint64(i))
}
var i atomic.Uint64
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
GetEphemeralPublicKey(packed, txKey, i.Load())
}
})
}
func BenchmarkCoinbaseDerivationInline(b *testing.B) {
packed := testAddress3.ToPackedAddress()
spendPub, viewPub := packed.SpendPublicKey().AsPoint().Point(), packed.ViewPublicKey().AsPoint().Point()
p := new(edwards25519.Point)
for i := 0; i < b.N; i++ {
getEphemeralPublicKeyInline(spendPub, viewPub, privateKey, uint64(i), p)
}
}
var i atomic.Uint64
b.RunParallel(func(pb *testing.PB) {
p := new(edwards25519.Point)
for pb.Next() {
getEphemeralPublicKeyInline(spendPub, viewPub, privateKey, i.Load(), p)
}
})
}

View file

@ -22,7 +22,7 @@ func GetEphemeralPublicKey(a Interface, txKey crypto.PrivateKey, outputIndex uin
return GetPublicKeyForSharedData(a, crypto.GetDerivationSharedDataForOutputIndex(txKey.GetDerivationCofactor(a.ViewPublicKey()), outputIndex))
}
func getEphemeralPublicKeyInline(spendPub, viewPub *edwards25519.Point, txKey *edwards25519.Scalar, outputIndex uint64, p *edwards25519.Point) {
func getEphemeralPublicKeyInline(spendPub, viewPub *edwards25519.Point, txKey *edwards25519.Scalar, outputIndex uint64, p *edwards25519.Point) {
//derivation
p.ScalarMult(txKey, viewPub).MultByCofactor(p)
@ -41,7 +41,7 @@ func GetEphemeralPublicKeyAndViewTag(a Interface, txKey crypto.PrivateKey, outpu
}
func GetTxProofV2(a Interface, txId types.Hash, txKey crypto.PrivateKey, message string) string {
prefixHash := types.Hash(moneroutil.Keccak256(txId[:], []byte(message)))
prefixHash := crypto.Keccak256(txId[:], []byte(message))
sharedSecret, signature := crypto.GenerateTxProofV2(prefixHash, txKey, a.ViewPublicKey(), nil)
@ -49,7 +49,7 @@ func GetTxProofV2(a Interface, txId types.Hash, txKey crypto.PrivateKey, message
}
func GetTxProofV1(a Interface, txId types.Hash, txKey crypto.PrivateKey, message string) string {
prefixHash := types.Hash(moneroutil.Keccak256(txId[:], []byte(message)))
prefixHash := crypto.Keccak256(txId[:], []byte(message))
sharedSecret, signature := crypto.GenerateTxProofV1(prefixHash, txKey, a.ViewPublicKey(), nil)
@ -65,21 +65,21 @@ const (
)
func GetMessageHash(a Interface, message []byte, mode uint8) types.Hash {
return types.Hash(moneroutil.Keccak256(
return crypto.Keccak256(
[]byte("MoneroMessageSignature\x00"),
a.SpendPublicKey().AsSlice(),
a.ViewPublicKey().AsSlice(),
[]byte{mode},
binary.AppendUvarint(nil, uint64(len(message))),
message,
))
)
}
func VerifyMessage(a Interface, message []byte, signature string) SignatureVerifyResult {
var hash types.Hash
if strings.HasPrefix(signature, "SigV1") {
hash = types.Hash(moneroutil.Keccak256(message))
hash = crypto.Keccak256(message)
} else if strings.HasPrefix(signature, "SigV2") {
hash = GetMessageHash(a, message, 0)
} else {

View file

@ -3,12 +3,13 @@ package block
import (
"bytes"
"encoding/binary"
"git.gammaspectra.live/P2Pool/moneroutil"
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/client"
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/crypto"
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/randomx"
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/transaction"
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
"golang.org/x/crypto/sha3"
"hash"
"io"
)
@ -197,6 +198,8 @@ func (b *Block) TxTreeHash() (rootHash types.Hash) {
} else if count == 2 {
rootHash = types.HashFromBytes(keccak(h))
} else {
hashInstance := crypto.GetKeccak256Hasher()
defer crypto.PutKeccak256Hasher(hashInstance)
var cnt int
{
@ -214,7 +217,7 @@ func (b *Block) TxTreeHash() (rootHash types.Hash) {
i := cnt*2 - count
j := cnt*2 - count
for j < cnt {
copy(ints[j*types.HashSize:], keccakl(h[i*types.HashSize:], types.HashSize*2))
keccakl(hashInstance, ints[j*types.HashSize:], h[i*types.HashSize:], types.HashSize*2)
i += 2
j++
}
@ -227,7 +230,7 @@ func (b *Block) TxTreeHash() (rootHash types.Hash) {
j := 0
for j < cnt {
copy(ints[j*types.HashSize:], keccakl(ints[i*types.HashSize:], types.HashSize*2))
keccakl(hashInstance, ints[j*types.HashSize:], ints[i*types.HashSize:], types.HashSize*2)
i += 2
j++
@ -235,7 +238,7 @@ func (b *Block) TxTreeHash() (rootHash types.Hash) {
}
}
copy(rootHash[:], keccakl(ints, types.HashSize*2))
keccakl(hashInstance, rootHash[:], ints, types.HashSize*2)
}
return
@ -261,15 +264,15 @@ func (b *Block) PowHashWithError() (types.Hash, error) {
func (b *Block) Id() types.Hash {
//cached by sidechain.Share
buf := b.HashingBlob()
return types.Hash(moneroutil.Keccak256(binary.AppendUvarint(nil, uint64(len(buf))), buf))
return crypto.PooledKeccak256(binary.AppendUvarint(nil, uint64(len(buf))), buf)
}
var hasher = randomx.NewRandomX()
func keccakl(data []byte, len int) []byte {
h := sha3.NewLegacyKeccak256()
h.Write(data[:len])
return h.Sum(nil)
func keccakl(hasher hash.Hash, dst []byte, data []byte, len int) {
hasher.Reset()
hasher.Write(data[:len])
crypto.HashFastSum(hasher, dst)
}
func keccak(data ...[]byte) []byte {

View file

@ -2,7 +2,6 @@ package crypto
import (
"encoding/binary"
"git.gammaspectra.live/P2Pool/moneroutil"
)
func GetDerivationSharedDataForOutputIndex(derivation PublicKey, outputIndex uint64) PrivateKey {
@ -14,8 +13,7 @@ func GetDerivationSharedDataForOutputIndex(derivation PublicKey, outputIndex uin
func GetDerivationViewTagForOutputIndex(derivation PublicKey, outputIndex uint64) uint8 {
var k = derivation.AsBytes()
var varIntBuf [binary.MaxVarintLen64]byte
h := moneroutil.Keccak256([]byte("view_tag"), k[:], varIntBuf[:binary.PutUvarint(varIntBuf[:], outputIndex)])
return h[0]
return PooledKeccak256([]byte("view_tag"), k[:], varIntBuf[:binary.PutUvarint(varIntBuf[:], outputIndex)])[0]
}
func GetDerivationSharedDataAndViewTagForOutputIndex(derivation PublicKey, outputIndex uint64) (PrivateKey, uint8) {
@ -24,10 +22,9 @@ func GetDerivationSharedDataAndViewTagForOutputIndex(derivation PublicKey, outpu
n := binary.PutUvarint(varIntBuf[:], outputIndex)
pK := PrivateKeyFromScalar(HashToScalar(k[:], varIntBuf[:n]))
h := moneroutil.Keccak256([]byte("view_tag"), k[:], varIntBuf[:n])
return pK, h[0]
return pK, PooledKeccak256([]byte("view_tag"), k[:], varIntBuf[:n])[0]
}
func GetKeyImage(pair *KeyPair) PublicKey {
return PublicKeyFromPoint(HashToPoint(pair.PublicKey)).Multiply(pair.PrivateKey.AsScalar())
}
}

View file

@ -3,29 +3,51 @@ package crypto
import (
"filippo.io/edwards25519"
"git.gammaspectra.live/P2Pool/moneroutil"
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
"golang.org/x/crypto/sha3"
"hash"
"io"
)
func BytesToScalar(buf []byte) *edwards25519.Scalar {
var bytes [32]byte
copy(bytes[:], buf[:])
scReduce32(bytes[:])
c, _ := edwards25519.NewScalar().SetCanonicalBytes(bytes[:])
c, _ := GetEdwards25519Scalar().SetCanonicalBytes(bytes[:])
return c
}
func Keccak256(data ...[]byte) (result types.Hash) {
h := sha3.NewLegacyKeccak256()
for _, b := range data {
h.Write(b)
}
HashFastSum(h, result[:])
return
}
func HashToScalar(data ...[]byte) *edwards25519.Scalar {
h := moneroutil.Keccak256(data...)
h := PooledKeccak256(data...)
scReduce32(h[:])
c, _ := edwards25519.NewScalar().SetCanonicalBytes(h[:])
c, _ := GetEdwards25519Scalar().SetCanonicalBytes(h[:])
return c
}
// HashFastSum sha3.Sum clones the state by allocating memory. prevent that. b must be pre-allocated to the expected size, or larger
func HashFastSum(hash hash.Hash, b []byte) []byte {
if r, ok := hash.(io.Reader); ok {
_, _ = r.Read(b[:hash.Size()])
return b
}
return hash.Sum(b[:0])
}
func HashToPoint(publicKey PublicKey) *edwards25519.Point {
//TODO: make this work with existing edwards25519 library
input := moneroutil.Key(publicKey.AsBytes())
var key moneroutil.Key
(&input).HashToEC().ToBytes(&key)
p, _ := (&edwards25519.Point{}).SetBytes(key[:])
p, _ := GetEdwards25519Point().SetBytes(key[:])
return p
}

View file

@ -0,0 +1,11 @@
package crypto
import "testing"
func TestHash(t *testing.T) {
h := PooledKeccak256([]byte("test")).String()
if h != "9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658" {
t.Fatalf("got %s, expected %s", h, "9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658")
}
}

63
monero/crypto/pool.go Normal file
View file

@ -0,0 +1,63 @@
package crypto
import (
"filippo.io/edwards25519"
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
"golang.org/x/crypto/sha3"
"hash"
"runtime"
"sync"
)
var hasherPool, pointPool, scalarPool sync.Pool
func init() {
hasherPool.New = func() any {
return sha3.NewLegacyKeccak256()
}
pointPool.New = func() any {
p := new(edwards25519.Point)
runtime.SetFinalizer(p, PutEdwards25519Point)
return p
}
scalarPool.New = func() any {
s := new(edwards25519.Scalar)
runtime.SetFinalizer(s, PutEdwards25519Scalar)
return s
}
}
func GetKeccak256Hasher() hash.Hash {
return hasherPool.Get().(hash.Hash)
}
func PutKeccak256Hasher(h hash.Hash) {
h.Reset()
hasherPool.Put(h)
}
func PooledKeccak256(data ...[]byte) (result types.Hash) {
h := GetKeccak256Hasher()
defer PutKeccak256Hasher(h)
for _, b := range data {
h.Write(b)
}
HashFastSum(h, result[:])
return
}
func GetEdwards25519Point() *edwards25519.Point {
return pointPool.Get().(*edwards25519.Point)
}
func PutEdwards25519Point(p *edwards25519.Point) {
pointPool.Put(p)
}
func GetEdwards25519Scalar() *edwards25519.Scalar {
return scalarPool.Get().(*edwards25519.Scalar)
}
func PutEdwards25519Scalar(s *edwards25519.Scalar) {
scalarPool.Put(s)
}

View file

@ -50,7 +50,7 @@ func (p *PrivateKeyScalar) Scalar() *edwards25519.Scalar {
}
func (p *PrivateKeyScalar) PublicKey() PublicKey {
return PublicKeyFromPoint((&edwards25519.Point{}).ScalarBaseMult(p.Scalar()))
return PublicKeyFromPoint(GetEdwards25519Point().ScalarBaseMult(p.Scalar()))
}
func (p *PrivateKeyScalar) GetDerivation(public PublicKey) PublicKey {
@ -61,7 +61,6 @@ func (p *PrivateKeyScalar) GetDerivationCofactor(public PublicKey) PublicKey {
return deriveKeyExchangeSecretCofactor(p, public.AsPoint())
}
func (p *PrivateKeyScalar) String() string {
return hex.EncodeToString(p.Scalar().Bytes())
}
@ -87,7 +86,6 @@ func (p *PrivateKeyScalar) UnmarshalJSON(b []byte) error {
}
}
type PrivateKeyBytes [PrivateKeySize]byte
func (k *PrivateKeyBytes) AsSlice() PrivateKeySlice {
@ -99,12 +97,12 @@ func (k *PrivateKeyBytes) AsBytes() PrivateKeyBytes {
}
func (k *PrivateKeyBytes) AsScalar() *PrivateKeyScalar {
secret, _ := edwards25519.NewScalar().SetCanonicalBytes((*k)[:])
secret, _ := GetEdwards25519Scalar().SetCanonicalBytes((*k)[:])
return PrivateKeyFromScalar(secret)
}
func (k *PrivateKeyBytes) PublicKey() PublicKey {
return PublicKeyFromPoint((&edwards25519.Point{}).ScalarBaseMult(k.AsScalar().Scalar()))
return PublicKeyFromPoint(GetEdwards25519Point().ScalarBaseMult(k.AsScalar().Scalar()))
}
func (k *PrivateKeyBytes) GetDerivation(public PublicKey) PublicKey {
@ -115,7 +113,6 @@ func (k *PrivateKeyBytes) GetDerivationCofactor(public PublicKey) PublicKey {
return k.AsScalar().GetDerivationCofactor(public)
}
func (k *PrivateKeyBytes) String() string {
return hex.EncodeToString(k.AsSlice())
}
@ -138,7 +135,6 @@ func (k *PrivateKeyBytes) UnmarshalJSON(b []byte) error {
}
}
type PrivateKeySlice []byte
func (k *PrivateKeySlice) AsSlice() PrivateKeySlice {
@ -151,12 +147,12 @@ func (k *PrivateKeySlice) AsBytes() (buf PrivateKeyBytes) {
}
func (k *PrivateKeySlice) AsScalar() *PrivateKeyScalar {
secret, _ := edwards25519.NewScalar().SetCanonicalBytes(*k)
secret, _ := GetEdwards25519Scalar().SetCanonicalBytes(*k)
return PrivateKeyFromScalar(secret)
}
func (k *PrivateKeySlice) PublicKey() PublicKey {
return PublicKeyFromPoint((&edwards25519.Point{}).ScalarBaseMult(k.AsScalar().Scalar()))
return PublicKeyFromPoint(GetEdwards25519Point().ScalarBaseMult(k.AsScalar().Scalar()))
}
func (k *PrivateKeySlice) GetDerivation(public PublicKey) PublicKey {
@ -167,7 +163,6 @@ func (k *PrivateKeySlice) GetDerivationCofactor(public PublicKey) PublicKey {
return k.AsScalar().GetDerivationCofactor(public)
}
func (k *PrivateKeySlice) String() string {
return hex.EncodeToString(*k)
}
@ -190,11 +185,10 @@ func (k *PrivateKeySlice) UnmarshalJSON(b []byte) error {
}
}
func deriveKeyExchangeSecretCofactor(private *PrivateKeyScalar, public *PublicKeyPoint) *PublicKeyPoint {
return public.Multiply(private).Cofactor()
}
func deriveKeyExchangeSecret(private *PrivateKeyScalar, public *PublicKeyPoint) *PublicKeyPoint {
return public.Multiply(private)
}
}

View file

@ -1,11 +1,10 @@
package crypto
import (
"git.gammaspectra.live/P2Pool/moneroutil"
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
)
var TxProofV2DomainSeparatorHash = types.Hash(moneroutil.Keccak256([]byte("TXPROOF_V2"))) // HASH_KEY_TXPROOF_V2
var TxProofV2DomainSeparatorHash = Keccak256([]byte("TXPROOF_V2")) // HASH_KEY_TXPROOF_V2
func GenerateTxProofV2(prefixHash types.Hash, txKey PrivateKey, recipientViewPublicKey PublicKey, recipientSpendPublicKey PublicKey) (derivation PublicKey, signature *Signature) {
comm := &SignatureComm_2{}
comm.Message = prefixHash

View file

@ -37,20 +37,20 @@ func (k *PublicKeyPoint) Point() *edwards25519.Point {
return (*edwards25519.Point)(k)
}
func (k *PublicKeyPoint) Add(b *PublicKeyPoint) *PublicKeyPoint{
return PublicKeyFromPoint((&edwards25519.Point{}).Add(k.Point(), b.Point()))
func (k *PublicKeyPoint) Add(b *PublicKeyPoint) *PublicKeyPoint {
return PublicKeyFromPoint(GetEdwards25519Point().Add(k.Point(), b.Point()))
}
func (k *PublicKeyPoint) Subtract(b *PublicKeyPoint) *PublicKeyPoint{
return PublicKeyFromPoint((&edwards25519.Point{}).Subtract(k.Point(), b.Point()))
func (k *PublicKeyPoint) Subtract(b *PublicKeyPoint) *PublicKeyPoint {
return PublicKeyFromPoint(GetEdwards25519Point().Subtract(k.Point(), b.Point()))
}
func (k *PublicKeyPoint) Multiply(b *PrivateKeyScalar) *PublicKeyPoint{
return PublicKeyFromPoint((&edwards25519.Point{}).ScalarMult(b.Scalar(), k.Point()))
func (k *PublicKeyPoint) Multiply(b *PrivateKeyScalar) *PublicKeyPoint {
return PublicKeyFromPoint(GetEdwards25519Point().ScalarMult(b.Scalar(), k.Point()))
}
func (k *PublicKeyPoint) Cofactor() *PublicKeyPoint{
return PublicKeyFromPoint((&edwards25519.Point{}).MultByCofactor(k.Point()))
func (k *PublicKeyPoint) Cofactor() *PublicKeyPoint {
return PublicKeyFromPoint(GetEdwards25519Point().MultByCofactor(k.Point()))
}
func PublicKeyFromPoint(point *edwards25519.Point, _ ...any) *PublicKeyPoint {
@ -82,8 +82,6 @@ func (k *PublicKeyPoint) UnmarshalJSON(b []byte) error {
}
}
type PublicKeyBytes [PublicKeySize]byte
func (k *PublicKeyBytes) AsSlice() PublicKeySlice {
@ -95,7 +93,7 @@ func (k *PublicKeyBytes) AsBytes() PublicKeyBytes {
}
func (k *PublicKeyBytes) AsPoint() *PublicKeyPoint {
return PublicKeyFromPoint((&edwards25519.Point{}).SetBytes(k.AsSlice()))
return PublicKeyFromPoint(GetEdwards25519Point().SetBytes(k.AsSlice()))
}
func (k *PublicKeyBytes) String() string {
@ -120,7 +118,6 @@ func (k *PublicKeyBytes) UnmarshalJSON(b []byte) error {
}
}
type PublicKeySlice []byte
func (k *PublicKeySlice) AsSlice() PublicKeySlice {
@ -133,7 +130,7 @@ func (k *PublicKeySlice) AsBytes() (buf PublicKeyBytes) {
}
func (k *PublicKeySlice) AsPoint() *PublicKeyPoint {
return PublicKeyFromPoint((&edwards25519.Point{}).SetBytes(*k))
return PublicKeyFromPoint(GetEdwards25519Point().SetBytes(*k))
}
func (k *PublicKeySlice) String() string {
@ -156,4 +153,4 @@ func (k *PublicKeySlice) UnmarshalJSON(b []byte) error {
*k = buf
return nil
}
}
}

View file

@ -35,7 +35,7 @@ func DeterministicScalar(entropy ...[]byte) *edwards25519.Scalar {
h := sha3.NewLegacyKeccak256()
var hash types.Hash
scalar := edwards25519.NewScalar()
scalar := GetEdwards25519Scalar()
for {
h.Reset()

View file

@ -12,10 +12,12 @@ type Signature struct {
// R result of the signature, also called s
R *edwards25519.Scalar
}
// SignatureSigningHandler receives k, inserts it or a pubkey into its data, and produces a []byte buffer for Signing/Verifying
type SignatureSigningHandler func (r PrivateKey) []byte
type SignatureSigningHandler func(r PrivateKey) []byte
// SignatureVerificationHandler receives r = pubkey(k), inserts it into its data, and produces a []byte buffer for Signing/Verifying
type SignatureVerificationHandler func (r PublicKey) []byte
type SignatureVerificationHandler func(r PublicKey) []byte
func NewSignatureFromBytes(buf []byte) *Signature {
if len(buf) != types.HashSize*2 {
@ -23,9 +25,9 @@ func NewSignatureFromBytes(buf []byte) *Signature {
}
signature := &Signature{}
var err error
if signature.C, err = edwards25519.NewScalar().SetCanonicalBytes(buf[:32]); err != nil {
if signature.C, err = GetEdwards25519Scalar().SetCanonicalBytes(buf[:32]); err != nil {
return nil
} else if signature.R, err = edwards25519.NewScalar().SetCanonicalBytes(buf[32:]); err != nil {
} else if signature.R, err = GetEdwards25519Scalar().SetCanonicalBytes(buf[32:]); err != nil {
return nil
} else {
return signature
@ -42,7 +44,7 @@ func (s *Signature) Bytes() []byte {
// Verify checks a Schnorr Signature using H = keccak
func (s *Signature) Verify(handler SignatureVerificationHandler, publicKey PublicKey) (ok bool, r *PublicKeyPoint) {
//s = C * k, R * G
sp := (&edwards25519.Point{}).VarTimeDoubleScalarBaseMult(s.C, publicKey.AsPoint().Point(), s.R)
sp := GetEdwards25519Point().VarTimeDoubleScalarBaseMult(s.C, publicKey.AsPoint().Point(), s.R)
if sp.Equal(infinityPoint) == 1 {
return false, nil
}
@ -62,11 +64,10 @@ func CreateSignature(handler SignatureSigningHandler, privateKey PrivateKey) *Si
// s = k - x * e
// EdDSA is an altered version, with addition instead of subtraction
signature.R = signature.R.Subtract(k.Scalar(), edwards25519.NewScalar().Multiply(signature.C, privateKey.AsScalar().Scalar()))
signature.R = signature.R.Subtract(k.Scalar(), GetEdwards25519Scalar().Multiply(signature.C, privateKey.AsScalar().Scalar()))
return signature
}
func CreateMessageSignature(prefixHash types.Hash, key PrivateKey) *Signature {
buf := &SignatureComm{}
buf.Hash = prefixHash

View file

@ -6,7 +6,7 @@ import (
"bytes"
"encoding/hex"
"errors"
"git.gammaspectra.live/P2Pool/moneroutil"
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/crypto"
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
"git.gammaspectra.live/P2Pool/randomx-go-bindings"
"github.com/go-faster/xor"
@ -17,7 +17,7 @@ import (
)
type hasherCollection struct {
lock sync.RWMutex
lock sync.RWMutex
index int
cache []*hasherState
}
@ -56,7 +56,7 @@ func (h *hasherCollection) Close() {
}
type hasherState struct {
lock sync.Mutex
lock sync.Mutex
dataset *randomx.RxDataset
vm *randomx.RxVM
key []byte
@ -97,7 +97,7 @@ func ConsensusHash(buf []byte) types.Hash {
cachePtr = cachePtr[stride:]
}
return types.Hash(moneroutil.Keccak256(scratchpadTopPtr))
return crypto.Keccak256(scratchpadTopPtr)
}
func NewRandomX() Hasher {
@ -141,7 +141,7 @@ func (h *hasherState) Init(key []byte) (err error) {
h.vm.Close()
}
if h.vm, err = randomx.NewRxVM(h.dataset, /*randomx.FlagFullMEM,*/ randomx.FlagHardAES, randomx.FlagJIT, randomx.FlagSecure); err != nil {
if h.vm, err = randomx.NewRxVM(h.dataset /*randomx.FlagFullMEM,*/, randomx.FlagHardAES, randomx.FlagJIT, randomx.FlagSecure); err != nil {
return err
}
log.Printf("[RandomX] Initialized to seed %s", hex.EncodeToString(h.key))

View file

@ -5,7 +5,7 @@ package randomx
import (
"bytes"
"git.gammaspectra.live/P2Pool/go-randomx"
"git.gammaspectra.live/P2Pool/moneroutil"
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/crypto"
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
"github.com/go-faster/xor"
"runtime"
@ -49,7 +49,7 @@ func ConsensusHash(buf []byte) types.Hash {
cachePtr = cachePtr[stride:]
}
return types.Hash(moneroutil.Keccak256(scratchpadTopPtr))
return crypto.Keccak256(scratchpadTopPtr)
}
func NewRandomX() Hasher {

View file

@ -5,7 +5,7 @@ import (
"encoding/binary"
"errors"
"fmt"
"git.gammaspectra.live/P2Pool/moneroutil"
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/crypto"
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
"golang.org/x/crypto/sha3"
"io"
@ -78,7 +78,6 @@ func (c *CoinbaseTransaction) FromReader(reader readerAndByteReader) (err error)
return err
}
if err = c.Outputs.FromReader(reader); err != nil {
return err
} else if len(c.Outputs) != 0 {
@ -207,6 +206,6 @@ func (c *CoinbaseTransaction) Id() types.Hash {
}
func hashKeccak(data ...[]byte) []byte {
d := moneroutil.Keccak256(data...)
d := crypto.PooledKeccak256(data...)
return d[:]
}

View file

@ -1,7 +1,6 @@
package transaction
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
@ -9,7 +8,7 @@ import (
"io"
)
type Outputs []*Output
type Outputs []Output
func (s *Outputs) FromReader(reader readerAndByteReader) (err error) {
@ -24,10 +23,9 @@ func (s *Outputs) FromReader(reader readerAndByteReader) (err error) {
*s = make(Outputs, 0, outputCount)
}
var o Output
for index := 0; index < int(outputCount); index++ {
o := &Output{
Index: uint64(index),
}
o.Index = uint64(index)
if o.Reward, err = binary.ReadUvarint(reader); err != nil {
return err
@ -47,6 +45,8 @@ func (s *Outputs) FromReader(reader readerAndByteReader) (err error) {
if o.ViewTag, err = reader.ReadByte(); err != nil {
return err
}
} else {
o.ViewTag = 0
}
default:
return fmt.Errorf("unknown %d TXOUT key", o.Type)
@ -59,28 +59,26 @@ func (s *Outputs) FromReader(reader readerAndByteReader) (err error) {
}
func (s *Outputs) MarshalBinary() (data []byte, err error) {
buf := new(bytes.Buffer)
data = make([]byte, 0, binary.MaxVarintLen64 + len(*s) * (binary.MaxVarintLen64 + 1 + crypto.PublicKeySize + 1))
varIntBuf := make([]byte, binary.MaxVarintLen64)
_, _ = buf.Write(varIntBuf[:binary.PutUvarint(varIntBuf, uint64(len(*s)))])
data = binary.AppendUvarint(data, uint64(len(*s)))
for _, o := range *s {
_, _ = buf.Write(varIntBuf[:binary.PutUvarint(varIntBuf, o.Reward)])
_ = binary.Write(buf, binary.BigEndian, o.Type)
data = binary.AppendUvarint(data, o.Reward)
data = append(data, o.Type)
switch o.Type {
case TxOutToTaggedKey, TxOutToKey:
_, _ = buf.Write(o.EphemeralPublicKey.AsSlice())
data = append(data, o.EphemeralPublicKey[:]...)
if o.Type == TxOutToTaggedKey {
_ = binary.Write(buf, binary.BigEndian, o.ViewTag)
data = append(data, o.ViewTag)
}
default:
return nil, errors.New("unknown output type")
}
}
return buf.Bytes(), nil
return data, nil
}
type Output struct {

View file

@ -3,9 +3,8 @@ package p2p
import (
"crypto/rand"
"encoding/binary"
"git.gammaspectra.live/P2Pool/moneroutil"
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/crypto"
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
"golang.org/x/crypto/sha3"
"sync/atomic"
"unsafe"
)
@ -26,24 +25,25 @@ func FindChallengeSolution(challenge HandshakeChallenge, consensusId types.Hash,
_, _ = rand.Read(saltSlice[:])
salt = binary.LittleEndian.Uint64(saltSlice[:])
h := sha3.NewLegacyKeccak256()
h := crypto.GetKeccak256Hasher()
defer crypto.PutKeccak256Hasher(h)
sum := make([]byte, types.HashSize)
var sum types.Hash
for {
h.Reset()
binary.LittleEndian.PutUint64(buf[types.HashSize+HandshakeChallengeSize:], salt)
_, _ = h.Write(buf[:])
sum = h.Sum(sum[:0])
crypto.HashFastSum(h, sum[:])
//check if we have been asked to stop
if stop.Load() {
return salt, types.HashFromBytes(sum), false
return salt, sum, false
}
if types.DifficultyFrom64(binary.LittleEndian.Uint64(sum[len(sum)-int(unsafe.Sizeof(uint64(0))):])).Mul64(HandshakeChallengeDifficulty).Hi == 0 {
//found solution
return salt, types.HashFromBytes(sum), true
return salt, sum, true
}
salt++
@ -51,6 +51,6 @@ func FindChallengeSolution(challenge HandshakeChallenge, consensusId types.Hash,
}
func CalculateChallengeHash(challenge HandshakeChallenge, consensusId types.Hash, solution uint64) (hash types.Hash, ok bool) {
hash = types.Hash(moneroutil.Keccak256(challenge[:], consensusId[:], binary.LittleEndian.AppendUint64(nil, solution)))
hash = crypto.PooledKeccak256(challenge[:], consensusId[:], binary.LittleEndian.AppendUint64(nil, solution))
return hash, types.DifficultyFrom64(binary.LittleEndian.Uint64(hash[types.HashSize-int(unsafe.Sizeof(uint64(0))):])).Mul64(HandshakeChallengeDifficulty).Hi == 0
}

View file

@ -24,19 +24,19 @@ const DefaultBanTime = time.Second * 600
const PeerListResponseMaxPeers = 16
type Client struct {
Owner *Server
Connection net.Conn
Closed atomic.Bool
AddressPort netip.AddrPort
LastActive time.Time
LastBroadcast time.Time
LastBlockRequest time.Time
PingTime time.Duration
Owner *Server
Connection net.Conn
Closed atomic.Bool
AddressPort netip.AddrPort
LastActive time.Time
LastBroadcast time.Time
LastBlockRequest time.Time
PingTime time.Duration
LastPeerListRequestTime time.Time
PeerId uint64
IsIncomingConnection bool
HandshakeComplete atomic.Bool
ListenPort uint32
PeerId uint64
IsIncomingConnection bool
HandshakeComplete atomic.Bool
ListenPort uint32
BlockPendingRequests int64
ChainTipBlockRequest bool
@ -61,7 +61,7 @@ func NewClient(owner *Server, conn net.Conn) *Client {
expectedMessage: MessageHandshakeChallenge,
blockRequestThrottler: time.Tick(time.Second / 50), //maximum 50 per second
messageChannel: make(chan *ClientMessage, 10),
closeChannel: make(chan struct{}),
closeChannel: make(chan struct{}),
}
return c
@ -80,7 +80,7 @@ func (c *Client) OnAfterHandshake() {
func (c *Client) SendListenPort() {
c.SendMessage(&ClientMessage{
MessageId: MessageListenPort,
Buffer: binary.LittleEndian.AppendUint32(nil, uint32(c.Owner.listenAddress.Port())),
Buffer: binary.LittleEndian.AppendUint32(nil, uint32(c.Owner.listenAddress.Port())),
})
}
@ -89,7 +89,7 @@ func (c *Client) SendBlockRequest(hash types.Hash) {
c.SendMessage(&ClientMessage{
MessageId: MessageBlockRequest,
Buffer: hash[:],
Buffer: hash[:],
})
c.BlockPendingRequests++
@ -105,13 +105,13 @@ func (c *Client) SendBlockResponse(block *sidechain.PoolBlock) {
c.SendMessage(&ClientMessage{
MessageId: MessageBlockResponse,
Buffer: append(binary.LittleEndian.AppendUint32(make([]byte, 0, len(blockData)+4), uint32(len(blockData))), blockData...),
Buffer: append(binary.LittleEndian.AppendUint32(make([]byte, 0, len(blockData)+4), uint32(len(blockData))), blockData...),
})
} else {
c.SendMessage(&ClientMessage{
MessageId: MessageBlockResponse,
Buffer: binary.LittleEndian.AppendUint32(nil, 0),
Buffer: binary.LittleEndian.AppendUint32(nil, 0),
})
}
}
@ -122,13 +122,13 @@ func (c *Client) SendBlockBroadcast(block *sidechain.PoolBlock) {
c.SendMessage(&ClientMessage{
MessageId: MessageBlockBroadcast,
Buffer: append(binary.LittleEndian.AppendUint32(make([]byte, 0, len(blockData)+4), uint32(len(blockData))), blockData...),
Buffer: append(binary.LittleEndian.AppendUint32(make([]byte, 0, len(blockData)+4), uint32(len(blockData))), blockData...),
})
} else {
c.SendMessage(&ClientMessage{
MessageId: MessageBlockBroadcast,
Buffer: binary.LittleEndian.AppendUint32(nil, 0),
Buffer: binary.LittleEndian.AppendUint32(nil, 0),
})
}
}
@ -144,7 +144,7 @@ func (c *Client) SendPeerListResponse(list []netip.AddrPort) {
if len(list) > PeerListResponseMaxPeers {
return
}
buf := make([]byte, 0, 1 + len(list) * (1 + 16 + 2 ))
buf := make([]byte, 0, 1+len(list)*(1+16+2))
buf = append(buf, byte(len(list)))
for i := range list {
if list[i].Addr().Is6() {
@ -158,7 +158,7 @@ func (c *Client) SendPeerListResponse(list []netip.AddrPort) {
}
c.SendMessage(&ClientMessage{
MessageId: MessagePeerListResponse,
Buffer: buf,
Buffer: buf,
})
}
@ -175,7 +175,7 @@ func (c *Client) OnConnection() {
select {
case <-c.closeChannel:
return
case message := <- c.messageChannel:
case message := <-c.messageChannel:
//log.Printf("Sending message %d len %d", message.MessageId, len(message.Buffer))
_, _ = c.Write([]byte{byte(message.MessageId)})
_, _ = c.Write(message.Buffer)
@ -449,7 +449,7 @@ func (c *Client) sendHandshakeChallenge() {
c.SendMessage(&ClientMessage{
MessageId: MessageHandshakeChallenge,
Buffer: buf[:],
Buffer: buf[:],
})
}
@ -468,7 +468,7 @@ func (c *Client) sendHandshakeSolution(challenge HandshakeChallenge) {
c.SendMessage(&ClientMessage{
MessageId: MessageHandshakeSolution,
Buffer: buf[:],
Buffer: buf[:],
})
}
}
@ -491,7 +491,7 @@ func (c *Client) Read(buf []byte) (n int, err error) {
type ClientMessage struct {
MessageId MessageId
Buffer []byte
Buffer []byte
}
func (c *Client) SendMessage(message *ClientMessage) {

View file

@ -148,7 +148,7 @@ func (s *Server) Connect(addrPort netip.AddrPort) error {
return errors.New("peer is already connected as " + clients[0].AddressPort.String())
}
if conn, err := net.Dial("tcp", addrPort.String()); err != nil {
if conn, err := net.DialTimeout("tcp", addrPort.String(), time.Second * 10); err != nil {
return err
} else {
s.clientsLock.Lock()

View file

@ -9,11 +9,11 @@ import (
)
type deterministicTransactionCacheKey [crypto.PublicKeySize + types.HashSize]byte
type ephemeralPublicKeyCacheKey [crypto.PrivateKeySize + crypto.PublicKeySize * 2 + 8]byte
type ephemeralPublicKeyCacheKey [crypto.PrivateKeySize + crypto.PublicKeySize*2 + 8]byte
type ephemeralPublicKeyWithViewTag struct {
PublicKey crypto.PublicKeyBytes
ViewTag uint8
ViewTag uint8
}
type DerivationCache struct {
@ -43,13 +43,13 @@ func (d *DerivationCache) Clear() {
d.ephemeralPublicKeyCache = lru.New[ephemeralPublicKeyCacheKey, ephemeralPublicKeyWithViewTag](pplnsSize * knownMinersPerPplns * outputIdsPerMiner)
}
func (d *DerivationCache) GetEphemeralPublicKey(a address.Interface, txKey crypto.PrivateKey, outputIndex uint64) (crypto.PublicKeyBytes, uint8) {
func (d *DerivationCache) GetEphemeralPublicKey(a address.Interface, txKeySlice crypto.PrivateKeySlice, txKeyScalar *crypto.PrivateKeyScalar, outputIndex uint64) (crypto.PublicKeyBytes, uint8) {
var key ephemeralPublicKeyCacheKey
copy(key[:], txKey.AsSlice())
copy(key[:], txKeySlice)
copy(key[crypto.PrivateKeySize:], a.ToPackedAddress().Bytes())
binary.LittleEndian.PutUint64(key[crypto.PrivateKeySize + crypto.PublicKeySize*2:], outputIndex)
binary.LittleEndian.PutUint64(key[crypto.PrivateKeySize+crypto.PublicKeySize*2:], outputIndex)
if ephemeralPubKey := d.ephemeralPublicKeyCache.Get(key); ephemeralPubKey == nil {
ephemeralPubKey, viewTag := address.GetEphemeralPublicKeyAndViewTag(a, txKey, outputIndex)
ephemeralPubKey, viewTag := address.GetEphemeralPublicKeyAndViewTag(a, txKeyScalar, outputIndex)
pKB := ephemeralPubKey.AsBytes()
d.ephemeralPublicKeyCache.Set(key, ephemeralPublicKeyWithViewTag{PublicKey: pKB, ViewTag: viewTag})
return pKB, viewTag

View file

@ -3,9 +3,9 @@ package sidechain
import (
"encoding/json"
"fmt"
"git.gammaspectra.live/P2Pool/moneroutil"
"git.gammaspectra.live/P2Pool/p2pool-observer/monero"
mainblock "git.gammaspectra.live/P2Pool/p2pool-observer/monero/block"
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/crypto"
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/randomx"
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
"strconv"
@ -139,7 +139,7 @@ func (i *Consensus) CalculateSideTemplateId(main *mainblock.Block, side *SideDat
}
func (i *Consensus) CalculateSideChainIdFromBlobs(mainBlob, sideBlob []byte) types.Hash {
return types.Hash(moneroutil.Keccak256(mainBlob, sideBlob, i.id[:]))
return crypto.PooledKeccak256(mainBlob, sideBlob, i.id[:])
}
func (i *Consensus) Id() types.Hash {

View file

@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"git.gammaspectra.live/P2Pool/p2pool-observer/monero"
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/address"
mainblock "git.gammaspectra.live/P2Pool/p2pool-observer/monero/block"
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/transaction"
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
@ -443,13 +444,18 @@ func (c *SideChain) verifyBlock(block *PoolBlock) (verification error, invalid e
} else if rewards := c.SplitReward(totalReward, c.sharesCache); len(rewards) != len(block.Main.Coinbase.Outputs) {
return nil, fmt.Errorf("invalid number of outputs, got %d, expected %d", len(block.Main.Coinbase.Outputs), len(rewards))
} else {
//prevent multiple allocations
txPrivateKeySlice := block.Side.CoinbasePrivateKey.AsSlice()
txPrivateKeyScalar := block.Side.CoinbasePrivateKey.AsScalar()
results := utils.SplitWork(-2, uint64(len(rewards)), func(workIndex uint64, workerIndex int) error {
out := block.Main.Coinbase.Outputs[workIndex]
if rewards[workIndex] != out.Reward {
return fmt.Errorf("has invalid reward at index %d, got %d, expected %d", workIndex, out.Reward, rewards[workIndex])
}
if ephPublicKey, viewTag := c.cache.GetEphemeralPublicKey(&c.sharesCache[workIndex].Address, &block.Side.CoinbasePrivateKey, workIndex); ephPublicKey != out.EphemeralPublicKey {
if ephPublicKey, viewTag := c.cache.GetEphemeralPublicKey(&c.sharesCache[workIndex].Address, txPrivateKeySlice, txPrivateKeyScalar, workIndex); ephPublicKey != out.EphemeralPublicKey {
return fmt.Errorf("has incorrect eph_public_key at index %d, got %s, expected %s", workIndex, out.EphemeralPublicKey.String(), ephPublicKey.String())
} else if out.Type == transaction.TxOutToTaggedKey && viewTag != out.ViewTag {
return fmt.Errorf("has incorrect view tag at index %d, got %d, expected %d", workIndex, out.ViewTag, viewTag)
@ -606,13 +612,16 @@ func (c *SideChain) calculateOutputs(block *PoolBlock) transaction.Outputs {
txType := c.GetTransactionOutputType(block.Main.MajorVersion)
txPrivateKeySlice := block.Side.CoinbasePrivateKey.AsSlice()
txPrivateKeyScalar := block.Side.CoinbasePrivateKey.AsScalar()
_ = utils.SplitWork(-2, n, func(workIndex uint64, workerIndex int) error {
output := &transaction.Output{
output := transaction.Output{
Index: workIndex,
Type: txType,
}
output.Reward = tmpRewards[output.Index]
output.EphemeralPublicKey, output.ViewTag = c.cache.GetEphemeralPublicKey(&tmpShares[output.Index].Address, &block.Side.CoinbasePrivateKey, output.Index)
output.EphemeralPublicKey, output.ViewTag = c.cache.GetEphemeralPublicKey(&tmpShares[output.Index].Address, txPrivateKeySlice, txPrivateKeyScalar, output.Index)
outputs[output.Index] = output
@ -657,15 +666,25 @@ func (c *SideChain) SplitReward(reward uint64, shares Shares) (rewards []uint64)
return rewards
}
func (c *SideChain) getShares(tip *PoolBlock, shares Shares) Shares {
shares = shares[:0]
func (c *SideChain) getShares(tip *PoolBlock, preAllocatedShares Shares) Shares {
var blockDepth uint64
cur := tip
index := 0
l := len(preAllocatedShares)
insert := func(weight uint64, a *address.PackedAddress) {
if index < l {
preAllocatedShares[index].Weight, preAllocatedShares[index].Address = weight, *a
} else {
preAllocatedShares = append(preAllocatedShares, &Share{Weight: weight, Address: *a})
}
index++
}
for {
curShare := &Share{Weight: cur.Side.Difficulty.Lo, Address: *cur.GetAddress()}
curWeight := cur.Side.Difficulty.Lo
for _, uncleId := range cur.Side.Uncles {
if uncle := c.getPoolBlockByTemplateId(uncleId); uncle == nil {
@ -680,13 +699,13 @@ func (c *SideChain) getShares(tip *PoolBlock, shares Shares) Shares {
// Take some % of uncle's weight into this share
product := uncle.Side.Difficulty.Mul64(c.Consensus().UnclePenalty)
unclePenalty := product.Div64(100)
curShare.Weight += unclePenalty.Lo
curWeight += unclePenalty.Lo
shares = append(shares, &Share{Weight: uncle.Side.Difficulty.Sub(unclePenalty).Lo, Address: *uncle.GetAddress()})
insert(uncle.Side.Difficulty.Sub(unclePenalty).Lo, uncle.GetAddress())
}
}
shares = append(shares, curShare)
insert(curWeight, cur.GetAddress())
blockDepth++
@ -706,6 +725,8 @@ func (c *SideChain) getShares(tip *PoolBlock, shares Shares) Shares {
}
}
shares := preAllocatedShares[:index]
// Combine shares with the same wallet addresses
slices.SortFunc(shares, func(a *Share, b *Share) bool {
return a.Address.Compare(&b.Address) < 0

View file

@ -244,13 +244,13 @@ func (d Difficulty) StringNumeric() string {
var powBase = uint256.NewInt(0).SetBytes32(bytes.Repeat([]byte{0xff}, 32))
func DifficultyFromPoW(powHash Hash) Difficulty {
pow := uint256.NewInt(0).SetBytes32(powHash[:])
pow = &uint256.Int{bits.ReverseBytes64(pow[3]), bits.ReverseBytes64(pow[2]), bits.ReverseBytes64(pow[1]), bits.ReverseBytes64(pow[0])}
if pow.Eq(uint256.NewInt(0)) {
if powHash == ZeroHash {
return ZeroDifficulty
}
pow := uint256.NewInt(0).SetBytes32(powHash[:])
pow = &uint256.Int{bits.ReverseBytes64(pow[3]), bits.ReverseBytes64(pow[2]), bits.ReverseBytes64(pow[1]), bits.ReverseBytes64(pow[0])}
powResult := uint256.NewInt(0).Div(powBase, pow).Bytes32()
return DifficultyFromBytes(powResult[16:])
}

View file

@ -11,6 +11,10 @@ func SplitWork(routines int, workSize uint64, do func(workIndex uint64, routineI
routines = Max(runtime.NumCPU()-routines, 4)
}
if workSize < uint64(routines) {
routines = int(workSize)
}
var counter atomic.Uint64
results := make([]error, routines)
@ -27,7 +31,7 @@ func SplitWork(routines int, workSize uint64, do func(workIndex uint64, routineI
return
}
if err = do(workIndex - 1, routineIndex); err != nil {
if err = do(workIndex-1, routineIndex); err != nil {
results[routineIndex] = err
return
}