From 883ed31199149c341d2611b291a621f0c1cdeeb0 Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Fri, 15 Sep 2023 13:08:49 +0530 Subject: [PATCH 01/22] initial commit to implement bor_sendRawTransactionConditional --- core/state/intra_block_state.go | 40 +++++ core/state/intra_block_state_test.go | 64 ++++++++ core/types/access_list_tx.go | 8 + core/types/blob_tx_wrapper.go | 8 + core/types/block.go | 38 +++++ core/types/block_test.go | 164 +++++++++++++++++++++ core/types/dynamic_fee_tx.go | 8 + core/types/legacy_tx.go | 8 + core/types/transaction.go | 5 + core/types/transaction_conditional.go | 162 ++++++++++++++++++++ core/types/transaction_conditional_test.go | 30 ++++ eth/stagedsync/stage_mining_exec.go | 24 +++ go.mod | 2 + go.sum | 2 + rpc/types.go | 12 ++ turbo/jsonrpc/bor_api.go | 12 +- turbo/jsonrpc/bor_snapshot.go | 97 ++++++++++++ turbo/jsonrpc/daemon.go | 2 +- 18 files changed, 680 insertions(+), 6 deletions(-) create mode 100644 core/types/transaction_conditional.go create mode 100644 core/types/transaction_conditional_test.go diff --git a/core/state/intra_block_state.go b/core/state/intra_block_state.go index 9064d22d3d4..8f15a0d6cd3 100644 --- a/core/state/intra_block_state.go +++ b/core/state/intra_block_state.go @@ -26,6 +26,7 @@ import ( "github.com/ledgerwatch/erigon-lib/chain" libcommon "github.com/ledgerwatch/erigon-lib/common" types2 "github.com/ledgerwatch/erigon-lib/types" + "github.com/ledgerwatch/erigon/common" "github.com/ledgerwatch/erigon/common/u256" "github.com/ledgerwatch/erigon/core/types" "github.com/ledgerwatch/erigon/core/types/accounts" @@ -827,3 +828,42 @@ func (sdb *IntraBlockState) AddressInAccessList(addr libcommon.Address) bool { func (sdb *IntraBlockState) SlotInAccessList(addr libcommon.Address, slot libcommon.Hash) (addressPresent bool, slotPresent bool) { return sdb.accessList.Contains(addr, slot) } + +// ValidateKnownAccounts validates the knownAccounts passed in the options parameter in the conditional transaction (EIP-4337) +func (sdb *IntraBlockState) ValidateKnownAccounts(knownAccounts types.KnownAccounts) error { + if knownAccounts == nil { + return nil + } + + for k, v := range knownAccounts { + tempAccount, err := sdb.stateReader.ReadAccountData(k) + if err != nil { + return fmt.Errorf("error reading account data at: %v", k) + } + + // check if the value is hex string or an object + switch { + case v.IsSingle(): + if tempAccount != nil { + if *v.Single != tempAccount.Root { + return fmt.Errorf("invalid root hash for: %v root hash: %v actual root hash: %v", k, v.Single, tempAccount.Root) + } + } else { + return fmt.Errorf("Storage Trie is nil for: %v", k) + } + case v.IsStorage(): + for slot, value := range v.Storage { + slot := slot + tempByte, _ := sdb.stateReader.ReadAccountStorage(k, tempAccount.Incarnation, &slot) + actualValue := libcommon.BytesToHash(common.LeftPadBytes(tempByte, 32)) + if value != actualValue { + return fmt.Errorf("invalid slot value at address: %v slot: %v value: %v actual value: %v", k, slot, value, actualValue) + } + } + default: + return fmt.Errorf("impossible to validate known accounts: %v", k) + } + } + + return nil +} diff --git a/core/state/intra_block_state_test.go b/core/state/intra_block_state_test.go index 08f4b28899f..27889811014 100644 --- a/core/state/intra_block_state_test.go +++ b/core/state/intra_block_state_test.go @@ -35,6 +35,7 @@ import ( libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/kv/memdb" "github.com/ledgerwatch/erigon/core/types" + "github.com/stretchr/testify/require" ) func TestSnapshotRandom(t *testing.T) { @@ -348,3 +349,66 @@ func TestTransientStorage(t *testing.T) { t.Fatalf("transient storage mismatch: have %x, want %x", got, exp) } } + +func TestValidateKnownAccounts(t *testing.T) { + t.Parallel() + + knownAccounts := make(types.KnownAccounts) + + types.InsertKnownAccounts(knownAccounts, libcommon.HexToAddress("0xadd1add1add1add1add1add1add1add1add1add1"), libcommon.HexToHash("0x2d6f8a898e7dec0bb7a50e8c142be32d7c98c096ff68ed57b9b08280d9aca1ce")) + types.InsertKnownAccounts(knownAccounts, libcommon.HexToAddress("0xadd2add2add2add2add2add2add2add2add2add2"), map[libcommon.Hash]libcommon.Hash{ + libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000aaa"): libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000bbb"), + libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000ccc"): libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000ddd"), + }) + + stateobjaddr1 := libcommon.HexToAddress("0xadd1add1add1add1add1add1add1add1add1add1") + stateobjaddr2 := libcommon.HexToAddress("0xadd2add2add2add2add2add2add2add2add2add2") + + storageaddr1 := libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000zzz") + storageaddr21 := libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000aaa") + storageaddr22 := libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000ccc") + + data1 := libcommon.BytesToHash([]byte{24}) + data21 := libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000bbb") + data22 := libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000ddd") + + s := newStateTest() + + // set initial state object value + s.state.SetState(stateobjaddr1, storageaddr1, data1) + s.state.SetState(stateobjaddr2, storageaddr21, data21) + s.state.SetState(stateobjaddr2, storageaddr22, data22) + + require.NoError(t, s.state.ValidateKnownAccounts(knownAccounts)) + + types.InsertKnownAccounts(knownAccounts, libcommon.HexToAddress("0xadd1add1add1add1add1add1add1add1add1add2"), libcommon.HexToHash("0x2d6f8a898e7dec0bb7a50e8c142be32d7c98c096ff68ed57b9b08280d9aca1cf")) + + stateobjaddr3 := libcommon.HexToAddress("0xadd1add1add1add1add1add1add1add1add1add2") + storageaddr3 := libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000yyy") + data3 := libcommon.BytesToHash([]byte{24}) + + s.state.SetState(stateobjaddr3, storageaddr3, data3) + + // expected error + err := s.state.ValidateKnownAccounts(knownAccounts) + require.Error(t, err, "should have been an error") + + // correct the previous mistake "0x2d6f8a898e7dec0bb7a50e8c142be32d7c98c096ff68ed57b9b08280d9aca1cf" -> "0x2d6f8a898e7dec0bb7a50e8c142be32d7c98c096ff68ed57b9b08280d9aca1ce" + types.InsertKnownAccounts(knownAccounts, libcommon.HexToAddress("0xadd1add1add1add1add1add1add1add1add1add2"), libcommon.HexToHash("0x2d6f8a898e7dec0bb7a50e8c142be32d7c98c096ff68ed57b9b08280d9aca1ce")) + types.InsertKnownAccounts(knownAccounts, libcommon.HexToAddress("0xadd2add2add2add2add2add2add2add2add2add3"), map[libcommon.Hash]libcommon.Hash{ + libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000aaa"): libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000bbb"), + libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000ccc"): libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000ddd"), + }) + + stateobjaddr4 := libcommon.HexToAddress("0xadd2add2add2add2add2add2add2add2add2add3") + storageaddr41 := libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000aaa") + storageaddr42 := libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000ccc") + data4 := libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000bbb") + + s.state.SetState(stateobjaddr4, storageaddr41, data4) + s.state.SetState(stateobjaddr4, storageaddr42, data4) + + // expected error + err = s.state.ValidateKnownAccounts(knownAccounts) + require.Error(t, err, "should have been an error") +} diff --git a/core/types/access_list_tx.go b/core/types/access_list_tx.go index 562205d3327..d5c1495e8f9 100644 --- a/core/types/access_list_tx.go +++ b/core/types/access_list_tx.go @@ -554,3 +554,11 @@ func (tx *AccessListTx) Sender(signer Signer) (libcommon.Address, error) { tx.from.Store(addr) return addr, nil } + +func (tx *AccessListTx) PutOptions(options *OptionsAA4337) { + tx.LegacyTx.CommonTx.TransactionMisc.optionsAA4337 = options +} + +func (tx *AccessListTx) GetOptions() *OptionsAA4337 { + return tx.LegacyTx.CommonTx.TransactionMisc.optionsAA4337 +} diff --git a/core/types/blob_tx_wrapper.go b/core/types/blob_tx_wrapper.go index a078cc351f5..e580350ea08 100644 --- a/core/types/blob_tx_wrapper.go +++ b/core/types/blob_tx_wrapper.go @@ -381,3 +381,11 @@ func (txw *BlobTxWrapper) MarshalBinary(w io.Writer) error { func (txw BlobTxWrapper) EncodeRLP(w io.Writer) error { return txw.Tx.EncodeRLP(w) } + +func (txw BlobTxWrapper) PutOptions(options *OptionsAA4337) { + txw.Tx.DynamicFeeTransaction.CommonTx.TransactionMisc.optionsAA4337 = options +} + +func (txw BlobTxWrapper) GetOptions() *OptionsAA4337 { + return txw.Tx.DynamicFeeTransaction.CommonTx.TransactionMisc.optionsAA4337 +} diff --git a/core/types/block.go b/core/types/block.go index c99ec59a9fa..81e3e4c3e43 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -611,6 +611,44 @@ func (h *Header) SanityCheck() error { return nil } +// ValidateBlockNumberOptions4337 validates the block range passed in the options parameter in the conditional transaction (EIP-4337) +func (h *Header) ValidateBlockNumberOptions4337(minBlockNumber *big.Int, maxBlockNumber *big.Int) error { + currentBlockNumber := h.Number + + if minBlockNumber != nil { + if currentBlockNumber.Cmp(minBlockNumber) == -1 { + return fmt.Errorf("current block number %v is less than minimum block number: %v", currentBlockNumber, minBlockNumber) + } + } + + if maxBlockNumber != nil { + if currentBlockNumber.Cmp(maxBlockNumber) == 1 { + return fmt.Errorf("current block number %v is greater than maximum block number: %v", currentBlockNumber, maxBlockNumber) + } + } + + return nil +} + +// ValidateBlockNumberOptions4337 validates the timestamp range passed in the options parameter in the conditional transaction (EIP-4337) +func (h *Header) ValidateTimestampOptions4337(minTimestamp *uint64, maxTimestamp *uint64) error { + currentBlockTime := h.Time + + if minTimestamp != nil { + if currentBlockTime < *minTimestamp { + return fmt.Errorf("current block time %v is less than minimum timestamp: %v", currentBlockTime, minTimestamp) + } + } + + if maxTimestamp != nil { + if currentBlockTime > *maxTimestamp { + return fmt.Errorf("current block time %v is greater than maximum timestamp: %v", currentBlockTime, maxTimestamp) + } + } + + return nil +} + // Body is a simple (mutable, non-safe) data container for storing and moving // a block's data contents (transactions and uncles) together. type Body struct { diff --git a/core/types/block_test.go b/core/types/block_test.go index be05c716b26..1d1fc4c0d1b 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -512,3 +512,167 @@ func TestCopyTxs(t *testing.T) { copies := CopyTxs(txs) assert.Equal(t, txs, copies) } + +func TestValidateBlockNumberOptions4337(t *testing.T) { + t.Parallel() + + testsPass := []struct { + number string + header Header + minBlockNumber *big.Int + maxBlockNumber *big.Int + }{ + { + "1", + Header{Number: big.NewInt(10)}, + big.NewInt(0), + big.NewInt(20), + }, + { + "2", + Header{Number: big.NewInt(10)}, + big.NewInt(10), + big.NewInt(10), + }, + { + "3", + Header{Number: big.NewInt(10)}, + big.NewInt(10), + big.NewInt(11), + }, + { + "4", + Header{Number: big.NewInt(10)}, + big.NewInt(0), + big.NewInt(10), + }, + } + + testsFail := []struct { + number string + header Header + minBlockNumber *big.Int + maxBlockNumber *big.Int + }{ + { + "5", + Header{Number: big.NewInt(10)}, + big.NewInt(0), + big.NewInt(0), + }, + { + "6", + Header{Number: big.NewInt(10)}, + big.NewInt(0), + big.NewInt(9), + }, + { + "7", + Header{Number: big.NewInt(10)}, + big.NewInt(11), + big.NewInt(9), + }, + { + "8", + Header{Number: big.NewInt(10)}, + big.NewInt(11), + big.NewInt(20), + }, + } + + for _, test := range testsPass { + if err := test.header.ValidateBlockNumberOptions4337(test.minBlockNumber, test.maxBlockNumber); err != nil { + t.Fatalf("test number %v should not have failed. err: %v", test.number, err) + } + } + + for _, test := range testsFail { + if err := test.header.ValidateBlockNumberOptions4337(test.minBlockNumber, test.maxBlockNumber); err == nil { + t.Fatalf("test number %v should have failed. err is nil", test.number) + } + } +} + +func TestValidateTimestampOptions4337(t *testing.T) { + t.Parallel() + + u64Ptr := func(n uint64) *uint64 { + return &n + } + + testsPass := []struct { + number string + header Header + minTimestamp *uint64 + maxTimestamp *uint64 + }{ + { + "1", + Header{Time: 1600000000}, + u64Ptr(1500000000), + u64Ptr(1700000000), + }, + { + "2", + Header{Time: 1600000000}, + u64Ptr(1600000000), + u64Ptr(1600000000), + }, + { + "3", + Header{Time: 1600000000}, + u64Ptr(1600000000), + u64Ptr(1700000000), + }, + { + "4", + Header{Time: 1600000000}, + u64Ptr(1500000000), + u64Ptr(1600000000), + }, + } + + testsFail := []struct { + number string + header Header + minTimestamp *uint64 + maxTimestamp *uint64 + }{ + { + "5", + Header{Time: 1600000000}, + u64Ptr(1500000000), + u64Ptr(1500000000), + }, + { + "6", + Header{Time: 1600000000}, + u64Ptr(1400000000), + u64Ptr(1500000000), + }, + { + "7", + Header{Time: 1600000000}, + u64Ptr(1700000000), + u64Ptr(1500000000), + }, + { + "8", + Header{Time: 1600000000}, + u64Ptr(1700000000), + u64Ptr(1800000000), + }, + } + + for _, test := range testsPass { + if err := test.header.ValidateTimestampOptions4337(test.minTimestamp, test.maxTimestamp); err != nil { + t.Fatalf("test number %v should not have failed. err: %v", test.number, err) + } + } + + for _, test := range testsFail { + if err := test.header.ValidateTimestampOptions4337(test.minTimestamp, test.maxTimestamp); err == nil { + t.Fatalf("test number %v should have failed. err is nil", test.number) + } + } +} diff --git a/core/types/dynamic_fee_tx.go b/core/types/dynamic_fee_tx.go index 0fa8b865569..4f07e1bbf4d 100644 --- a/core/types/dynamic_fee_tx.go +++ b/core/types/dynamic_fee_tx.go @@ -473,6 +473,14 @@ func (tx *DynamicFeeTransaction) Sender(signer Signer) (libcommon.Address, error return addr, nil } +func (tx *DynamicFeeTransaction) PutOptions(options *OptionsAA4337) { + tx.CommonTx.TransactionMisc.optionsAA4337 = options +} + +func (tx *DynamicFeeTransaction) GetOptions() *OptionsAA4337 { + return tx.CommonTx.TransactionMisc.optionsAA4337 +} + // NewEIP1559Transaction creates an unsigned eip1559 transaction. func NewEIP1559Transaction(chainID uint256.Int, nonce uint64, to libcommon.Address, amount *uint256.Int, gasLimit uint64, gasPrice *uint256.Int, gasTip *uint256.Int, gasFeeCap *uint256.Int, data []byte) *DynamicFeeTransaction { return &DynamicFeeTransaction{ diff --git a/core/types/legacy_tx.go b/core/types/legacy_tx.go index 92c12f2f964..daf871102fd 100644 --- a/core/types/legacy_tx.go +++ b/core/types/legacy_tx.go @@ -463,3 +463,11 @@ func (tx *LegacyTx) Sender(signer Signer) (libcommon.Address, error) { tx.from.Store(addr) return addr, nil } + +func (tx *LegacyTx) PutOptions(options *OptionsAA4337) { + tx.CommonTx.TransactionMisc.optionsAA4337 = options +} + +func (tx *LegacyTx) GetOptions() *OptionsAA4337 { + return tx.CommonTx.TransactionMisc.optionsAA4337 +} diff --git a/core/types/transaction.go b/core/types/transaction.go index 71f6f729aa9..c29207ede5b 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -96,6 +96,8 @@ type Transaction interface { SetSender(libcommon.Address) IsContractDeploy() bool Unwrap() Transaction // If this is a network wrapper, returns the unwrapped tx. Otherwise returns itself. + PutOptions(options *OptionsAA4337) + GetOptions() *OptionsAA4337 } // TransactionMisc is collection of miscelaneous fields for transaction that is supposed to be embedded into concrete @@ -103,6 +105,9 @@ type Transaction interface { type TransactionMisc struct { time time.Time // Time first seen locally (spam avoidance) + // knownAccounts (EIP-4337) + optionsAA4337 *OptionsAA4337 + // caches hash atomic.Value //nolint:structcheck from atomic.Value diff --git a/core/types/transaction_conditional.go b/core/types/transaction_conditional.go new file mode 100644 index 00000000000..e6393c6319c --- /dev/null +++ b/core/types/transaction_conditional.go @@ -0,0 +1,162 @@ +// Copyright 2014 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package types + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "math/big" + + libcommon "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/common/hexutility" +) + +type KnownAccounts map[libcommon.Address]*Value + +type Value struct { + Single *libcommon.Hash + Storage map[libcommon.Hash]libcommon.Hash +} + +func SingleFromHex(hex string) *Value { + return &Value{Single: libcommon.HexToRefHash(hex)} +} + +func FromMap(m map[string]string) *Value { + res := map[libcommon.Hash]libcommon.Hash{} + + for k, v := range m { + res[libcommon.HexToHash(k)] = libcommon.HexToHash(v) + } + + return &Value{Storage: res} +} + +func (v *Value) IsSingle() bool { + return v != nil && v.Single != nil && !v.IsStorage() +} + +func (v *Value) IsStorage() bool { + return v != nil && v.Storage != nil +} + +const EmptyValue = "{}" + +func (v *Value) MarshalJSON() ([]byte, error) { + if v.IsSingle() { + return json.Marshal(v.Single) + } + + if v.IsStorage() { + return json.Marshal(v.Storage) + } + + return []byte(EmptyValue), nil +} + +const hashTypeName = "Hash" + +func (v *Value) UnmarshalJSON(data []byte) error { + if len(data) == 0 { + return nil + } + + var m map[string]json.RawMessage + + err := json.Unmarshal(data, &m) + if err != nil { + // single Hash value case + v.Single = new(libcommon.Hash) + + innerErr := json.Unmarshal(data, v.Single) + if innerErr != nil { + return fmt.Errorf("can't unmarshal to single value with error: %v value %q", innerErr, string(data)) + } + + return nil + } + + res := make(map[libcommon.Hash]libcommon.Hash, len(m)) + + for k, v := range m { + // check k if it is a Hex value + var kHash libcommon.Hash + + err = hexutility.UnmarshalFixedText(hashTypeName, []byte(k), kHash[:]) + if err != nil { + return fmt.Errorf("%w by key: %s with key %q and value %q", ErrKnownAccounts, err, k, string(v)) + } + + // check v if it is a Hex value + var vHash libcommon.Hash + + err = hexutility.UnmarshalFixedText("hashTypeName", bytes.Trim(v, "\""), vHash[:]) + if err != nil { + return fmt.Errorf("%w by value: %s with key %q and value %q", ErrKnownAccounts, err, k, string(v)) + } + + res[kHash] = vHash + } + + v.Storage = res + + return nil +} + +func InsertKnownAccounts[T libcommon.Hash | map[libcommon.Hash]libcommon.Hash](accounts KnownAccounts, k libcommon.Address, v T) { + switch typedV := any(v).(type) { + case libcommon.Hash: + accounts[k] = &Value{Single: &typedV} + case map[libcommon.Hash]libcommon.Hash: + accounts[k] = &Value{Storage: typedV} + } +} + +type OptionsAA4337 struct { + KnownAccounts KnownAccounts `json:"knownAccounts"` + BlockNumberMin *big.Int `json:"blockNumberMin"` + BlockNumberMax *big.Int `json:"blockNumberMax"` + TimestampMin *uint64 `json:"timestampMin"` + TimestampMax *uint64 `json:"timestampMax"` +} + +var ErrKnownAccounts = errors.New("an incorrect list of knownAccounts") + +func (ka KnownAccounts) ValidateLength() error { + if ka == nil { + return nil + } + + length := 0 + + for _, v := range ka { + // check if the value is hex string or an object + if v.IsSingle() { + length += 1 + } else { + length += len(v.Storage) + } + } + + if length >= 1000 { + return fmt.Errorf("number of slots/accounts in KnownAccounts %v exceeds the limit of 1000", length) + } + + return nil +} diff --git a/core/types/transaction_conditional_test.go b/core/types/transaction_conditional_test.go new file mode 100644 index 00000000000..6923e17c284 --- /dev/null +++ b/core/types/transaction_conditional_test.go @@ -0,0 +1,30 @@ +package types + +import ( + "encoding/json" + "testing" + + "github.com/ledgerwatch/erigon-lib/common" + "github.com/stretchr/testify/require" +) + +func TestKnownAccounts(t *testing.T) { + t.Parallel() + + requestRaw := []byte(`{"0xadd1add1add1add1add1add1add1add1add1add1": "0x000000000000000000000000313aadca1750caadc7bcb26ff08175c95dcf8e38", "0xadd2add2add2add2add2add2add2add2add2add2": {"0x0000000000000000000000000000000000000000000000000000000000000aaa": "0x0000000000000000000000000000000000000000000000000000000000000bbb", "0x0000000000000000000000000000000000000000000000000000000000000ccc": "0x0000000000000000000000000000000000000000000000000000000000000ddd"}}`) + + accs := &KnownAccounts{} + + err := json.Unmarshal(requestRaw, accs) + require.NoError(t, err) + + expected := &KnownAccounts{ + common.HexToAddress("0xadd1add1add1add1add1add1add1add1add1add1"): SingleFromHex("0x000000000000000000000000313aadca1750caadc7bcb26ff08175c95dcf8e38"), + common.HexToAddress("0xadd2add2add2add2add2add2add2add2add2add2"): FromMap(map[string]string{ + "0x0000000000000000000000000000000000000000000000000000000000000aaa": "0x0000000000000000000000000000000000000000000000000000000000000bbb", + "0x0000000000000000000000000000000000000000000000000000000000000ccc": "0x0000000000000000000000000000000000000000000000000000000000000ddd", + }), + } + + require.Equal(t, expected, accs) +} diff --git a/eth/stagedsync/stage_mining_exec.go b/eth/stagedsync/stage_mining_exec.go index 4bb14b2f0b1..41ed85ffc7e 100644 --- a/eth/stagedsync/stage_mining_exec.go +++ b/eth/stagedsync/stage_mining_exec.go @@ -437,6 +437,30 @@ LOOP: continue } + // not prioritising conditional transaction, yet. + if options := txn.GetOptions(); options != nil { + if err := header.ValidateBlockNumberOptions4337(options.BlockNumberMin, options.BlockNumberMax); err != nil { + log.Trace("Dropping conditional transaction", "from", from, "hash", txn.Hash(), "reason", err) + txs.Pop() + + continue + } + + if err := header.ValidateTimestampOptions4337(options.TimestampMin, options.TimestampMax); err != nil { + log.Trace("Dropping conditional transaction", "from", from, "hash", txn.Hash(), "reason", err) + txs.Pop() + + continue + } + + if err := ibs.ValidateKnownAccounts(options.KnownAccounts); err != nil { + log.Trace("Dropping conditional transaction", "from", from, "hash", txn.Hash(), "reason", err) + txs.Pop() + + continue + } + } + // Check whether the txn is replay protected. If we're not in the EIP155 (Spurious Dragon) hf // phase, start ignoring the sender until we do. if txn.Protected() && !chainConfig.IsSpuriousDragon(header.Number.Uint64()) { diff --git a/go.mod b/go.mod index 7b051e4b162..18b499476b8 100644 --- a/go.mod +++ b/go.mod @@ -275,3 +275,5 @@ require ( replace github.com/tendermint/tendermint => github.com/bnb-chain/tendermint v0.31.12 replace github.com/VictoriaMetrics/metrics => github.com/ledgerwatch/victoria-metrics v0.0.4 + +replace github.com/ledgerwatch/erigon-lib => github.com/pratikspatil024/erigon-lib v0.0.0-20230914110124-2768437ea2d4 diff --git a/go.sum b/go.sum index c54b61c31ec..cc3186133f2 100644 --- a/go.sum +++ b/go.sum @@ -699,6 +699,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/pratikspatil024/erigon-lib v0.0.0-20230914110124-2768437ea2d4 h1:QlGItRoGzXyVIied7fsN0RaanngktpGqDmLbT8J2KEA= +github.com/pratikspatil024/erigon-lib v0.0.0-20230914110124-2768437ea2d4/go.mod h1:DRy/PNMCuzakVJFE42OR9F3SARTLxlfK7R4JwP5u/5k= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= diff --git a/rpc/types.go b/rpc/types.go index 58683829c97..c8e2813f3fd 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -456,3 +456,15 @@ func (ts *Timestamp) UnmarshalJSON(data []byte) error { return nil } + +type OptionsValidateError struct{ Message string } + +func (e *OptionsValidateError) ErrorCode() int { return -32003 } + +func (e *OptionsValidateError) Error() string { return e.Message } + +type KnownAccountsLimitExceededError struct{ Message string } + +func (e *KnownAccountsLimitExceededError) ErrorCode() int { return -32005 } + +func (e *KnownAccountsLimitExceededError) Error() string { return e.Message } diff --git a/turbo/jsonrpc/bor_api.go b/turbo/jsonrpc/bor_api.go index 2ee4a461e86..238bc3db10d 100644 --- a/turbo/jsonrpc/bor_api.go +++ b/turbo/jsonrpc/bor_api.go @@ -2,9 +2,9 @@ package jsonrpc import ( "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" "github.com/ledgerwatch/erigon-lib/kv" - "github.com/ledgerwatch/erigon/consensus/bor" "github.com/ledgerwatch/erigon/consensus/bor/valset" "github.com/ledgerwatch/erigon/rpc" ) @@ -26,15 +26,17 @@ type BorAPI interface { // BorImpl is implementation of the BorAPI interface type BorImpl struct { *BaseAPI - db kv.RoDB // the chain db - bor *bor.Bor + db kv.RoDB // the chain db + borDb kv.RoDB // the consensus db + txPool txpool.TxpoolClient } // NewBorAPI returns BorImpl instance -func NewBorAPI(base *BaseAPI, db kv.RoDB, bor *bor.Bor) *BorImpl { +func NewBorAPI(base *BaseAPI, db kv.RoDB, borDb kv.RoDB, txpool txpool.TxpoolClient) *BorImpl { return &BorImpl{ BaseAPI: base, db: db, - bor: bor, + borDb: borDb, + txPool: txpool, } } diff --git a/turbo/jsonrpc/bor_snapshot.go b/turbo/jsonrpc/bor_snapshot.go index 91bdf642afb..b2343b67309 100644 --- a/turbo/jsonrpc/bor_snapshot.go +++ b/turbo/jsonrpc/bor_snapshot.go @@ -8,6 +8,8 @@ import ( "github.com/ledgerwatch/erigon-lib/chain" "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/common/hexutility" + txPoolProto "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/log/v3" @@ -15,9 +17,12 @@ import ( "github.com/ledgerwatch/erigon/consensus/bor" "github.com/ledgerwatch/erigon/consensus/bor/valset" "github.com/ledgerwatch/erigon/core/rawdb" + "github.com/ledgerwatch/erigon/core/state" "github.com/ledgerwatch/erigon/core/types" "github.com/ledgerwatch/erigon/eth/borfinality/whitelist" + "github.com/ledgerwatch/erigon/eth/ethconfig" "github.com/ledgerwatch/erigon/rpc" + "github.com/ledgerwatch/erigon/turbo/rpchelper" ) type Snapshot struct { @@ -250,6 +255,98 @@ func (api *BorImpl) GetVoteOnHash(ctx context.Context, starBlockNr uint64, endBl return true, nil } +// SendRawTransactionConditional will add the signed transaction to the transaction pool. +// The sender/bundler is responsible for signing the transaction +func (api *BorImpl) SendRawTransactionConditional(ctx context.Context, encodedTx hexutility.Bytes, options types.OptionsAA4337) (common.Hash, error) { + txn, err := types.DecodeWrappedTransaction(encodedTx) + if err != nil { + return common.Hash{}, err + } + + txTemp, err := api.db.BeginRo(ctx) + if err != nil { + return common.Hash{}, err + } + defer txTemp.Rollback() + + currentHeader := rawdb.ReadCurrentHeader(txTemp) + + tempBlockNumber := rpc.BlockNumber(currentHeader.Number.Int64()) + tempBlockorHash := rpc.BlockNumberOrHash{BlockNumber: &tempBlockNumber} + + readerTemp, err := rpchelper.CreateStateReader(ctx, txTemp, tempBlockorHash, 0, api.filters, api.stateCache, api.historyV3(txTemp), "") + if err != nil { + return common.Hash{}, err + } + + currentState := state.New(readerTemp) + + // check block number range + if err := currentHeader.ValidateBlockNumberOptions4337(options.BlockNumberMin, options.BlockNumberMax); err != nil { + return common.Hash{}, &rpc.OptionsValidateError{Message: "out of block range. err: " + err.Error()} + } + + // check timestamp range + if err := currentHeader.ValidateTimestampOptions4337(options.TimestampMin, options.TimestampMax); err != nil { + return common.Hash{}, &rpc.OptionsValidateError{Message: "out of time range. err: " + err.Error()} + } + + // check knownAccounts length (number of slots/accounts) should be less than 1000 + if err := options.KnownAccounts.ValidateLength(); err != nil { + return common.Hash{}, &rpc.KnownAccountsLimitExceededError{Message: "limit exceeded. err: " + err.Error()} + } + + // check knownAccounts + if err := currentState.ValidateKnownAccounts(options.KnownAccounts); err != nil { + return common.Hash{}, &rpc.OptionsValidateError{Message: "storage error. err: " + err.Error()} + } + + // put options data in Tx, to use it later while block building + txn.PutOptions(&options) + + // If the transaction fee cap is already specified, ensure the + // fee of the given transaction is _reasonable_. + if err := checkTxFee(txn.GetPrice().ToBig(), txn.GetGas(), ethconfig.Defaults.RPCTxFeeCap); err != nil { + return common.Hash{}, err + } + if !txn.Protected() { + return common.Hash{}, errors.New("only replay-protected (EIP-155) transactions allowed over RPC") + } + + // this has been moved to prior to adding of transactions to capture the + // pre state of the db - which is used for logging in the messages below + tx, err := api.db.BeginRo(ctx) + if err != nil { + return common.Hash{}, err + } + + defer tx.Rollback() + + cc, err := api.chainConfig(tx) + if err != nil { + return common.Hash{}, err + } + + txnChainId := txn.GetChainID() + chainId := cc.ChainID + + if chainId.Cmp(txnChainId.ToBig()) != 0 { + return common.Hash{}, fmt.Errorf("invalid chain id, expected: %d got: %d", chainId, *txnChainId) + } + + hash := txn.Hash() + res, err := api.txPool.Add(ctx, &txPoolProto.AddRequest{RlpTxs: [][]byte{encodedTx}}) + if err != nil { + return common.Hash{}, err + } + + if res.Imported[0] != txPoolProto.ImportResult_SUCCESS { + return hash, fmt.Errorf("%s: %s", txPoolProto.ImportResult_name[int32(res.Imported[0])], res.Errors[0]) + } + + return txn.Hash(), nil +} + type BlockSigners struct { Signers []difficultiesKV Diff int diff --git a/turbo/jsonrpc/daemon.go b/turbo/jsonrpc/daemon.go index 9c57c1ed47b..4cb358e1186 100644 --- a/turbo/jsonrpc/daemon.go +++ b/turbo/jsonrpc/daemon.go @@ -36,7 +36,7 @@ func APIList(db kv.RoDB, eth rpchelper.ApiBackend, txPool txpool.TxpoolClient, m var borImpl *BorImpl if bor, ok := engine.(*bor.Bor); ok { - borImpl = NewBorAPI(base, db, bor) // bor (consensus) specific + borImpl = NewBorAPI(base, db, bor, txpool) // bor (consensus) specific } otsImpl := NewOtterscanAPI(base, db, cfg.OtsMaxPageSize) From b6b5a385c7b876411c462e14df4fa440301e8d9a Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Mon, 18 Sep 2023 13:13:22 +0530 Subject: [PATCH 02/22] addressed comments --- core/state/intra_block_state.go | 6 +++++- turbo/jsonrpc/bor_snapshot.go | 21 ++++++++++----------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/core/state/intra_block_state.go b/core/state/intra_block_state.go index 8f15a0d6cd3..fa5775e79d7 100644 --- a/core/state/intra_block_state.go +++ b/core/state/intra_block_state.go @@ -854,7 +854,11 @@ func (sdb *IntraBlockState) ValidateKnownAccounts(knownAccounts types.KnownAccou case v.IsStorage(): for slot, value := range v.Storage { slot := slot - tempByte, _ := sdb.stateReader.ReadAccountStorage(k, tempAccount.Incarnation, &slot) + tempByte, err := sdb.stateReader.ReadAccountStorage(k, tempAccount.Incarnation, &slot) + if err != nil { + return fmt.Errorf("error reading account storage at: %v slot: %v", k, slot) + } + actualValue := libcommon.BytesToHash(common.LeftPadBytes(tempByte, 32)) if value != actualValue { return fmt.Errorf("invalid slot value at address: %v slot: %v value: %v actual value: %v", k, slot, value, actualValue) diff --git a/turbo/jsonrpc/bor_snapshot.go b/turbo/jsonrpc/bor_snapshot.go index b2343b67309..f9d09ad8781 100644 --- a/turbo/jsonrpc/bor_snapshot.go +++ b/turbo/jsonrpc/bor_snapshot.go @@ -263,18 +263,24 @@ func (api *BorImpl) SendRawTransactionConditional(ctx context.Context, encodedTx return common.Hash{}, err } - txTemp, err := api.db.BeginRo(ctx) + // this has been moved to prior to adding of transactions to capture the + // pre state of the db - which is used for logging in the messages below + tx, err := api.db.BeginRo(ctx) if err != nil { return common.Hash{}, err } - defer txTemp.Rollback() + defer tx.Rollback() - currentHeader := rawdb.ReadCurrentHeader(txTemp) + currentHeader := rawdb.ReadCurrentHeader(tx) + // Ensure we have an actually valid block + if currentHeader == nil { + return common.Hash{}, errUnknownBlock + } tempBlockNumber := rpc.BlockNumber(currentHeader.Number.Int64()) tempBlockorHash := rpc.BlockNumberOrHash{BlockNumber: &tempBlockNumber} - readerTemp, err := rpchelper.CreateStateReader(ctx, txTemp, tempBlockorHash, 0, api.filters, api.stateCache, api.historyV3(txTemp), "") + readerTemp, err := rpchelper.CreateStateReader(ctx, tx, tempBlockorHash, 0, api.filters, api.stateCache, api.historyV3(tx), "") if err != nil { return common.Hash{}, err } @@ -313,13 +319,6 @@ func (api *BorImpl) SendRawTransactionConditional(ctx context.Context, encodedTx return common.Hash{}, errors.New("only replay-protected (EIP-155) transactions allowed over RPC") } - // this has been moved to prior to adding of transactions to capture the - // pre state of the db - which is used for logging in the messages below - tx, err := api.db.BeginRo(ctx) - if err != nil { - return common.Hash{}, err - } - defer tx.Rollback() cc, err := api.chainConfig(tx) From 74e53a4699056522ba0d635d8c47f6a1e2899c90 Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Tue, 19 Sep 2023 15:12:10 +0530 Subject: [PATCH 03/22] removed duplicate line --- turbo/jsonrpc/bor_snapshot.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/turbo/jsonrpc/bor_snapshot.go b/turbo/jsonrpc/bor_snapshot.go index f9d09ad8781..dbb01e06751 100644 --- a/turbo/jsonrpc/bor_snapshot.go +++ b/turbo/jsonrpc/bor_snapshot.go @@ -319,8 +319,6 @@ func (api *BorImpl) SendRawTransactionConditional(ctx context.Context, encodedTx return common.Hash{}, errors.New("only replay-protected (EIP-155) transactions allowed over RPC") } - defer tx.Rollback() - cc, err := api.chainConfig(tx) if err != nil { return common.Hash{}, err From d257b26780971393f208cab13bcb5e982e3222a5 Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Tue, 3 Oct 2023 08:59:37 +0530 Subject: [PATCH 04/22] fix go.mod & go.sum --- go.mod | 2 -- go.sum | 2 -- 2 files changed, 4 deletions(-) diff --git a/go.mod b/go.mod index 18b499476b8..7b051e4b162 100644 --- a/go.mod +++ b/go.mod @@ -275,5 +275,3 @@ require ( replace github.com/tendermint/tendermint => github.com/bnb-chain/tendermint v0.31.12 replace github.com/VictoriaMetrics/metrics => github.com/ledgerwatch/victoria-metrics v0.0.4 - -replace github.com/ledgerwatch/erigon-lib => github.com/pratikspatil024/erigon-lib v0.0.0-20230914110124-2768437ea2d4 diff --git a/go.sum b/go.sum index cc3186133f2..c54b61c31ec 100644 --- a/go.sum +++ b/go.sum @@ -699,8 +699,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/pratikspatil024/erigon-lib v0.0.0-20230914110124-2768437ea2d4 h1:QlGItRoGzXyVIied7fsN0RaanngktpGqDmLbT8J2KEA= -github.com/pratikspatil024/erigon-lib v0.0.0-20230914110124-2768437ea2d4/go.mod h1:DRy/PNMCuzakVJFE42OR9F3SARTLxlfK7R4JwP5u/5k= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= From 6c446e856f9c796b26af9ee9efcbc2bcc9e530eb Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Tue, 3 Oct 2023 09:02:12 +0530 Subject: [PATCH 05/22] added func HexToRefHash() in erigon-lib --- erigon-lib/common/hash.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/erigon-lib/common/hash.go b/erigon-lib/common/hash.go index a2353a4e6b9..90e3316fce0 100644 --- a/erigon-lib/common/hash.go +++ b/erigon-lib/common/hash.go @@ -61,6 +61,12 @@ func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) } // If b is larger than len(h), b will be cropped from the left. func HexToHash(s string) Hash { return BytesToHash(hexutility.FromHex(s)) } +func HexToRefHash(s string) *Hash { + v := BytesToHash(FromHex(s)) + + return &v +} + // Bytes gets the byte representation of the underlying hash. func (h Hash) Bytes() []byte { return h[:] } From 0a45d296bf689413c436d15836e65d16926c8094 Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Tue, 3 Oct 2023 09:50:44 +0530 Subject: [PATCH 06/22] small fix --- turbo/jsonrpc/bor_api.go | 7 ++++--- turbo/jsonrpc/daemon.go | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/turbo/jsonrpc/bor_api.go b/turbo/jsonrpc/bor_api.go index 238bc3db10d..ccb59682707 100644 --- a/turbo/jsonrpc/bor_api.go +++ b/turbo/jsonrpc/bor_api.go @@ -5,6 +5,7 @@ import ( "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon/consensus/bor" "github.com/ledgerwatch/erigon/consensus/bor/valset" "github.com/ledgerwatch/erigon/rpc" ) @@ -27,16 +28,16 @@ type BorAPI interface { type BorImpl struct { *BaseAPI db kv.RoDB // the chain db - borDb kv.RoDB // the consensus db + bor *bor.Bor txPool txpool.TxpoolClient } // NewBorAPI returns BorImpl instance -func NewBorAPI(base *BaseAPI, db kv.RoDB, borDb kv.RoDB, txpool txpool.TxpoolClient) *BorImpl { +func NewBorAPI(base *BaseAPI, db kv.RoDB, bor *bor.Bor, txpool txpool.TxpoolClient) *BorImpl { return &BorImpl{ BaseAPI: base, db: db, - borDb: borDb, + bor: bor, txPool: txpool, } } diff --git a/turbo/jsonrpc/daemon.go b/turbo/jsonrpc/daemon.go index 4cb358e1186..178a6f9e567 100644 --- a/turbo/jsonrpc/daemon.go +++ b/turbo/jsonrpc/daemon.go @@ -36,7 +36,7 @@ func APIList(db kv.RoDB, eth rpchelper.ApiBackend, txPool txpool.TxpoolClient, m var borImpl *BorImpl if bor, ok := engine.(*bor.Bor); ok { - borImpl = NewBorAPI(base, db, bor, txpool) // bor (consensus) specific + borImpl = NewBorAPI(base, db, bor, txPool) // bor (consensus) specific } otsImpl := NewOtterscanAPI(base, db, cfg.OtsMaxPageSize) From 7d777224335f6e4b6c2fcec58defad1bc3c3c6b3 Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Tue, 3 Oct 2023 13:35:37 +0530 Subject: [PATCH 07/22] made optionsAA4337 public --- core/types/access_list_tx.go | 4 ++-- core/types/blob_tx_wrapper.go | 4 ++-- core/types/dynamic_fee_tx.go | 4 ++-- core/types/legacy_tx.go | 4 ++-- core/types/transaction.go | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/types/access_list_tx.go b/core/types/access_list_tx.go index d5c1495e8f9..0d1118b3714 100644 --- a/core/types/access_list_tx.go +++ b/core/types/access_list_tx.go @@ -556,9 +556,9 @@ func (tx *AccessListTx) Sender(signer Signer) (libcommon.Address, error) { } func (tx *AccessListTx) PutOptions(options *OptionsAA4337) { - tx.LegacyTx.CommonTx.TransactionMisc.optionsAA4337 = options + tx.OptionsAA4337 = options } func (tx *AccessListTx) GetOptions() *OptionsAA4337 { - return tx.LegacyTx.CommonTx.TransactionMisc.optionsAA4337 + return tx.OptionsAA4337 } diff --git a/core/types/blob_tx_wrapper.go b/core/types/blob_tx_wrapper.go index e580350ea08..09c6de70c6b 100644 --- a/core/types/blob_tx_wrapper.go +++ b/core/types/blob_tx_wrapper.go @@ -383,9 +383,9 @@ func (txw BlobTxWrapper) EncodeRLP(w io.Writer) error { } func (txw BlobTxWrapper) PutOptions(options *OptionsAA4337) { - txw.Tx.DynamicFeeTransaction.CommonTx.TransactionMisc.optionsAA4337 = options + txw.Tx.OptionsAA4337 = options } func (txw BlobTxWrapper) GetOptions() *OptionsAA4337 { - return txw.Tx.DynamicFeeTransaction.CommonTx.TransactionMisc.optionsAA4337 + return txw.Tx.OptionsAA4337 } diff --git a/core/types/dynamic_fee_tx.go b/core/types/dynamic_fee_tx.go index 4f07e1bbf4d..bfc8f11828b 100644 --- a/core/types/dynamic_fee_tx.go +++ b/core/types/dynamic_fee_tx.go @@ -474,11 +474,11 @@ func (tx *DynamicFeeTransaction) Sender(signer Signer) (libcommon.Address, error } func (tx *DynamicFeeTransaction) PutOptions(options *OptionsAA4337) { - tx.CommonTx.TransactionMisc.optionsAA4337 = options + tx.OptionsAA4337 = options } func (tx *DynamicFeeTransaction) GetOptions() *OptionsAA4337 { - return tx.CommonTx.TransactionMisc.optionsAA4337 + return tx.OptionsAA4337 } // NewEIP1559Transaction creates an unsigned eip1559 transaction. diff --git a/core/types/legacy_tx.go b/core/types/legacy_tx.go index daf871102fd..fd48a1e9613 100644 --- a/core/types/legacy_tx.go +++ b/core/types/legacy_tx.go @@ -465,9 +465,9 @@ func (tx *LegacyTx) Sender(signer Signer) (libcommon.Address, error) { } func (tx *LegacyTx) PutOptions(options *OptionsAA4337) { - tx.CommonTx.TransactionMisc.optionsAA4337 = options + tx.OptionsAA4337 = options } func (tx *LegacyTx) GetOptions() *OptionsAA4337 { - return tx.CommonTx.TransactionMisc.optionsAA4337 + return tx.OptionsAA4337 } diff --git a/core/types/transaction.go b/core/types/transaction.go index c29207ede5b..49eab4e5c92 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -106,7 +106,7 @@ type TransactionMisc struct { time time.Time // Time first seen locally (spam avoidance) // knownAccounts (EIP-4337) - optionsAA4337 *OptionsAA4337 + OptionsAA4337 *OptionsAA4337 // caches hash atomic.Value //nolint:structcheck From 8a91beaeacd3309725dd84e8b4c8cf29b3af6628 Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Tue, 3 Oct 2023 13:48:17 +0530 Subject: [PATCH 08/22] added check to check nil account data --- core/state/intra_block_state.go | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/core/state/intra_block_state.go b/core/state/intra_block_state.go index fa5775e79d7..2a8ea5694d9 100644 --- a/core/state/intra_block_state.go +++ b/core/state/intra_block_state.go @@ -852,17 +852,21 @@ func (sdb *IntraBlockState) ValidateKnownAccounts(knownAccounts types.KnownAccou return fmt.Errorf("Storage Trie is nil for: %v", k) } case v.IsStorage(): - for slot, value := range v.Storage { - slot := slot - tempByte, err := sdb.stateReader.ReadAccountStorage(k, tempAccount.Incarnation, &slot) - if err != nil { - return fmt.Errorf("error reading account storage at: %v slot: %v", k, slot) - } - - actualValue := libcommon.BytesToHash(common.LeftPadBytes(tempByte, 32)) - if value != actualValue { - return fmt.Errorf("invalid slot value at address: %v slot: %v value: %v actual value: %v", k, slot, value, actualValue) + if tempAccount != nil { + for slot, value := range v.Storage { + slot := slot + tempByte, err := sdb.stateReader.ReadAccountStorage(k, tempAccount.Incarnation, &slot) + if err != nil { + return fmt.Errorf("error reading account storage at: %v slot: %v", k, slot) + } + + actualValue := libcommon.BytesToHash(common.LeftPadBytes(tempByte, 32)) + if value != actualValue { + return fmt.Errorf("invalid slot value at address: %v slot: %v value: %v actual value: %v", k, slot, value, actualValue) + } } + } else { + return fmt.Errorf("Storage Trie is nil for: %v", k) } default: return fmt.Errorf("impossible to validate known accounts: %v", k) From cc8ddac8b6556c05b9380b260f63e9c489f0baf6 Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Tue, 3 Oct 2023 13:56:37 +0530 Subject: [PATCH 09/22] renamed OptionsAA4337 to TransactionConditions --- core/types/access_list_tx.go | 8 ++++---- core/types/blob_tx_wrapper.go | 8 ++++---- core/types/dynamic_fee_tx.go | 8 ++++---- core/types/legacy_tx.go | 8 ++++---- core/types/transaction.go | 6 +++--- core/types/transaction_conditional.go | 2 +- turbo/jsonrpc/bor_snapshot.go | 2 +- 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/core/types/access_list_tx.go b/core/types/access_list_tx.go index 0d1118b3714..1d422add86d 100644 --- a/core/types/access_list_tx.go +++ b/core/types/access_list_tx.go @@ -555,10 +555,10 @@ func (tx *AccessListTx) Sender(signer Signer) (libcommon.Address, error) { return addr, nil } -func (tx *AccessListTx) PutOptions(options *OptionsAA4337) { - tx.OptionsAA4337 = options +func (tx *AccessListTx) PutOptions(options *TransactionConditions) { + tx.TransactionConditions = options } -func (tx *AccessListTx) GetOptions() *OptionsAA4337 { - return tx.OptionsAA4337 +func (tx *AccessListTx) GetOptions() *TransactionConditions { + return tx.TransactionConditions } diff --git a/core/types/blob_tx_wrapper.go b/core/types/blob_tx_wrapper.go index 09c6de70c6b..6b59f5d0b34 100644 --- a/core/types/blob_tx_wrapper.go +++ b/core/types/blob_tx_wrapper.go @@ -382,10 +382,10 @@ func (txw BlobTxWrapper) EncodeRLP(w io.Writer) error { return txw.Tx.EncodeRLP(w) } -func (txw BlobTxWrapper) PutOptions(options *OptionsAA4337) { - txw.Tx.OptionsAA4337 = options +func (txw BlobTxWrapper) PutOptions(options *TransactionConditions) { + txw.Tx.TransactionConditions = options } -func (txw BlobTxWrapper) GetOptions() *OptionsAA4337 { - return txw.Tx.OptionsAA4337 +func (txw BlobTxWrapper) GetOptions() *TransactionConditions { + return txw.Tx.TransactionConditions } diff --git a/core/types/dynamic_fee_tx.go b/core/types/dynamic_fee_tx.go index bfc8f11828b..37a1db91fee 100644 --- a/core/types/dynamic_fee_tx.go +++ b/core/types/dynamic_fee_tx.go @@ -473,12 +473,12 @@ func (tx *DynamicFeeTransaction) Sender(signer Signer) (libcommon.Address, error return addr, nil } -func (tx *DynamicFeeTransaction) PutOptions(options *OptionsAA4337) { - tx.OptionsAA4337 = options +func (tx *DynamicFeeTransaction) PutOptions(options *TransactionConditions) { + tx.TransactionConditions = options } -func (tx *DynamicFeeTransaction) GetOptions() *OptionsAA4337 { - return tx.OptionsAA4337 +func (tx *DynamicFeeTransaction) GetOptions() *TransactionConditions { + return tx.TransactionConditions } // NewEIP1559Transaction creates an unsigned eip1559 transaction. diff --git a/core/types/legacy_tx.go b/core/types/legacy_tx.go index fd48a1e9613..89c2e51c4d6 100644 --- a/core/types/legacy_tx.go +++ b/core/types/legacy_tx.go @@ -464,10 +464,10 @@ func (tx *LegacyTx) Sender(signer Signer) (libcommon.Address, error) { return addr, nil } -func (tx *LegacyTx) PutOptions(options *OptionsAA4337) { - tx.OptionsAA4337 = options +func (tx *LegacyTx) PutOptions(options *TransactionConditions) { + tx.TransactionConditions = options } -func (tx *LegacyTx) GetOptions() *OptionsAA4337 { - return tx.OptionsAA4337 +func (tx *LegacyTx) GetOptions() *TransactionConditions { + return tx.TransactionConditions } diff --git a/core/types/transaction.go b/core/types/transaction.go index 49eab4e5c92..437ba01322d 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -96,8 +96,8 @@ type Transaction interface { SetSender(libcommon.Address) IsContractDeploy() bool Unwrap() Transaction // If this is a network wrapper, returns the unwrapped tx. Otherwise returns itself. - PutOptions(options *OptionsAA4337) - GetOptions() *OptionsAA4337 + PutOptions(options *TransactionConditions) + GetOptions() *TransactionConditions } // TransactionMisc is collection of miscelaneous fields for transaction that is supposed to be embedded into concrete @@ -106,7 +106,7 @@ type TransactionMisc struct { time time.Time // Time first seen locally (spam avoidance) // knownAccounts (EIP-4337) - OptionsAA4337 *OptionsAA4337 + TransactionConditions *TransactionConditions // caches hash atomic.Value //nolint:structcheck diff --git a/core/types/transaction_conditional.go b/core/types/transaction_conditional.go index e6393c6319c..c95b6021e5a 100644 --- a/core/types/transaction_conditional.go +++ b/core/types/transaction_conditional.go @@ -128,7 +128,7 @@ func InsertKnownAccounts[T libcommon.Hash | map[libcommon.Hash]libcommon.Hash](a } } -type OptionsAA4337 struct { +type TransactionConditions struct { KnownAccounts KnownAccounts `json:"knownAccounts"` BlockNumberMin *big.Int `json:"blockNumberMin"` BlockNumberMax *big.Int `json:"blockNumberMax"` diff --git a/turbo/jsonrpc/bor_snapshot.go b/turbo/jsonrpc/bor_snapshot.go index dbb01e06751..4ca03a8296e 100644 --- a/turbo/jsonrpc/bor_snapshot.go +++ b/turbo/jsonrpc/bor_snapshot.go @@ -257,7 +257,7 @@ func (api *BorImpl) GetVoteOnHash(ctx context.Context, starBlockNr uint64, endBl // SendRawTransactionConditional will add the signed transaction to the transaction pool. // The sender/bundler is responsible for signing the transaction -func (api *BorImpl) SendRawTransactionConditional(ctx context.Context, encodedTx hexutility.Bytes, options types.OptionsAA4337) (common.Hash, error) { +func (api *BorImpl) SendRawTransactionConditional(ctx context.Context, encodedTx hexutility.Bytes, options types.TransactionConditions) (common.Hash, error) { txn, err := types.DecodeWrappedTransaction(encodedTx) if err != nil { return common.Hash{}, err From afbfb8ba3de2463c5798c0b2b27ffa1720539d16 Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Tue, 3 Oct 2023 14:00:39 +0530 Subject: [PATCH 10/22] renamed KnownAccounts to KnownAccountStorageConditions and Value to KnownAccountStorageCondition --- core/state/intra_block_state.go | 2 +- core/state/intra_block_state_test.go | 2 +- core/types/transaction_conditional.go | 40 +++++++++++----------- core/types/transaction_conditional_test.go | 4 +-- eth/stagedsync/stage_mining_exec.go | 2 +- turbo/jsonrpc/bor_snapshot.go | 4 +-- 6 files changed, 27 insertions(+), 27 deletions(-) diff --git a/core/state/intra_block_state.go b/core/state/intra_block_state.go index 2a8ea5694d9..c20217ef755 100644 --- a/core/state/intra_block_state.go +++ b/core/state/intra_block_state.go @@ -830,7 +830,7 @@ func (sdb *IntraBlockState) SlotInAccessList(addr libcommon.Address, slot libcom } // ValidateKnownAccounts validates the knownAccounts passed in the options parameter in the conditional transaction (EIP-4337) -func (sdb *IntraBlockState) ValidateKnownAccounts(knownAccounts types.KnownAccounts) error { +func (sdb *IntraBlockState) ValidateKnownAccounts(knownAccounts types.KnownAccountStorageConditions) error { if knownAccounts == nil { return nil } diff --git a/core/state/intra_block_state_test.go b/core/state/intra_block_state_test.go index 27889811014..df99ed964a1 100644 --- a/core/state/intra_block_state_test.go +++ b/core/state/intra_block_state_test.go @@ -353,7 +353,7 @@ func TestTransientStorage(t *testing.T) { func TestValidateKnownAccounts(t *testing.T) { t.Parallel() - knownAccounts := make(types.KnownAccounts) + knownAccounts := make(types.KnownAccountStorageConditions) types.InsertKnownAccounts(knownAccounts, libcommon.HexToAddress("0xadd1add1add1add1add1add1add1add1add1add1"), libcommon.HexToHash("0x2d6f8a898e7dec0bb7a50e8c142be32d7c98c096ff68ed57b9b08280d9aca1ce")) types.InsertKnownAccounts(knownAccounts, libcommon.HexToAddress("0xadd2add2add2add2add2add2add2add2add2add2"), map[libcommon.Hash]libcommon.Hash{ diff --git a/core/types/transaction_conditional.go b/core/types/transaction_conditional.go index c95b6021e5a..7f77fe0627a 100644 --- a/core/types/transaction_conditional.go +++ b/core/types/transaction_conditional.go @@ -27,38 +27,38 @@ import ( "github.com/ledgerwatch/erigon-lib/common/hexutility" ) -type KnownAccounts map[libcommon.Address]*Value +type KnownAccountStorageConditions map[libcommon.Address]*KnownAccountStorageCondition -type Value struct { +type KnownAccountStorageCondition struct { Single *libcommon.Hash Storage map[libcommon.Hash]libcommon.Hash } -func SingleFromHex(hex string) *Value { - return &Value{Single: libcommon.HexToRefHash(hex)} +func SingleFromHex(hex string) *KnownAccountStorageCondition { + return &KnownAccountStorageCondition{Single: libcommon.HexToRefHash(hex)} } -func FromMap(m map[string]string) *Value { +func FromMap(m map[string]string) *KnownAccountStorageCondition { res := map[libcommon.Hash]libcommon.Hash{} for k, v := range m { res[libcommon.HexToHash(k)] = libcommon.HexToHash(v) } - return &Value{Storage: res} + return &KnownAccountStorageCondition{Storage: res} } -func (v *Value) IsSingle() bool { +func (v *KnownAccountStorageCondition) IsSingle() bool { return v != nil && v.Single != nil && !v.IsStorage() } -func (v *Value) IsStorage() bool { +func (v *KnownAccountStorageCondition) IsStorage() bool { return v != nil && v.Storage != nil } const EmptyValue = "{}" -func (v *Value) MarshalJSON() ([]byte, error) { +func (v *KnownAccountStorageCondition) MarshalJSON() ([]byte, error) { if v.IsSingle() { return json.Marshal(v.Single) } @@ -72,7 +72,7 @@ func (v *Value) MarshalJSON() ([]byte, error) { const hashTypeName = "Hash" -func (v *Value) UnmarshalJSON(data []byte) error { +func (v *KnownAccountStorageCondition) UnmarshalJSON(data []byte) error { if len(data) == 0 { return nil } @@ -119,26 +119,26 @@ func (v *Value) UnmarshalJSON(data []byte) error { return nil } -func InsertKnownAccounts[T libcommon.Hash | map[libcommon.Hash]libcommon.Hash](accounts KnownAccounts, k libcommon.Address, v T) { +func InsertKnownAccounts[T libcommon.Hash | map[libcommon.Hash]libcommon.Hash](accounts KnownAccountStorageConditions, k libcommon.Address, v T) { switch typedV := any(v).(type) { case libcommon.Hash: - accounts[k] = &Value{Single: &typedV} + accounts[k] = &KnownAccountStorageCondition{Single: &typedV} case map[libcommon.Hash]libcommon.Hash: - accounts[k] = &Value{Storage: typedV} + accounts[k] = &KnownAccountStorageCondition{Storage: typedV} } } type TransactionConditions struct { - KnownAccounts KnownAccounts `json:"knownAccounts"` - BlockNumberMin *big.Int `json:"blockNumberMin"` - BlockNumberMax *big.Int `json:"blockNumberMax"` - TimestampMin *uint64 `json:"timestampMin"` - TimestampMax *uint64 `json:"timestampMax"` + KnownAccountStorageConditions KnownAccountStorageConditions `json:"knownAccounts"` + BlockNumberMin *big.Int `json:"blockNumberMin"` + BlockNumberMax *big.Int `json:"blockNumberMax"` + TimestampMin *uint64 `json:"timestampMin"` + TimestampMax *uint64 `json:"timestampMax"` } var ErrKnownAccounts = errors.New("an incorrect list of knownAccounts") -func (ka KnownAccounts) ValidateLength() error { +func (ka KnownAccountStorageConditions) ValidateLength() error { if ka == nil { return nil } @@ -155,7 +155,7 @@ func (ka KnownAccounts) ValidateLength() error { } if length >= 1000 { - return fmt.Errorf("number of slots/accounts in KnownAccounts %v exceeds the limit of 1000", length) + return fmt.Errorf("number of slots/accounts in KnownAccountStorageConditions %v exceeds the limit of 1000", length) } return nil diff --git a/core/types/transaction_conditional_test.go b/core/types/transaction_conditional_test.go index 6923e17c284..0c5f63535a8 100644 --- a/core/types/transaction_conditional_test.go +++ b/core/types/transaction_conditional_test.go @@ -13,12 +13,12 @@ func TestKnownAccounts(t *testing.T) { requestRaw := []byte(`{"0xadd1add1add1add1add1add1add1add1add1add1": "0x000000000000000000000000313aadca1750caadc7bcb26ff08175c95dcf8e38", "0xadd2add2add2add2add2add2add2add2add2add2": {"0x0000000000000000000000000000000000000000000000000000000000000aaa": "0x0000000000000000000000000000000000000000000000000000000000000bbb", "0x0000000000000000000000000000000000000000000000000000000000000ccc": "0x0000000000000000000000000000000000000000000000000000000000000ddd"}}`) - accs := &KnownAccounts{} + accs := &KnownAccountStorageConditions{} err := json.Unmarshal(requestRaw, accs) require.NoError(t, err) - expected := &KnownAccounts{ + expected := &KnownAccountStorageConditions{ common.HexToAddress("0xadd1add1add1add1add1add1add1add1add1add1"): SingleFromHex("0x000000000000000000000000313aadca1750caadc7bcb26ff08175c95dcf8e38"), common.HexToAddress("0xadd2add2add2add2add2add2add2add2add2add2"): FromMap(map[string]string{ "0x0000000000000000000000000000000000000000000000000000000000000aaa": "0x0000000000000000000000000000000000000000000000000000000000000bbb", diff --git a/eth/stagedsync/stage_mining_exec.go b/eth/stagedsync/stage_mining_exec.go index 41ed85ffc7e..b264fe82d5e 100644 --- a/eth/stagedsync/stage_mining_exec.go +++ b/eth/stagedsync/stage_mining_exec.go @@ -453,7 +453,7 @@ LOOP: continue } - if err := ibs.ValidateKnownAccounts(options.KnownAccounts); err != nil { + if err := ibs.ValidateKnownAccounts(options.KnownAccountStorageConditions); err != nil { log.Trace("Dropping conditional transaction", "from", from, "hash", txn.Hash(), "reason", err) txs.Pop() diff --git a/turbo/jsonrpc/bor_snapshot.go b/turbo/jsonrpc/bor_snapshot.go index 4ca03a8296e..bb8a6095b0e 100644 --- a/turbo/jsonrpc/bor_snapshot.go +++ b/turbo/jsonrpc/bor_snapshot.go @@ -298,12 +298,12 @@ func (api *BorImpl) SendRawTransactionConditional(ctx context.Context, encodedTx } // check knownAccounts length (number of slots/accounts) should be less than 1000 - if err := options.KnownAccounts.ValidateLength(); err != nil { + if err := options.KnownAccountStorageConditions.ValidateLength(); err != nil { return common.Hash{}, &rpc.KnownAccountsLimitExceededError{Message: "limit exceeded. err: " + err.Error()} } // check knownAccounts - if err := currentState.ValidateKnownAccounts(options.KnownAccounts); err != nil { + if err := currentState.ValidateKnownAccounts(options.KnownAccountStorageConditions); err != nil { return common.Hash{}, &rpc.OptionsValidateError{Message: "storage error. err: " + err.Error()} } From 03260188f6ff9c38ff2ab88201c636be9f3505d7 Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Tue, 3 Oct 2023 14:06:53 +0530 Subject: [PATCH 11/22] renaming of Single/Storage and relevent functions --- core/state/intra_block_state.go | 6 ++-- core/types/transaction_conditional.go | 32 +++++++++++----------- core/types/transaction_conditional_test.go | 4 +-- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/core/state/intra_block_state.go b/core/state/intra_block_state.go index c20217ef755..f961aad999b 100644 --- a/core/state/intra_block_state.go +++ b/core/state/intra_block_state.go @@ -845,15 +845,15 @@ func (sdb *IntraBlockState) ValidateKnownAccounts(knownAccounts types.KnownAccou switch { case v.IsSingle(): if tempAccount != nil { - if *v.Single != tempAccount.Root { - return fmt.Errorf("invalid root hash for: %v root hash: %v actual root hash: %v", k, v.Single, tempAccount.Root) + if *v.StorageRootHash != tempAccount.Root { + return fmt.Errorf("invalid root hash for: %v root hash: %v actual root hash: %v", k, v.StorageRootHash, tempAccount.Root) } } else { return fmt.Errorf("Storage Trie is nil for: %v", k) } case v.IsStorage(): if tempAccount != nil { - for slot, value := range v.Storage { + for slot, value := range v.StorageSlotHashes { slot := slot tempByte, err := sdb.stateReader.ReadAccountStorage(k, tempAccount.Incarnation, &slot) if err != nil { diff --git a/core/types/transaction_conditional.go b/core/types/transaction_conditional.go index 7f77fe0627a..7691047a53d 100644 --- a/core/types/transaction_conditional.go +++ b/core/types/transaction_conditional.go @@ -30,41 +30,41 @@ import ( type KnownAccountStorageConditions map[libcommon.Address]*KnownAccountStorageCondition type KnownAccountStorageCondition struct { - Single *libcommon.Hash - Storage map[libcommon.Hash]libcommon.Hash + StorageRootHash *libcommon.Hash + StorageSlotHashes map[libcommon.Hash]libcommon.Hash } -func SingleFromHex(hex string) *KnownAccountStorageCondition { - return &KnownAccountStorageCondition{Single: libcommon.HexToRefHash(hex)} +func NewKnownAccountStorageConditionWithRootHash(hex string) *KnownAccountStorageCondition { + return &KnownAccountStorageCondition{StorageRootHash: libcommon.HexToRefHash(hex)} } -func FromMap(m map[string]string) *KnownAccountStorageCondition { +func NewKnownAccountStorageConditionWithSlotHashes(m map[string]string) *KnownAccountStorageCondition { res := map[libcommon.Hash]libcommon.Hash{} for k, v := range m { res[libcommon.HexToHash(k)] = libcommon.HexToHash(v) } - return &KnownAccountStorageCondition{Storage: res} + return &KnownAccountStorageCondition{StorageSlotHashes: res} } func (v *KnownAccountStorageCondition) IsSingle() bool { - return v != nil && v.Single != nil && !v.IsStorage() + return v != nil && v.StorageRootHash != nil && !v.IsStorage() } func (v *KnownAccountStorageCondition) IsStorage() bool { - return v != nil && v.Storage != nil + return v != nil && v.StorageSlotHashes != nil } const EmptyValue = "{}" func (v *KnownAccountStorageCondition) MarshalJSON() ([]byte, error) { if v.IsSingle() { - return json.Marshal(v.Single) + return json.Marshal(v.StorageRootHash) } if v.IsStorage() { - return json.Marshal(v.Storage) + return json.Marshal(v.StorageSlotHashes) } return []byte(EmptyValue), nil @@ -82,9 +82,9 @@ func (v *KnownAccountStorageCondition) UnmarshalJSON(data []byte) error { err := json.Unmarshal(data, &m) if err != nil { // single Hash value case - v.Single = new(libcommon.Hash) + v.StorageRootHash = new(libcommon.Hash) - innerErr := json.Unmarshal(data, v.Single) + innerErr := json.Unmarshal(data, v.StorageRootHash) if innerErr != nil { return fmt.Errorf("can't unmarshal to single value with error: %v value %q", innerErr, string(data)) } @@ -114,7 +114,7 @@ func (v *KnownAccountStorageCondition) UnmarshalJSON(data []byte) error { res[kHash] = vHash } - v.Storage = res + v.StorageSlotHashes = res return nil } @@ -122,9 +122,9 @@ func (v *KnownAccountStorageCondition) UnmarshalJSON(data []byte) error { func InsertKnownAccounts[T libcommon.Hash | map[libcommon.Hash]libcommon.Hash](accounts KnownAccountStorageConditions, k libcommon.Address, v T) { switch typedV := any(v).(type) { case libcommon.Hash: - accounts[k] = &KnownAccountStorageCondition{Single: &typedV} + accounts[k] = &KnownAccountStorageCondition{StorageRootHash: &typedV} case map[libcommon.Hash]libcommon.Hash: - accounts[k] = &KnownAccountStorageCondition{Storage: typedV} + accounts[k] = &KnownAccountStorageCondition{StorageSlotHashes: typedV} } } @@ -150,7 +150,7 @@ func (ka KnownAccountStorageConditions) ValidateLength() error { if v.IsSingle() { length += 1 } else { - length += len(v.Storage) + length += len(v.StorageSlotHashes) } } diff --git a/core/types/transaction_conditional_test.go b/core/types/transaction_conditional_test.go index 0c5f63535a8..15627dd5f42 100644 --- a/core/types/transaction_conditional_test.go +++ b/core/types/transaction_conditional_test.go @@ -19,8 +19,8 @@ func TestKnownAccounts(t *testing.T) { require.NoError(t, err) expected := &KnownAccountStorageConditions{ - common.HexToAddress("0xadd1add1add1add1add1add1add1add1add1add1"): SingleFromHex("0x000000000000000000000000313aadca1750caadc7bcb26ff08175c95dcf8e38"), - common.HexToAddress("0xadd2add2add2add2add2add2add2add2add2add2"): FromMap(map[string]string{ + common.HexToAddress("0xadd1add1add1add1add1add1add1add1add1add1"): NewKnownAccountStorageConditionWithRootHash("0x000000000000000000000000313aadca1750caadc7bcb26ff08175c95dcf8e38"), + common.HexToAddress("0xadd2add2add2add2add2add2add2add2add2add2"): NewKnownAccountStorageConditionWithSlotHashes(map[string]string{ "0x0000000000000000000000000000000000000000000000000000000000000aaa": "0x0000000000000000000000000000000000000000000000000000000000000bbb", "0x0000000000000000000000000000000000000000000000000000000000000ccc": "0x0000000000000000000000000000000000000000000000000000000000000ddd", }), From f67a5049c8bd586cae6059a456654604fef05fdd Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Tue, 3 Oct 2023 14:21:47 +0530 Subject: [PATCH 12/22] inlined 2 constants --- core/types/transaction_conditional.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/core/types/transaction_conditional.go b/core/types/transaction_conditional.go index 7691047a53d..7c503e64293 100644 --- a/core/types/transaction_conditional.go +++ b/core/types/transaction_conditional.go @@ -56,8 +56,6 @@ func (v *KnownAccountStorageCondition) IsStorage() bool { return v != nil && v.StorageSlotHashes != nil } -const EmptyValue = "{}" - func (v *KnownAccountStorageCondition) MarshalJSON() ([]byte, error) { if v.IsSingle() { return json.Marshal(v.StorageRootHash) @@ -67,11 +65,9 @@ func (v *KnownAccountStorageCondition) MarshalJSON() ([]byte, error) { return json.Marshal(v.StorageSlotHashes) } - return []byte(EmptyValue), nil + return []byte("{}"), nil } -const hashTypeName = "Hash" - func (v *KnownAccountStorageCondition) UnmarshalJSON(data []byte) error { if len(data) == 0 { return nil @@ -98,7 +94,7 @@ func (v *KnownAccountStorageCondition) UnmarshalJSON(data []byte) error { // check k if it is a Hex value var kHash libcommon.Hash - err = hexutility.UnmarshalFixedText(hashTypeName, []byte(k), kHash[:]) + err = hexutility.UnmarshalFixedText("Hash", []byte(k), kHash[:]) if err != nil { return fmt.Errorf("%w by key: %s with key %q and value %q", ErrKnownAccounts, err, k, string(v)) } From 75f7622a56d1befd02bca4f5596f201aca5d5b7a Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Tue, 3 Oct 2023 14:26:20 +0530 Subject: [PATCH 13/22] moved ErrKnownAccounts to func UnmarshalJSON --- core/types/transaction_conditional.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/types/transaction_conditional.go b/core/types/transaction_conditional.go index 7c503e64293..1d50dc02e1b 100644 --- a/core/types/transaction_conditional.go +++ b/core/types/transaction_conditional.go @@ -69,6 +69,8 @@ func (v *KnownAccountStorageCondition) MarshalJSON() ([]byte, error) { } func (v *KnownAccountStorageCondition) UnmarshalJSON(data []byte) error { + var ErrKnownAccounts = errors.New("an incorrect list of knownAccounts") + if len(data) == 0 { return nil } @@ -132,8 +134,6 @@ type TransactionConditions struct { TimestampMax *uint64 `json:"timestampMax"` } -var ErrKnownAccounts = errors.New("an incorrect list of knownAccounts") - func (ka KnownAccountStorageConditions) ValidateLength() error { if ka == nil { return nil From f6d97dd64bc20fd04523a9732b54530224857e82 Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Tue, 3 Oct 2023 14:32:27 +0530 Subject: [PATCH 14/22] separate length calculation and validation logic of KnownAccountStorageConditions --- core/types/transaction_conditional.go | 10 +++------- turbo/jsonrpc/bor_snapshot.go | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/core/types/transaction_conditional.go b/core/types/transaction_conditional.go index 1d50dc02e1b..f842a166e5a 100644 --- a/core/types/transaction_conditional.go +++ b/core/types/transaction_conditional.go @@ -134,9 +134,9 @@ type TransactionConditions struct { TimestampMax *uint64 `json:"timestampMax"` } -func (ka KnownAccountStorageConditions) ValidateLength() error { +func (ka KnownAccountStorageConditions) CountStorageEntries() int { if ka == nil { - return nil + return 0 } length := 0 @@ -150,9 +150,5 @@ func (ka KnownAccountStorageConditions) ValidateLength() error { } } - if length >= 1000 { - return fmt.Errorf("number of slots/accounts in KnownAccountStorageConditions %v exceeds the limit of 1000", length) - } - - return nil + return length } diff --git a/turbo/jsonrpc/bor_snapshot.go b/turbo/jsonrpc/bor_snapshot.go index bb8a6095b0e..dddd45f220e 100644 --- a/turbo/jsonrpc/bor_snapshot.go +++ b/turbo/jsonrpc/bor_snapshot.go @@ -298,7 +298,7 @@ func (api *BorImpl) SendRawTransactionConditional(ctx context.Context, encodedTx } // check knownAccounts length (number of slots/accounts) should be less than 1000 - if err := options.KnownAccountStorageConditions.ValidateLength(); err != nil { + if options.KnownAccountStorageConditions.CountStorageEntries() >= 1000 { return common.Hash{}, &rpc.KnownAccountsLimitExceededError{Message: "limit exceeded. err: " + err.Error()} } From 220acfd5b43c35a98c1368938551d6e10f49c773 Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Tue, 3 Oct 2023 14:43:17 +0530 Subject: [PATCH 15/22] moved errors to a better place --- rpc/types.go | 12 ------------ turbo/jsonrpc/bor_snapshot.go | 20 ++++++++++++++++---- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/rpc/types.go b/rpc/types.go index c8e2813f3fd..58683829c97 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -456,15 +456,3 @@ func (ts *Timestamp) UnmarshalJSON(data []byte) error { return nil } - -type OptionsValidateError struct{ Message string } - -func (e *OptionsValidateError) ErrorCode() int { return -32003 } - -func (e *OptionsValidateError) Error() string { return e.Message } - -type KnownAccountsLimitExceededError struct{ Message string } - -func (e *KnownAccountsLimitExceededError) ErrorCode() int { return -32005 } - -func (e *KnownAccountsLimitExceededError) Error() string { return e.Message } diff --git a/turbo/jsonrpc/bor_snapshot.go b/turbo/jsonrpc/bor_snapshot.go index dddd45f220e..69365b0bc23 100644 --- a/turbo/jsonrpc/bor_snapshot.go +++ b/turbo/jsonrpc/bor_snapshot.go @@ -289,22 +289,22 @@ func (api *BorImpl) SendRawTransactionConditional(ctx context.Context, encodedTx // check block number range if err := currentHeader.ValidateBlockNumberOptions4337(options.BlockNumberMin, options.BlockNumberMax); err != nil { - return common.Hash{}, &rpc.OptionsValidateError{Message: "out of block range. err: " + err.Error()} + return common.Hash{}, &TransactionConditionsValidationError{Message: "out of block range. err: " + err.Error()} } // check timestamp range if err := currentHeader.ValidateTimestampOptions4337(options.TimestampMin, options.TimestampMax); err != nil { - return common.Hash{}, &rpc.OptionsValidateError{Message: "out of time range. err: " + err.Error()} + return common.Hash{}, &TransactionConditionsValidationError{Message: "out of time range. err: " + err.Error()} } // check knownAccounts length (number of slots/accounts) should be less than 1000 if options.KnownAccountStorageConditions.CountStorageEntries() >= 1000 { - return common.Hash{}, &rpc.KnownAccountsLimitExceededError{Message: "limit exceeded. err: " + err.Error()} + return common.Hash{}, &KnownAccountsLimitExceededError{Message: "limit exceeded. err: " + err.Error()} } // check knownAccounts if err := currentState.ValidateKnownAccounts(options.KnownAccountStorageConditions); err != nil { - return common.Hash{}, &rpc.OptionsValidateError{Message: "storage error. err: " + err.Error()} + return common.Hash{}, &TransactionConditionsValidationError{Message: "storage error. err: " + err.Error()} } // put options data in Tx, to use it later while block building @@ -632,3 +632,15 @@ func loadSnapshot(api *BorImpl, db kv.Tx, borDb kv.Tx, hash common.Hash) (*Snaps return snap, nil } + +type TransactionConditionsValidationError struct{ Message string } + +func (e *TransactionConditionsValidationError) ErrorCode() int { return -32003 } + +func (e *TransactionConditionsValidationError) Error() string { return e.Message } + +type KnownAccountsLimitExceededError struct{ Message string } + +func (e *KnownAccountsLimitExceededError) ErrorCode() int { return -32005 } + +func (e *KnownAccountsLimitExceededError) Error() string { return e.Message } From 3d28edd8addf373407548c449f16e2f87ecf9a3e Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Tue, 3 Oct 2023 16:48:29 +0530 Subject: [PATCH 16/22] moved transaction_conditional to erigon/types --- core/state/intra_block_state.go | 2 +- core/types/access_list_tx.go | 4 ++-- core/types/blob_tx_wrapper.go | 4 ++-- core/types/dynamic_fee_tx.go | 4 ++-- core/types/legacy_tx.go | 4 ++-- core/types/transaction.go | 6 +++--- {core => erigon-lib}/types/transaction_conditional.go | 0 {core => erigon-lib}/types/transaction_conditional_test.go | 0 turbo/jsonrpc/bor_snapshot.go | 3 ++- 9 files changed, 14 insertions(+), 13 deletions(-) rename {core => erigon-lib}/types/transaction_conditional.go (100%) rename {core => erigon-lib}/types/transaction_conditional_test.go (100%) diff --git a/core/state/intra_block_state.go b/core/state/intra_block_state.go index f961aad999b..b9294b73a6f 100644 --- a/core/state/intra_block_state.go +++ b/core/state/intra_block_state.go @@ -830,7 +830,7 @@ func (sdb *IntraBlockState) SlotInAccessList(addr libcommon.Address, slot libcom } // ValidateKnownAccounts validates the knownAccounts passed in the options parameter in the conditional transaction (EIP-4337) -func (sdb *IntraBlockState) ValidateKnownAccounts(knownAccounts types.KnownAccountStorageConditions) error { +func (sdb *IntraBlockState) ValidateKnownAccounts(knownAccounts types2.KnownAccountStorageConditions) error { if knownAccounts == nil { return nil } diff --git a/core/types/access_list_tx.go b/core/types/access_list_tx.go index 1d422add86d..c03e6b84b25 100644 --- a/core/types/access_list_tx.go +++ b/core/types/access_list_tx.go @@ -555,10 +555,10 @@ func (tx *AccessListTx) Sender(signer Signer) (libcommon.Address, error) { return addr, nil } -func (tx *AccessListTx) PutOptions(options *TransactionConditions) { +func (tx *AccessListTx) PutOptions(options *types2.TransactionConditions) { tx.TransactionConditions = options } -func (tx *AccessListTx) GetOptions() *TransactionConditions { +func (tx *AccessListTx) GetOptions() *types2.TransactionConditions { return tx.TransactionConditions } diff --git a/core/types/blob_tx_wrapper.go b/core/types/blob_tx_wrapper.go index 6b59f5d0b34..03f93340a95 100644 --- a/core/types/blob_tx_wrapper.go +++ b/core/types/blob_tx_wrapper.go @@ -382,10 +382,10 @@ func (txw BlobTxWrapper) EncodeRLP(w io.Writer) error { return txw.Tx.EncodeRLP(w) } -func (txw BlobTxWrapper) PutOptions(options *TransactionConditions) { +func (txw BlobTxWrapper) PutOptions(options *types2.TransactionConditions) { txw.Tx.TransactionConditions = options } -func (txw BlobTxWrapper) GetOptions() *TransactionConditions { +func (txw BlobTxWrapper) GetOptions() *types2.TransactionConditions { return txw.Tx.TransactionConditions } diff --git a/core/types/dynamic_fee_tx.go b/core/types/dynamic_fee_tx.go index 37a1db91fee..cf58807142e 100644 --- a/core/types/dynamic_fee_tx.go +++ b/core/types/dynamic_fee_tx.go @@ -473,11 +473,11 @@ func (tx *DynamicFeeTransaction) Sender(signer Signer) (libcommon.Address, error return addr, nil } -func (tx *DynamicFeeTransaction) PutOptions(options *TransactionConditions) { +func (tx *DynamicFeeTransaction) PutOptions(options *types2.TransactionConditions) { tx.TransactionConditions = options } -func (tx *DynamicFeeTransaction) GetOptions() *TransactionConditions { +func (tx *DynamicFeeTransaction) GetOptions() *types2.TransactionConditions { return tx.TransactionConditions } diff --git a/core/types/legacy_tx.go b/core/types/legacy_tx.go index 89c2e51c4d6..ecbd98ec58d 100644 --- a/core/types/legacy_tx.go +++ b/core/types/legacy_tx.go @@ -464,10 +464,10 @@ func (tx *LegacyTx) Sender(signer Signer) (libcommon.Address, error) { return addr, nil } -func (tx *LegacyTx) PutOptions(options *TransactionConditions) { +func (tx *LegacyTx) PutOptions(options *types2.TransactionConditions) { tx.TransactionConditions = options } -func (tx *LegacyTx) GetOptions() *TransactionConditions { +func (tx *LegacyTx) GetOptions() *types2.TransactionConditions { return tx.TransactionConditions } diff --git a/core/types/transaction.go b/core/types/transaction.go index 437ba01322d..0c8ac3db423 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -96,8 +96,8 @@ type Transaction interface { SetSender(libcommon.Address) IsContractDeploy() bool Unwrap() Transaction // If this is a network wrapper, returns the unwrapped tx. Otherwise returns itself. - PutOptions(options *TransactionConditions) - GetOptions() *TransactionConditions + PutOptions(options *types2.TransactionConditions) + GetOptions() *types2.TransactionConditions } // TransactionMisc is collection of miscelaneous fields for transaction that is supposed to be embedded into concrete @@ -106,7 +106,7 @@ type TransactionMisc struct { time time.Time // Time first seen locally (spam avoidance) // knownAccounts (EIP-4337) - TransactionConditions *TransactionConditions + TransactionConditions *types2.TransactionConditions // caches hash atomic.Value //nolint:structcheck diff --git a/core/types/transaction_conditional.go b/erigon-lib/types/transaction_conditional.go similarity index 100% rename from core/types/transaction_conditional.go rename to erigon-lib/types/transaction_conditional.go diff --git a/core/types/transaction_conditional_test.go b/erigon-lib/types/transaction_conditional_test.go similarity index 100% rename from core/types/transaction_conditional_test.go rename to erigon-lib/types/transaction_conditional_test.go diff --git a/turbo/jsonrpc/bor_snapshot.go b/turbo/jsonrpc/bor_snapshot.go index 69365b0bc23..f3dcb9ce1ad 100644 --- a/turbo/jsonrpc/bor_snapshot.go +++ b/turbo/jsonrpc/bor_snapshot.go @@ -11,6 +11,7 @@ import ( "github.com/ledgerwatch/erigon-lib/common/hexutility" txPoolProto "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" "github.com/ledgerwatch/erigon-lib/kv" + types2 "github.com/ledgerwatch/erigon-lib/types" "github.com/ledgerwatch/log/v3" "github.com/ledgerwatch/erigon/consensus" @@ -257,7 +258,7 @@ func (api *BorImpl) GetVoteOnHash(ctx context.Context, starBlockNr uint64, endBl // SendRawTransactionConditional will add the signed transaction to the transaction pool. // The sender/bundler is responsible for signing the transaction -func (api *BorImpl) SendRawTransactionConditional(ctx context.Context, encodedTx hexutility.Bytes, options types.TransactionConditions) (common.Hash, error) { +func (api *BorImpl) SendRawTransactionConditional(ctx context.Context, encodedTx hexutility.Bytes, options types2.TransactionConditions) (common.Hash, error) { txn, err := types.DecodeWrappedTransaction(encodedTx) if err != nil { return common.Hash{}, err From cc63de0c1cc00fe8a7978512bd622a94d14badb0 Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Wed, 4 Oct 2023 08:39:09 +0530 Subject: [PATCH 17/22] generalised validate block range and timestamp range functions --- core/types/block.go | 38 --------------------- core/types/block_test.go | 8 ++--- erigon-lib/types/transaction_conditional.go | 24 +++++++++++++ eth/stagedsync/stage_mining_exec.go | 4 +-- turbo/jsonrpc/bor_snapshot.go | 4 +-- 5 files changed, 32 insertions(+), 46 deletions(-) diff --git a/core/types/block.go b/core/types/block.go index 81e3e4c3e43..c99ec59a9fa 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -611,44 +611,6 @@ func (h *Header) SanityCheck() error { return nil } -// ValidateBlockNumberOptions4337 validates the block range passed in the options parameter in the conditional transaction (EIP-4337) -func (h *Header) ValidateBlockNumberOptions4337(minBlockNumber *big.Int, maxBlockNumber *big.Int) error { - currentBlockNumber := h.Number - - if minBlockNumber != nil { - if currentBlockNumber.Cmp(minBlockNumber) == -1 { - return fmt.Errorf("current block number %v is less than minimum block number: %v", currentBlockNumber, minBlockNumber) - } - } - - if maxBlockNumber != nil { - if currentBlockNumber.Cmp(maxBlockNumber) == 1 { - return fmt.Errorf("current block number %v is greater than maximum block number: %v", currentBlockNumber, maxBlockNumber) - } - } - - return nil -} - -// ValidateBlockNumberOptions4337 validates the timestamp range passed in the options parameter in the conditional transaction (EIP-4337) -func (h *Header) ValidateTimestampOptions4337(minTimestamp *uint64, maxTimestamp *uint64) error { - currentBlockTime := h.Time - - if minTimestamp != nil { - if currentBlockTime < *minTimestamp { - return fmt.Errorf("current block time %v is less than minimum timestamp: %v", currentBlockTime, minTimestamp) - } - } - - if maxTimestamp != nil { - if currentBlockTime > *maxTimestamp { - return fmt.Errorf("current block time %v is greater than maximum timestamp: %v", currentBlockTime, maxTimestamp) - } - } - - return nil -} - // Body is a simple (mutable, non-safe) data container for storing and moving // a block's data contents (transactions and uncles) together. type Body struct { diff --git a/core/types/block_test.go b/core/types/block_test.go index 1d1fc4c0d1b..7fb1efe69c6 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -581,13 +581,13 @@ func TestValidateBlockNumberOptions4337(t *testing.T) { } for _, test := range testsPass { - if err := test.header.ValidateBlockNumberOptions4337(test.minBlockNumber, test.maxBlockNumber); err != nil { + if _, err := types2.BigIntIsWithinRange(test.header.Number, test.minBlockNumber, test.maxBlockNumber); err != nil { t.Fatalf("test number %v should not have failed. err: %v", test.number, err) } } for _, test := range testsFail { - if err := test.header.ValidateBlockNumberOptions4337(test.minBlockNumber, test.maxBlockNumber); err == nil { + if _, err := types2.BigIntIsWithinRange(test.header.Number, test.minBlockNumber, test.maxBlockNumber); err == nil { t.Fatalf("test number %v should have failed. err is nil", test.number) } } @@ -665,13 +665,13 @@ func TestValidateTimestampOptions4337(t *testing.T) { } for _, test := range testsPass { - if err := test.header.ValidateTimestampOptions4337(test.minTimestamp, test.maxTimestamp); err != nil { + if _, err := types2.Uint64IsWithinRange(&test.header.Time, test.minTimestamp, test.maxTimestamp); err != nil { t.Fatalf("test number %v should not have failed. err: %v", test.number, err) } } for _, test := range testsFail { - if err := test.header.ValidateTimestampOptions4337(test.minTimestamp, test.maxTimestamp); err == nil { + if _, err := types2.Uint64IsWithinRange(&test.header.Time, test.minTimestamp, test.maxTimestamp); err == nil { t.Fatalf("test number %v should have failed. err is nil", test.number) } } diff --git a/erigon-lib/types/transaction_conditional.go b/erigon-lib/types/transaction_conditional.go index f842a166e5a..80897620cf7 100644 --- a/erigon-lib/types/transaction_conditional.go +++ b/erigon-lib/types/transaction_conditional.go @@ -152,3 +152,27 @@ func (ka KnownAccountStorageConditions) CountStorageEntries() int { return length } + +func BigIntIsWithinRange(num *big.Int, min *big.Int, max *big.Int) (bool, error) { + if min != nil && num.Cmp(min) == -1 { + return false, fmt.Errorf("provided number %v is less than minimum number: %v", num, min) + } + + if max != nil && num.Cmp(max) == 1 { + return false, fmt.Errorf("provided number %v is greater than maximum number: %v", num, max) + } + + return true, nil +} + +func Uint64IsWithinRange(num *uint64, min *uint64, max *uint64) (bool, error) { + if min != nil && *num < *min { + return false, fmt.Errorf("provided number %v is less than minimum number: %v", num, min) + } + + if max != nil && *num > *max { + return false, fmt.Errorf("provided number %v is greater than maximum number: %v", num, max) + } + + return true, nil +} diff --git a/eth/stagedsync/stage_mining_exec.go b/eth/stagedsync/stage_mining_exec.go index b264fe82d5e..5bedfce9579 100644 --- a/eth/stagedsync/stage_mining_exec.go +++ b/eth/stagedsync/stage_mining_exec.go @@ -439,14 +439,14 @@ LOOP: // not prioritising conditional transaction, yet. if options := txn.GetOptions(); options != nil { - if err := header.ValidateBlockNumberOptions4337(options.BlockNumberMin, options.BlockNumberMax); err != nil { + if _, err := types2.BigIntIsWithinRange(header.Number, options.BlockNumberMin, options.BlockNumberMax); err != nil { log.Trace("Dropping conditional transaction", "from", from, "hash", txn.Hash(), "reason", err) txs.Pop() continue } - if err := header.ValidateTimestampOptions4337(options.TimestampMin, options.TimestampMax); err != nil { + if _, err := types2.Uint64IsWithinRange(&header.Time, options.TimestampMin, options.TimestampMax); err != nil { log.Trace("Dropping conditional transaction", "from", from, "hash", txn.Hash(), "reason", err) txs.Pop() diff --git a/turbo/jsonrpc/bor_snapshot.go b/turbo/jsonrpc/bor_snapshot.go index f3dcb9ce1ad..0261ad79ce1 100644 --- a/turbo/jsonrpc/bor_snapshot.go +++ b/turbo/jsonrpc/bor_snapshot.go @@ -289,12 +289,12 @@ func (api *BorImpl) SendRawTransactionConditional(ctx context.Context, encodedTx currentState := state.New(readerTemp) // check block number range - if err := currentHeader.ValidateBlockNumberOptions4337(options.BlockNumberMin, options.BlockNumberMax); err != nil { + if _, err := types2.BigIntIsWithinRange(currentHeader.Number, options.BlockNumberMin, options.BlockNumberMax); err != nil { return common.Hash{}, &TransactionConditionsValidationError{Message: "out of block range. err: " + err.Error()} } // check timestamp range - if err := currentHeader.ValidateTimestampOptions4337(options.TimestampMin, options.TimestampMax); err != nil { + if _, err := types2.Uint64IsWithinRange(¤tHeader.Time, options.TimestampMin, options.TimestampMax); err != nil { return common.Hash{}, &TransactionConditionsValidationError{Message: "out of time range. err: " + err.Error()} } From 254e2884e95530f69319326449211e2ae30af6c1 Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Wed, 4 Oct 2023 10:22:12 +0530 Subject: [PATCH 18/22] refactored the 4 validation functions into 1 --- erigon-lib/types/transaction_conditional.go | 12 ++++++ eth/stagedsync/stage_mining_exec.go | 42 +++++++++++++-------- turbo/jsonrpc/bor_snapshot.go | 33 ++-------------- 3 files changed, 42 insertions(+), 45 deletions(-) diff --git a/erigon-lib/types/transaction_conditional.go b/erigon-lib/types/transaction_conditional.go index 80897620cf7..76bb70cc00b 100644 --- a/erigon-lib/types/transaction_conditional.go +++ b/erigon-lib/types/transaction_conditional.go @@ -176,3 +176,15 @@ func Uint64IsWithinRange(num *uint64, min *uint64, max *uint64) (bool, error) { return true, nil } + +type TransactionConditionsValidationError struct{ Message string } + +func (e *TransactionConditionsValidationError) ErrorCode() int { return -32003 } + +func (e *TransactionConditionsValidationError) Error() string { return e.Message } + +type KnownAccountsLimitExceededError struct{ Message string } + +func (e *KnownAccountsLimitExceededError) ErrorCode() int { return -32005 } + +func (e *KnownAccountsLimitExceededError) Error() string { return e.Message } diff --git a/eth/stagedsync/stage_mining_exec.go b/eth/stagedsync/stage_mining_exec.go index 5bedfce9579..76909106ecd 100644 --- a/eth/stagedsync/stage_mining_exec.go +++ b/eth/stagedsync/stage_mining_exec.go @@ -439,21 +439,7 @@ LOOP: // not prioritising conditional transaction, yet. if options := txn.GetOptions(); options != nil { - if _, err := types2.BigIntIsWithinRange(header.Number, options.BlockNumberMin, options.BlockNumberMax); err != nil { - log.Trace("Dropping conditional transaction", "from", from, "hash", txn.Hash(), "reason", err) - txs.Pop() - - continue - } - - if _, err := types2.Uint64IsWithinRange(&header.Time, options.TimestampMin, options.TimestampMax); err != nil { - log.Trace("Dropping conditional transaction", "from", from, "hash", txn.Hash(), "reason", err) - txs.Pop() - - continue - } - - if err := ibs.ValidateKnownAccounts(options.KnownAccountStorageConditions); err != nil { + if err := ValidateTransactionConditions(options, header, ibs, false); err != nil { log.Trace("Dropping conditional transaction", "from", from, "hash", txn.Hash(), "reason", err) txs.Pop() @@ -521,3 +507,29 @@ func NotifyPendingLogs(logPrefix string, notifier ChainEventNotifier, logs types } notifier.OnNewPendingLogs(logs) } + +func ValidateTransactionConditions(tc *types2.TransactionConditions, header *types.Header, ibs *state.IntraBlockState, lengthCheckFlag bool) error { + // check block number range + if _, err := types2.BigIntIsWithinRange(header.Number, tc.BlockNumberMin, tc.BlockNumberMax); err != nil { + return &types2.TransactionConditionsValidationError{Message: "out of block range. err: " + err.Error()} + } + + // check timestamp range + if _, err := types2.Uint64IsWithinRange(&header.Time, tc.TimestampMin, tc.TimestampMax); err != nil { + return &types2.TransactionConditionsValidationError{Message: "out of time range. err: " + err.Error()} + } + + // check knownAccounts + if err := ibs.ValidateKnownAccounts(tc.KnownAccountStorageConditions); err != nil { + return &types2.KnownAccountsLimitExceededError{Message: "limit exceeded. err: number of slots/accounts in KnownAccountStorageConditions exceeds the limit of 1000"} + } + + if lengthCheckFlag { + // check knownAccounts length (number of slots/accounts) should be less than 1000 + if tc.KnownAccountStorageConditions.CountStorageEntries() >= 1000 { + return &types2.KnownAccountsLimitExceededError{Message: "limit exceeded. err: number of slots/accounts in KnownAccountStorageConditions exceeds the limit of 1000"} + } + } + + return nil +} diff --git a/turbo/jsonrpc/bor_snapshot.go b/turbo/jsonrpc/bor_snapshot.go index 0261ad79ce1..6068ec59155 100644 --- a/turbo/jsonrpc/bor_snapshot.go +++ b/turbo/jsonrpc/bor_snapshot.go @@ -22,6 +22,7 @@ import ( "github.com/ledgerwatch/erigon/core/types" "github.com/ledgerwatch/erigon/eth/borfinality/whitelist" "github.com/ledgerwatch/erigon/eth/ethconfig" + "github.com/ledgerwatch/erigon/eth/stagedsync" "github.com/ledgerwatch/erigon/rpc" "github.com/ledgerwatch/erigon/turbo/rpchelper" ) @@ -288,24 +289,8 @@ func (api *BorImpl) SendRawTransactionConditional(ctx context.Context, encodedTx currentState := state.New(readerTemp) - // check block number range - if _, err := types2.BigIntIsWithinRange(currentHeader.Number, options.BlockNumberMin, options.BlockNumberMax); err != nil { - return common.Hash{}, &TransactionConditionsValidationError{Message: "out of block range. err: " + err.Error()} - } - - // check timestamp range - if _, err := types2.Uint64IsWithinRange(¤tHeader.Time, options.TimestampMin, options.TimestampMax); err != nil { - return common.Hash{}, &TransactionConditionsValidationError{Message: "out of time range. err: " + err.Error()} - } - - // check knownAccounts length (number of slots/accounts) should be less than 1000 - if options.KnownAccountStorageConditions.CountStorageEntries() >= 1000 { - return common.Hash{}, &KnownAccountsLimitExceededError{Message: "limit exceeded. err: " + err.Error()} - } - - // check knownAccounts - if err := currentState.ValidateKnownAccounts(options.KnownAccountStorageConditions); err != nil { - return common.Hash{}, &TransactionConditionsValidationError{Message: "storage error. err: " + err.Error()} + if err := stagedsync.ValidateTransactionConditions(&options, currentHeader, currentState, true); err != nil { + return common.Hash{}, err } // put options data in Tx, to use it later while block building @@ -633,15 +618,3 @@ func loadSnapshot(api *BorImpl, db kv.Tx, borDb kv.Tx, hash common.Hash) (*Snaps return snap, nil } - -type TransactionConditionsValidationError struct{ Message string } - -func (e *TransactionConditionsValidationError) ErrorCode() int { return -32003 } - -func (e *TransactionConditionsValidationError) Error() string { return e.Message } - -type KnownAccountsLimitExceededError struct{ Message string } - -func (e *KnownAccountsLimitExceededError) ErrorCode() int { return -32005 } - -func (e *KnownAccountsLimitExceededError) Error() string { return e.Message } From c095f93b304c236f5c177dc7fb5f3b9abff4ea7c Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Thu, 5 Oct 2023 08:13:42 +0530 Subject: [PATCH 19/22] made InsertKnownAccounts private for test --- core/state/intra_block_state_test.go | 22 +++++++++++++++------ erigon-lib/types/transaction_conditional.go | 9 --------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/core/state/intra_block_state_test.go b/core/state/intra_block_state_test.go index df99ed964a1..238be0ee047 100644 --- a/core/state/intra_block_state_test.go +++ b/core/state/intra_block_state_test.go @@ -34,6 +34,7 @@ import ( "github.com/holiman/uint256" libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/kv/memdb" + types2 "github.com/ledgerwatch/erigon-lib/types" "github.com/ledgerwatch/erigon/core/types" "github.com/stretchr/testify/require" ) @@ -350,13 +351,22 @@ func TestTransientStorage(t *testing.T) { } } +func insertKnownAccounts[T libcommon.Hash | map[libcommon.Hash]libcommon.Hash](accounts KnownAccountStorageConditions, k libcommon.Address, v T) { + switch typedV := any(v).(type) { + case libcommon.Hash: + accounts[k] = &KnownAccountStorageCondition{StorageRootHash: &typedV} + case map[libcommon.Hash]libcommon.Hash: + accounts[k] = &KnownAccountStorageCondition{StorageSlotHashes: typedV} + } +} + func TestValidateKnownAccounts(t *testing.T) { t.Parallel() - knownAccounts := make(types.KnownAccountStorageConditions) + knownAccounts := make(types2.KnownAccountStorageConditions) - types.InsertKnownAccounts(knownAccounts, libcommon.HexToAddress("0xadd1add1add1add1add1add1add1add1add1add1"), libcommon.HexToHash("0x2d6f8a898e7dec0bb7a50e8c142be32d7c98c096ff68ed57b9b08280d9aca1ce")) - types.InsertKnownAccounts(knownAccounts, libcommon.HexToAddress("0xadd2add2add2add2add2add2add2add2add2add2"), map[libcommon.Hash]libcommon.Hash{ + insertKnownAccounts(knownAccounts, libcommon.HexToAddress("0xadd1add1add1add1add1add1add1add1add1add1"), libcommon.HexToHash("0x2d6f8a898e7dec0bb7a50e8c142be32d7c98c096ff68ed57b9b08280d9aca1ce")) + insertKnownAccounts(knownAccounts, libcommon.HexToAddress("0xadd2add2add2add2add2add2add2add2add2add2"), map[libcommon.Hash]libcommon.Hash{ libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000aaa"): libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000bbb"), libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000ccc"): libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000ddd"), }) @@ -381,7 +391,7 @@ func TestValidateKnownAccounts(t *testing.T) { require.NoError(t, s.state.ValidateKnownAccounts(knownAccounts)) - types.InsertKnownAccounts(knownAccounts, libcommon.HexToAddress("0xadd1add1add1add1add1add1add1add1add1add2"), libcommon.HexToHash("0x2d6f8a898e7dec0bb7a50e8c142be32d7c98c096ff68ed57b9b08280d9aca1cf")) + insertKnownAccounts(knownAccounts, libcommon.HexToAddress("0xadd1add1add1add1add1add1add1add1add1add2"), libcommon.HexToHash("0x2d6f8a898e7dec0bb7a50e8c142be32d7c98c096ff68ed57b9b08280d9aca1cf")) stateobjaddr3 := libcommon.HexToAddress("0xadd1add1add1add1add1add1add1add1add1add2") storageaddr3 := libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000yyy") @@ -394,8 +404,8 @@ func TestValidateKnownAccounts(t *testing.T) { require.Error(t, err, "should have been an error") // correct the previous mistake "0x2d6f8a898e7dec0bb7a50e8c142be32d7c98c096ff68ed57b9b08280d9aca1cf" -> "0x2d6f8a898e7dec0bb7a50e8c142be32d7c98c096ff68ed57b9b08280d9aca1ce" - types.InsertKnownAccounts(knownAccounts, libcommon.HexToAddress("0xadd1add1add1add1add1add1add1add1add1add2"), libcommon.HexToHash("0x2d6f8a898e7dec0bb7a50e8c142be32d7c98c096ff68ed57b9b08280d9aca1ce")) - types.InsertKnownAccounts(knownAccounts, libcommon.HexToAddress("0xadd2add2add2add2add2add2add2add2add2add3"), map[libcommon.Hash]libcommon.Hash{ + insertKnownAccounts(knownAccounts, libcommon.HexToAddress("0xadd1add1add1add1add1add1add1add1add1add2"), libcommon.HexToHash("0x2d6f8a898e7dec0bb7a50e8c142be32d7c98c096ff68ed57b9b08280d9aca1ce")) + insertKnownAccounts(knownAccounts, libcommon.HexToAddress("0xadd2add2add2add2add2add2add2add2add2add3"), map[libcommon.Hash]libcommon.Hash{ libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000aaa"): libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000bbb"), libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000ccc"): libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000ddd"), }) diff --git a/erigon-lib/types/transaction_conditional.go b/erigon-lib/types/transaction_conditional.go index 76bb70cc00b..ce4dce1cdf7 100644 --- a/erigon-lib/types/transaction_conditional.go +++ b/erigon-lib/types/transaction_conditional.go @@ -117,15 +117,6 @@ func (v *KnownAccountStorageCondition) UnmarshalJSON(data []byte) error { return nil } -func InsertKnownAccounts[T libcommon.Hash | map[libcommon.Hash]libcommon.Hash](accounts KnownAccountStorageConditions, k libcommon.Address, v T) { - switch typedV := any(v).(type) { - case libcommon.Hash: - accounts[k] = &KnownAccountStorageCondition{StorageRootHash: &typedV} - case map[libcommon.Hash]libcommon.Hash: - accounts[k] = &KnownAccountStorageCondition{StorageSlotHashes: typedV} - } -} - type TransactionConditions struct { KnownAccountStorageConditions KnownAccountStorageConditions `json:"knownAccounts"` BlockNumberMin *big.Int `json:"blockNumberMin"` From 5ae1dd41745663c0effcb2295ffee037ae1f0a42 Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Thu, 5 Oct 2023 08:21:11 +0530 Subject: [PATCH 20/22] meaningful variable names --- core/state/intra_block_state.go | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/core/state/intra_block_state.go b/core/state/intra_block_state.go index b9294b73a6f..e8c3e3817d3 100644 --- a/core/state/intra_block_state.go +++ b/core/state/intra_block_state.go @@ -835,41 +835,41 @@ func (sdb *IntraBlockState) ValidateKnownAccounts(knownAccounts types2.KnownAcco return nil } - for k, v := range knownAccounts { - tempAccount, err := sdb.stateReader.ReadAccountData(k) + for address, condition := range knownAccounts { + tempAccount, err := sdb.stateReader.ReadAccountData(address) if err != nil { - return fmt.Errorf("error reading account data at: %v", k) + return fmt.Errorf("error reading account data at: %v", address) } // check if the value is hex string or an object switch { - case v.IsSingle(): + case condition.IsSingle(): if tempAccount != nil { - if *v.StorageRootHash != tempAccount.Root { - return fmt.Errorf("invalid root hash for: %v root hash: %v actual root hash: %v", k, v.StorageRootHash, tempAccount.Root) + if *condition.StorageRootHash != tempAccount.Root { + return fmt.Errorf("invalid root hash for: %v root hash: %v actual root hash: %v", address, condition.StorageRootHash, tempAccount.Root) } } else { - return fmt.Errorf("Storage Trie is nil for: %v", k) + return fmt.Errorf("Storage Trie is nil for: %v", address) } - case v.IsStorage(): + case condition.IsStorage(): if tempAccount != nil { - for slot, value := range v.StorageSlotHashes { + for slot, value := range condition.StorageSlotHashes { slot := slot - tempByte, err := sdb.stateReader.ReadAccountStorage(k, tempAccount.Incarnation, &slot) + tempByte, err := sdb.stateReader.ReadAccountStorage(address, tempAccount.Incarnation, &slot) if err != nil { - return fmt.Errorf("error reading account storage at: %v slot: %v", k, slot) + return fmt.Errorf("error reading account storage at: %v slot: %v", address, slot) } actualValue := libcommon.BytesToHash(common.LeftPadBytes(tempByte, 32)) if value != actualValue { - return fmt.Errorf("invalid slot value at address: %v slot: %v value: %v actual value: %v", k, slot, value, actualValue) + return fmt.Errorf("invalid slot value at address: %v slot: %v value: %v actual value: %v", address, slot, value, actualValue) } } } else { - return fmt.Errorf("Storage Trie is nil for: %v", k) + return fmt.Errorf("Storage Trie is nil for: %v", address) } default: - return fmt.Errorf("impossible to validate known accounts: %v", k) + return fmt.Errorf("impossible to validate known accounts: %v", address) } } From a6a66ad1435a154dead5a168ff081b3f2b489fa2 Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Thu, 19 Oct 2023 09:41:52 +0530 Subject: [PATCH 21/22] moved tempAccount check outside switch --- core/state/intra_block_state.go | 36 +++++++++++++++------------------ 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/core/state/intra_block_state.go b/core/state/intra_block_state.go index e8c3e3817d3..db4647172d6 100644 --- a/core/state/intra_block_state.go +++ b/core/state/intra_block_state.go @@ -841,32 +841,28 @@ func (sdb *IntraBlockState) ValidateKnownAccounts(knownAccounts types2.KnownAcco return fmt.Errorf("error reading account data at: %v", address) } + if tempAccount == nil { + return fmt.Errorf("Storage Trie is nil for: %v", address) + } + // check if the value is hex string or an object switch { case condition.IsSingle(): - if tempAccount != nil { - if *condition.StorageRootHash != tempAccount.Root { - return fmt.Errorf("invalid root hash for: %v root hash: %v actual root hash: %v", address, condition.StorageRootHash, tempAccount.Root) - } - } else { - return fmt.Errorf("Storage Trie is nil for: %v", address) + if *condition.StorageRootHash != tempAccount.Root { + return fmt.Errorf("invalid root hash for: %v root hash: %v actual root hash: %v", address, condition.StorageRootHash, tempAccount.Root) } case condition.IsStorage(): - if tempAccount != nil { - for slot, value := range condition.StorageSlotHashes { - slot := slot - tempByte, err := sdb.stateReader.ReadAccountStorage(address, tempAccount.Incarnation, &slot) - if err != nil { - return fmt.Errorf("error reading account storage at: %v slot: %v", address, slot) - } - - actualValue := libcommon.BytesToHash(common.LeftPadBytes(tempByte, 32)) - if value != actualValue { - return fmt.Errorf("invalid slot value at address: %v slot: %v value: %v actual value: %v", address, slot, value, actualValue) - } + for slot, value := range condition.StorageSlotHashes { + slot := slot + tempByte, err := sdb.stateReader.ReadAccountStorage(address, tempAccount.Incarnation, &slot) + if err != nil { + return fmt.Errorf("error reading account storage at: %v slot: %v", address, slot) + } + + actualValue := libcommon.BytesToHash(common.LeftPadBytes(tempByte, 32)) + if value != actualValue { + return fmt.Errorf("invalid slot value at address: %v slot: %v value: %v actual value: %v", address, slot, value, actualValue) } - } else { - return fmt.Errorf("Storage Trie is nil for: %v", address) } default: return fmt.Errorf("impossible to validate known accounts: %v", address) From 3c5c466e318bc70660ae63c6d9ce75f0bc37ad76 Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Thu, 19 Oct 2023 10:42:08 +0530 Subject: [PATCH 22/22] only checking options on the RPC level, removed unwanted code, will continue later --- core/types/access_list_tx.go | 8 ------- core/types/blob_tx_wrapper.go | 8 ------- core/types/dynamic_fee_tx.go | 8 ------- core/types/legacy_tx.go | 8 ------- core/types/transaction.go | 5 ---- eth/stagedsync/stage_mining_exec.go | 36 ----------------------------- turbo/jsonrpc/bor_snapshot.go | 32 ++++++++++++++++++++++--- 7 files changed, 29 insertions(+), 76 deletions(-) diff --git a/core/types/access_list_tx.go b/core/types/access_list_tx.go index c03e6b84b25..562205d3327 100644 --- a/core/types/access_list_tx.go +++ b/core/types/access_list_tx.go @@ -554,11 +554,3 @@ func (tx *AccessListTx) Sender(signer Signer) (libcommon.Address, error) { tx.from.Store(addr) return addr, nil } - -func (tx *AccessListTx) PutOptions(options *types2.TransactionConditions) { - tx.TransactionConditions = options -} - -func (tx *AccessListTx) GetOptions() *types2.TransactionConditions { - return tx.TransactionConditions -} diff --git a/core/types/blob_tx_wrapper.go b/core/types/blob_tx_wrapper.go index 03f93340a95..a078cc351f5 100644 --- a/core/types/blob_tx_wrapper.go +++ b/core/types/blob_tx_wrapper.go @@ -381,11 +381,3 @@ func (txw *BlobTxWrapper) MarshalBinary(w io.Writer) error { func (txw BlobTxWrapper) EncodeRLP(w io.Writer) error { return txw.Tx.EncodeRLP(w) } - -func (txw BlobTxWrapper) PutOptions(options *types2.TransactionConditions) { - txw.Tx.TransactionConditions = options -} - -func (txw BlobTxWrapper) GetOptions() *types2.TransactionConditions { - return txw.Tx.TransactionConditions -} diff --git a/core/types/dynamic_fee_tx.go b/core/types/dynamic_fee_tx.go index cf58807142e..0fa8b865569 100644 --- a/core/types/dynamic_fee_tx.go +++ b/core/types/dynamic_fee_tx.go @@ -473,14 +473,6 @@ func (tx *DynamicFeeTransaction) Sender(signer Signer) (libcommon.Address, error return addr, nil } -func (tx *DynamicFeeTransaction) PutOptions(options *types2.TransactionConditions) { - tx.TransactionConditions = options -} - -func (tx *DynamicFeeTransaction) GetOptions() *types2.TransactionConditions { - return tx.TransactionConditions -} - // NewEIP1559Transaction creates an unsigned eip1559 transaction. func NewEIP1559Transaction(chainID uint256.Int, nonce uint64, to libcommon.Address, amount *uint256.Int, gasLimit uint64, gasPrice *uint256.Int, gasTip *uint256.Int, gasFeeCap *uint256.Int, data []byte) *DynamicFeeTransaction { return &DynamicFeeTransaction{ diff --git a/core/types/legacy_tx.go b/core/types/legacy_tx.go index ecbd98ec58d..92c12f2f964 100644 --- a/core/types/legacy_tx.go +++ b/core/types/legacy_tx.go @@ -463,11 +463,3 @@ func (tx *LegacyTx) Sender(signer Signer) (libcommon.Address, error) { tx.from.Store(addr) return addr, nil } - -func (tx *LegacyTx) PutOptions(options *types2.TransactionConditions) { - tx.TransactionConditions = options -} - -func (tx *LegacyTx) GetOptions() *types2.TransactionConditions { - return tx.TransactionConditions -} diff --git a/core/types/transaction.go b/core/types/transaction.go index 0c8ac3db423..71f6f729aa9 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -96,8 +96,6 @@ type Transaction interface { SetSender(libcommon.Address) IsContractDeploy() bool Unwrap() Transaction // If this is a network wrapper, returns the unwrapped tx. Otherwise returns itself. - PutOptions(options *types2.TransactionConditions) - GetOptions() *types2.TransactionConditions } // TransactionMisc is collection of miscelaneous fields for transaction that is supposed to be embedded into concrete @@ -105,9 +103,6 @@ type Transaction interface { type TransactionMisc struct { time time.Time // Time first seen locally (spam avoidance) - // knownAccounts (EIP-4337) - TransactionConditions *types2.TransactionConditions - // caches hash atomic.Value //nolint:structcheck from atomic.Value diff --git a/eth/stagedsync/stage_mining_exec.go b/eth/stagedsync/stage_mining_exec.go index 76909106ecd..4bb14b2f0b1 100644 --- a/eth/stagedsync/stage_mining_exec.go +++ b/eth/stagedsync/stage_mining_exec.go @@ -437,16 +437,6 @@ LOOP: continue } - // not prioritising conditional transaction, yet. - if options := txn.GetOptions(); options != nil { - if err := ValidateTransactionConditions(options, header, ibs, false); err != nil { - log.Trace("Dropping conditional transaction", "from", from, "hash", txn.Hash(), "reason", err) - txs.Pop() - - continue - } - } - // Check whether the txn is replay protected. If we're not in the EIP155 (Spurious Dragon) hf // phase, start ignoring the sender until we do. if txn.Protected() && !chainConfig.IsSpuriousDragon(header.Number.Uint64()) { @@ -507,29 +497,3 @@ func NotifyPendingLogs(logPrefix string, notifier ChainEventNotifier, logs types } notifier.OnNewPendingLogs(logs) } - -func ValidateTransactionConditions(tc *types2.TransactionConditions, header *types.Header, ibs *state.IntraBlockState, lengthCheckFlag bool) error { - // check block number range - if _, err := types2.BigIntIsWithinRange(header.Number, tc.BlockNumberMin, tc.BlockNumberMax); err != nil { - return &types2.TransactionConditionsValidationError{Message: "out of block range. err: " + err.Error()} - } - - // check timestamp range - if _, err := types2.Uint64IsWithinRange(&header.Time, tc.TimestampMin, tc.TimestampMax); err != nil { - return &types2.TransactionConditionsValidationError{Message: "out of time range. err: " + err.Error()} - } - - // check knownAccounts - if err := ibs.ValidateKnownAccounts(tc.KnownAccountStorageConditions); err != nil { - return &types2.KnownAccountsLimitExceededError{Message: "limit exceeded. err: number of slots/accounts in KnownAccountStorageConditions exceeds the limit of 1000"} - } - - if lengthCheckFlag { - // check knownAccounts length (number of slots/accounts) should be less than 1000 - if tc.KnownAccountStorageConditions.CountStorageEntries() >= 1000 { - return &types2.KnownAccountsLimitExceededError{Message: "limit exceeded. err: number of slots/accounts in KnownAccountStorageConditions exceeds the limit of 1000"} - } - } - - return nil -} diff --git a/turbo/jsonrpc/bor_snapshot.go b/turbo/jsonrpc/bor_snapshot.go index 6068ec59155..577b63fa87b 100644 --- a/turbo/jsonrpc/bor_snapshot.go +++ b/turbo/jsonrpc/bor_snapshot.go @@ -22,7 +22,6 @@ import ( "github.com/ledgerwatch/erigon/core/types" "github.com/ledgerwatch/erigon/eth/borfinality/whitelist" "github.com/ledgerwatch/erigon/eth/ethconfig" - "github.com/ledgerwatch/erigon/eth/stagedsync" "github.com/ledgerwatch/erigon/rpc" "github.com/ledgerwatch/erigon/turbo/rpchelper" ) @@ -257,6 +256,32 @@ func (api *BorImpl) GetVoteOnHash(ctx context.Context, starBlockNr uint64, endBl return true, nil } +func ValidateTransactionConditions(tc *types2.TransactionConditions, header *types.Header, ibs *state.IntraBlockState, lengthCheckFlag bool) error { + // check block number range + if _, err := types2.BigIntIsWithinRange(header.Number, tc.BlockNumberMin, tc.BlockNumberMax); err != nil { + return &types2.TransactionConditionsValidationError{Message: "out of block range. err: " + err.Error()} + } + + // check timestamp range + if _, err := types2.Uint64IsWithinRange(&header.Time, tc.TimestampMin, tc.TimestampMax); err != nil { + return &types2.TransactionConditionsValidationError{Message: "out of time range. err: " + err.Error()} + } + + // check knownAccounts + if err := ibs.ValidateKnownAccounts(tc.KnownAccountStorageConditions); err != nil { + return &types2.KnownAccountsLimitExceededError{Message: "limit exceeded. err: number of slots/accounts in KnownAccountStorageConditions exceeds the limit of 1000"} + } + + if lengthCheckFlag { + // check knownAccounts length (number of slots/accounts) should be less than 1000 + if tc.KnownAccountStorageConditions.CountStorageEntries() >= 1000 { + return &types2.KnownAccountsLimitExceededError{Message: "limit exceeded. err: number of slots/accounts in KnownAccountStorageConditions exceeds the limit of 1000"} + } + } + + return nil +} + // SendRawTransactionConditional will add the signed transaction to the transaction pool. // The sender/bundler is responsible for signing the transaction func (api *BorImpl) SendRawTransactionConditional(ctx context.Context, encodedTx hexutility.Bytes, options types2.TransactionConditions) (common.Hash, error) { @@ -289,12 +314,13 @@ func (api *BorImpl) SendRawTransactionConditional(ctx context.Context, encodedTx currentState := state.New(readerTemp) - if err := stagedsync.ValidateTransactionConditions(&options, currentHeader, currentState, true); err != nil { + if err := ValidateTransactionConditions(&options, currentHeader, currentState, true); err != nil { return common.Hash{}, err } + // TODO // put options data in Tx, to use it later while block building - txn.PutOptions(&options) + // txn.PutOptions(&options) // If the transaction fee cap is already specified, ensure the // fee of the given transaction is _reasonable_.