Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

faster computation of transaction ID and length #1880

Merged
merged 1 commit into from
Feb 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion data/pools/transactionPool.go
Original file line number Diff line number Diff line change
Expand Up @@ -763,7 +763,7 @@ func (pool *TransactionPool) AssembleBlock(round basics.Round, deadline time.Tim

for i, txib := range payset {
fee := txib.Txn.Fee.Raw
encodedLen := len(protocol.Encode(&txib))
encodedLen := txib.GetEncodedLength()

stats.IncludedCount++
totalFees += fee
Expand Down
11 changes: 10 additions & 1 deletion data/transactions/signedtxn.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,16 @@ func (s SignedTxnInBlock) ID() {

// GetEncodedLength returns the length in bytes of the encoded transaction
func (s SignedTxn) GetEncodedLength() int {
return len(protocol.Encode(&s))
enc := s.MarshalMsg(protocol.GetEncodingBuf())
defer protocol.PutEncodingBuf(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)
return len(enc)
}

// Authorizer returns the address against which the signature/msig/lsig should be checked,
Expand Down
4 changes: 3 additions & 1 deletion data/transactions/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,9 @@ func (tx Transaction) ToBeHashed() (protocol.HashID, []byte) {

// ID returns the Txid (i.e., hash) of the transaction.
func (tx Transaction) ID() Txid {
return Txid(crypto.HashObj(tx))
enc := tx.MarshalMsg(append(protocol.GetEncodingBuf(), []byte(protocol.Transaction)...))
defer protocol.PutEncodingBuf(enc)
return Txid(crypto.Hash(enc))
}

// Sign signs a transaction using a given Account's secrets.
Expand Down
2 changes: 1 addition & 1 deletion ledger/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -733,7 +733,7 @@ func (eval *BlockEvaluator) transactionGroup(txgroup []transactions.SignedTxnWit
txibs = append(txibs, txib)

if eval.validate {
groupTxBytes += len(protocol.Encode(&txib))
groupTxBytes += txib.GetEncodedLength()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra brownie points ( overall solution ): we've currently triple-encoding the payset -

  1. we encode it to calculate the block size.
  2. we encode it to calculate the commit hash ( either via flat, or as Merkle tree ).
  3. we encode it as a whole for the purpose of preparing the proposal ( I know that this isn't always the case, but this case happens to be on the critical path ).

Caching the encoded data of the first block could help us repeating the process.

if eval.blockTxBytes+groupTxBytes > eval.proto.MaxTxnBytesPerBlock {
return ErrNoSpace
}
Expand Down
22 changes: 22 additions & 0 deletions protocol/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,3 +241,25 @@ func NewJSONDecoder(r io.Reader) Decoder {
func NewDecoderBytes(b []byte) Decoder {
return codec.NewDecoderBytes(b, CodecHandle)
}

// encodingPool holds temporary byte slice buffers used for encoding messages.
var encodingPool = sync.Pool{
New: func() interface{} {
return []byte{}
},
}

// 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]
}

// 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)
}