diff --git a/crypto/merklesignature/persistentMerkleSignatureScheme.go b/crypto/merklesignature/persistentMerkleSignatureScheme.go index c862dcb965..a5e114a46a 100644 --- a/crypto/merklesignature/persistentMerkleSignatureScheme.go +++ b/crypto/merklesignature/persistentMerkleSignatureScheme.go @@ -98,7 +98,8 @@ func (s *Secrets) Persist(store db.Accessor) error { return fmt.Errorf("Secrets.Persist: %w", ErrKeyLifetimeIsZero) } round := indexToRound(s.FirstValid, s.KeyLifetime, 0) - encodedKey := protocol.GetEncodingBuf() + encodedBuf := protocol.GetEncodingBuf() + encodedKey := encodedBuf.Bytes() err := store.Atomic(func(ctx context.Context, tx *sql.Tx) error { err := InstallStateProofTable(tx) // assumes schema table already exists (created by partInstallDatabase) if err != nil { @@ -126,7 +127,7 @@ func (s *Secrets) Persist(store db.Accessor) error { return nil }) - protocol.PutEncodingBuf(encodedKey) + protocol.PutEncodingBuf(encodedBuf.Update(encodedKey)) if err != nil { return fmt.Errorf("Secrets.Persist: %w", err) } diff --git a/data/transactions/signedtxn.go b/data/transactions/signedtxn.go index 4f0823d7ff..30d0e90e11 100644 --- a/data/transactions/signedtxn.go +++ b/data/transactions/signedtxn.go @@ -71,15 +71,17 @@ func (s SignedTxnInBlock) ID() { // GetEncodedLength returns the length in bytes of the encoded transaction func (s SignedTxn) GetEncodedLength() int { - enc := s.MarshalMsg(protocol.GetEncodingBuf()) - defer protocol.PutEncodingBuf(enc) + buf := protocol.GetEncodingBuf() + enc := s.MarshalMsg(buf.Bytes()) + defer protocol.PutEncodingBuf(buf.Update(enc)) return len(enc) } // GetEncodedLength returns the length in bytes of the encoded transaction func (s SignedTxnInBlock) GetEncodedLength() int { - enc := s.MarshalMsg(protocol.GetEncodingBuf()) - defer protocol.PutEncodingBuf(enc) + buf := protocol.GetEncodingBuf() + enc := s.MarshalMsg(buf.Bytes()) + defer protocol.PutEncodingBuf(buf.Update(enc)) return len(enc) } @@ -116,16 +118,17 @@ func (s *SignedTxnInBlock) ToBeHashed() (protocol.HashID, []byte) { // Hash implements an optimized version of crypto.HashObj(s). func (s *SignedTxnInBlock) Hash() crypto.Digest { - enc := s.MarshalMsg(append(protocol.GetEncodingBuf(), []byte(protocol.SignedTxnInBlock)...)) - defer protocol.PutEncodingBuf(enc) - + buf := protocol.GetEncodingBuf() + enc := s.MarshalMsg(append(buf.Bytes(), []byte(protocol.SignedTxnInBlock)...)) + defer protocol.PutEncodingBuf(buf.Update(enc)) return crypto.Hash(enc) } // HashSHA256 implements an optimized version of crypto.HashObj(s) using SHA256 instead of the default SHA512_256. func (s *SignedTxnInBlock) HashSHA256() crypto.Digest { - enc := s.MarshalMsg(append(protocol.GetEncodingBuf(), []byte(protocol.SignedTxnInBlock)...)) - defer protocol.PutEncodingBuf(enc) + buf := protocol.GetEncodingBuf() + enc := s.MarshalMsg(append(buf.Bytes(), []byte(protocol.SignedTxnInBlock)...)) + defer protocol.PutEncodingBuf(buf.Update(enc)) return sha256.Sum256(enc) } diff --git a/data/transactions/teal.go b/data/transactions/teal.go index 6d09ab3140..85a162854c 100644 --- a/data/transactions/teal.go +++ b/data/transactions/teal.go @@ -89,9 +89,13 @@ func (ed EvalDelta) Equal(o EvalDelta) bool { // tedious) field comparisons. == is not defined on almost any of the // subfields because of slices. func (stx SignedTxn) equal(o SignedTxn) bool { - stxenc := stx.MarshalMsg(protocol.GetEncodingBuf()) - defer protocol.PutEncodingBuf(stxenc) - oenc := o.MarshalMsg(protocol.GetEncodingBuf()) - defer protocol.PutEncodingBuf(oenc) + buf1 := protocol.GetEncodingBuf() + stxenc := stx.MarshalMsg(buf1.Bytes()) + defer protocol.PutEncodingBuf(buf1.Update(stxenc)) + + buf2 := protocol.GetEncodingBuf() + oenc := o.MarshalMsg(buf2.Bytes()) + defer protocol.PutEncodingBuf(buf2.Update(oenc)) + return bytes.Equal(stxenc, oenc) } diff --git a/protocol/codec.go b/protocol/codec.go index e0386eb9b2..85b59851f2 100644 --- a/protocol/codec.go +++ b/protocol/codec.go @@ -288,21 +288,38 @@ func (d *MsgpDecoderBytes) Remaining() int { // encodingPool holds temporary byte slice buffers used for encoding messages. var encodingPool = sync.Pool{ New: func() interface{} { - return []byte{} + return &EncodingBuf{b: make([]byte, 0, 1024)} }, } +type EncodingBuf struct { + b []byte +} + +func (eb *EncodingBuf) Bytes() []byte { + return eb.b +} + +func (eb *EncodingBuf) Update(v []byte) *EncodingBuf { + if cap(eb.b) < cap(v) { + eb.b = v + } + return eb +} + // GetEncodingBuf returns a byte slice that can be used for encoding a // temporary message. The byte slice has zero length but potentially // non-zero capacity. The caller gets full ownership of the byte slice, // but is encouraged to return it using PutEncodingBuf(). -func GetEncodingBuf() []byte { - return encodingPool.Get().([]byte)[:0] +func GetEncodingBuf() *EncodingBuf { + buf := encodingPool.Get().(*EncodingBuf) + buf.b = buf.b[:0] + return buf } // PutEncodingBuf places a byte slice into the pool of temporary buffers // for encoding. The caller gives up ownership of the byte slice when // passing it to PutEncodingBuf(). -func PutEncodingBuf(s []byte) { - encodingPool.Put(s) +func PutEncodingBuf(buf *EncodingBuf) { + encodingPool.Put(buf) }