transaction: cache tx size, don't serialize it over and over again
This commit is contained in:
parent
a6a1df4e0d
commit
19c69618c5
5 changed files with 21 additions and 11 deletions
|
@ -1181,7 +1181,7 @@ func (bc *Blockchain) ApplyPolicyToTxSet(txes []*transaction.Transaction) []*tra
|
||||||
)
|
)
|
||||||
blockSize = uint32(io.GetVarSize(new(block.Block)) + io.GetVarSize(len(txes)+1))
|
blockSize = uint32(io.GetVarSize(new(block.Block)) + io.GetVarSize(len(txes)+1))
|
||||||
for i, tx := range txes {
|
for i, tx := range txes {
|
||||||
blockSize += uint32(io.GetVarSize(tx))
|
blockSize += uint32(tx.Size())
|
||||||
sysFee += tx.SystemFee
|
sysFee += tx.SystemFee
|
||||||
if blockSize > maxBlockSize || sysFee > maxBlockSysFee {
|
if blockSize > maxBlockSize || sysFee > maxBlockSysFee {
|
||||||
txes = txes[:i]
|
txes = txes[:i]
|
||||||
|
@ -1234,7 +1234,7 @@ func (bc *Blockchain) verifyAndPoolTx(t *transaction.Transaction, pool *mempool.
|
||||||
// Only one %w can be used.
|
// Only one %w can be used.
|
||||||
return fmt.Errorf("%w: %v", ErrPolicy, err)
|
return fmt.Errorf("%w: %v", ErrPolicy, err)
|
||||||
}
|
}
|
||||||
size := io.GetVarSize(t)
|
size := t.Size()
|
||||||
if size > transaction.MaxTransactionSize {
|
if size > transaction.MaxTransactionSize {
|
||||||
return fmt.Errorf("%w: (%d > MaxTransactionSize %d)", ErrTxTooBig, size, transaction.MaxTransactionSize)
|
return fmt.Errorf("%w: (%d > MaxTransactionSize %d)", ErrTxTooBig, size, transaction.MaxTransactionSize)
|
||||||
}
|
}
|
||||||
|
|
|
@ -524,8 +524,8 @@ func TestGetTransaction(t *testing.T) {
|
||||||
tx, height, err := bc.GetTransaction(block.Transactions[0].Hash())
|
tx, height, err := bc.GetTransaction(block.Transactions[0].Hash())
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
assert.Equal(t, block.Index, height)
|
assert.Equal(t, block.Index, height)
|
||||||
|
assert.Equal(t, txSize, tx.Size())
|
||||||
assert.Equal(t, block.Transactions[0], tx)
|
assert.Equal(t, block.Transactions[0], tx)
|
||||||
assert.Equal(t, txSize, io.GetVarSize(tx))
|
|
||||||
assert.Equal(t, 1, io.GetVarSize(tx.Attributes))
|
assert.Equal(t, 1, io.GetVarSize(tx.Attributes))
|
||||||
assert.Equal(t, 1, io.GetVarSize(tx.Scripts))
|
assert.Equal(t, 1, io.GetVarSize(tx.Scripts))
|
||||||
assert.NoError(t, bc.persist())
|
assert.NoError(t, bc.persist())
|
||||||
|
|
|
@ -62,8 +62,8 @@ type Transaction struct {
|
||||||
// for correct signing/verification.
|
// for correct signing/verification.
|
||||||
Network netmode.Magic
|
Network netmode.Magic
|
||||||
|
|
||||||
// feePerByte is the ratio of NetworkFee and tx size, used for calculating tx priority.
|
// size is transaction's serialized size.
|
||||||
feePerByte int64
|
size int
|
||||||
|
|
||||||
// Hash of the transaction (double SHA256).
|
// Hash of the transaction (double SHA256).
|
||||||
hash util.Uint256
|
hash util.Uint256
|
||||||
|
@ -158,6 +158,7 @@ func (t *Transaction) DecodeBinary(br *io.BinReader) {
|
||||||
// to do it anymore.
|
// to do it anymore.
|
||||||
if br.Err == nil {
|
if br.Err == nil {
|
||||||
br.Err = t.createHash()
|
br.Err = t.createHash()
|
||||||
|
_ = t.Size()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,18 +253,22 @@ func NewTransactionFromBytes(network netmode.Magic, b []byte) (*Transaction, err
|
||||||
if r.Err == nil {
|
if r.Err == nil {
|
||||||
return nil, errors.New("additional data after the transaction")
|
return nil, errors.New("additional data after the transaction")
|
||||||
}
|
}
|
||||||
tx.feePerByte = tx.NetworkFee / int64(len(b))
|
tx.size = len(b)
|
||||||
return tx, nil
|
return tx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FeePerByte returns NetworkFee of the transaction divided by
|
// FeePerByte returns NetworkFee of the transaction divided by
|
||||||
// its size
|
// its size
|
||||||
func (t *Transaction) FeePerByte() int64 {
|
func (t *Transaction) FeePerByte() int64 {
|
||||||
if t.feePerByte != 0 {
|
return t.NetworkFee / int64(t.Size())
|
||||||
return t.feePerByte
|
}
|
||||||
|
|
||||||
|
// Size returns size of the serialized transaction.
|
||||||
|
func (t *Transaction) Size() int {
|
||||||
|
if t.size == 0 {
|
||||||
|
t.size = io.GetVarSize(t)
|
||||||
}
|
}
|
||||||
t.feePerByte = t.NetworkFee / int64(io.GetVarSize(t))
|
return t.size
|
||||||
return t.feePerByte
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sender returns the sender of the transaction which is always on the first place
|
// Sender returns the sender of the transaction which is always on the first place
|
||||||
|
@ -296,7 +301,7 @@ type transactionJSON struct {
|
||||||
func (t *Transaction) MarshalJSON() ([]byte, error) {
|
func (t *Transaction) MarshalJSON() ([]byte, error) {
|
||||||
tx := transactionJSON{
|
tx := transactionJSON{
|
||||||
TxID: t.Hash(),
|
TxID: t.Hash(),
|
||||||
Size: io.GetVarSize(t),
|
Size: t.Size(),
|
||||||
Version: t.Version,
|
Version: t.Version,
|
||||||
Nonce: t.Nonce,
|
Nonce: t.Nonce,
|
||||||
Sender: address.Uint160ToString(t.Sender()),
|
Sender: address.Uint160ToString(t.Sender()),
|
||||||
|
@ -329,6 +334,9 @@ func (t *Transaction) UnmarshalJSON(data []byte) error {
|
||||||
if t.Hash() != tx.TxID {
|
if t.Hash() != tx.TxID {
|
||||||
return errors.New("txid doesn't match transaction hash")
|
return errors.New("txid doesn't match transaction hash")
|
||||||
}
|
}
|
||||||
|
if t.Size() != tx.Size {
|
||||||
|
return errors.New("'size' doesn't match transaction size")
|
||||||
|
}
|
||||||
|
|
||||||
return t.isValid()
|
return t.isValid()
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ func TestNew(t *testing.T) {
|
||||||
assert.Equal(t, script, tx.Script)
|
assert.Equal(t, script, tx.Script)
|
||||||
// Update hash fields to match tx2 that is gonna autoupdate them on decode.
|
// Update hash fields to match tx2 that is gonna autoupdate them on decode.
|
||||||
_ = tx.Hash()
|
_ = tx.Hash()
|
||||||
|
_ = tx.Size()
|
||||||
testserdes.EncodeDecodeBinary(t, tx, &Transaction{Network: netmode.UnitTestNet})
|
testserdes.EncodeDecodeBinary(t, tx, &Transaction{Network: netmode.UnitTestNet})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -811,6 +811,7 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
|
||||||
t.Run("getrawtransaction 2 arguments, verbose", func(t *testing.T) {
|
t.Run("getrawtransaction 2 arguments, verbose", func(t *testing.T) {
|
||||||
block, _ := chain.GetBlock(chain.GetHeaderHash(0))
|
block, _ := chain.GetBlock(chain.GetHeaderHash(0))
|
||||||
TXHash := block.Transactions[0].Hash()
|
TXHash := block.Transactions[0].Hash()
|
||||||
|
_ = block.Transactions[0].Size()
|
||||||
rpc := fmt.Sprintf(`{"jsonrpc": "2.0", "id": 1, "method": "getrawtransaction", "params": ["%s", 1]}"`, TXHash.StringLE())
|
rpc := fmt.Sprintf(`{"jsonrpc": "2.0", "id": 1, "method": "getrawtransaction", "params": ["%s", 1]}"`, TXHash.StringLE())
|
||||||
body := doRPCCall(rpc, httpSrv.URL, t)
|
body := doRPCCall(rpc, httpSrv.URL, t)
|
||||||
txOut := checkErrGetResult(t, body, false)
|
txOut := checkErrGetResult(t, body, false)
|
||||||
|
|
Loading…
Reference in a new issue