diff --git a/core/rawdb/celo_accessors.go b/core/rawdb/celo_accessors.go index fb020ba04d..e5e977adca 100644 --- a/core/rawdb/celo_accessors.go +++ b/core/rawdb/celo_accessors.go @@ -5,11 +5,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/rlp" ) var ( - CeloPreGingerbreadFieldsPrefix = []byte("celoPgbFields-") // CeloPreGingerbreadFieldsPrefix + block hash -> PreGingerbreadAdditionalFields + CeloPreGingerbreadBaseFeePrefix = []byte("celoPgbBlockBaseFee-") // CeloPreGingerbreadBlockBaseFeePrefix + block hash -> BaseFee ) type PreGingerbreadFields struct { @@ -17,38 +16,22 @@ type PreGingerbreadFields struct { GasLimit *big.Int } -// preGingerbreadAdditionalFieldsKey calculates a database key for PreGingerbreadAdditionalFields for the given block hash -func preGingerbreadAdditionalFieldsKey(hash common.Hash) []byte { - return append(CeloPreGingerbreadFieldsPrefix, hash[:]...) +// preGingerbreadBlockBaseFeeKey calculates a database key of pre-Gingerbread block BaseFee for the given block hash +func preGingerbreadBlockBaseFeeKey(hash common.Hash) []byte { + return append(CeloPreGingerbreadBaseFeePrefix, hash[:]...) } -// ReadPreGingerbreadAdditionalFields reads PreGingerbreadAdditionalFields from the given database for the given block hash -func ReadPreGingerbreadAdditionalFields(db ethdb.KeyValueReader, blockHash common.Hash) (*PreGingerbreadFields, error) { - data, _ := db.Get(preGingerbreadAdditionalFieldsKey(blockHash)) +// ReadPreGingerbreadBlockBaseFee reads BaseFee of pre-Gingerbread block from the given database for the given block hash +func ReadPreGingerbreadBlockBaseFee(db ethdb.KeyValueReader, blockHash common.Hash) (*big.Int, error) { + data, _ := db.Get(preGingerbreadBlockBaseFeeKey(blockHash)) if len(data) == 0 { return nil, nil } - fields := &PreGingerbreadFields{} - - err := rlp.DecodeBytes(data, fields) - if err != nil { - return nil, err - } - - return fields, nil + return new(big.Int).SetBytes(data), nil } -// WritePreGingerbreadAdditionalFields writes PreGingerbreadAdditionalFields to the given database for the given block hash -func WritePreGingerbreadAdditionalFields(db ethdb.KeyValueWriter, blockHash common.Hash, data *PreGingerbreadFields) error { - rawData, err := rlp.EncodeToBytes(data) - if err != nil { - return err - } - - if err := db.Put(preGingerbreadAdditionalFieldsKey(blockHash), rawData); err != nil { - return err - } - - return nil +// WritePreGingerbreadBlockBaseFee writes BaseFee of pre-Gingerbread block to the given database at the given block hash +func WritePreGingerbreadBlockBaseFee(db ethdb.KeyValueWriter, blockHash common.Hash, baseFee *big.Int) error { + return db.Put(preGingerbreadBlockBaseFeeKey(blockHash), baseFee.Bytes()) } diff --git a/core/rawdb/celo_accessors_test.go b/core/rawdb/celo_accessors_test.go index c53d62ddca..4cf002a02a 100644 --- a/core/rawdb/celo_accessors_test.go +++ b/core/rawdb/celo_accessors_test.go @@ -5,127 +5,28 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/rlp" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) -// TestPreGingerbreadAdditionalFields tests ReadPreGingerbreadAdditionalFields function -func TestPreGingerbreadAdditionalFields(t *testing.T) { - db := NewMemoryDatabase() - - mockData, err := rlp.EncodeToBytes(&PreGingerbreadFields{ - BaseFee: big.NewInt(1000), - GasLimit: big.NewInt(2000), - }) - assert.NoError(t, err) - - type SeedData struct { - hash common.Hash - data []byte - } - - tests := []struct { - name string - seedData []SeedData - hash common.Hash - expectedRes *PreGingerbreadFields - returnsError bool - }{ - { - name: "should return nil if data is not found", - seedData: []SeedData{}, - hash: common.HexToHash("0x1"), - expectedRes: nil, - returnsError: false, - }, - { - name: "should return data", - seedData: []SeedData{ - { - hash: common.HexToHash("0x2"), - data: mockData, - }, - }, - hash: common.HexToHash("0x2"), - expectedRes: &PreGingerbreadFields{ - BaseFee: big.NewInt(1000), - GasLimit: big.NewInt(2000), - }, - returnsError: false, - }, - { - name: "should return error if data is broken", - seedData: []SeedData{ - { - hash: common.HexToHash("0x3"), - data: []byte{0x1, 0x2, 0x3}, - }, - }, - hash: common.HexToHash("0x3"), - expectedRes: nil, - returnsError: true, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - for _, seed := range test.seedData { - err := db.Put(preGingerbreadAdditionalFieldsKey(seed.hash), seed.data) - assert.NoError(t, err) - } - - t.Cleanup(func() { - for _, seed := range test.seedData { - err := db.Delete(preGingerbreadAdditionalFieldsKey(seed.hash)) - assert.NoError(t, err) - } - }) - - res, err := ReadPreGingerbreadAdditionalFields(db, test.hash) - assert.Equal(t, test.expectedRes, res) - - if test.returnsError { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - }) - } -} - -// TestWritePreGingerbreadAdditionalFields tests WritePreGingerbreadAdditionalFields function -func TestWritePreGingerbreadAdditionalFields(t *testing.T) { +// TestReadAndWritePreGingerbreadBlockBaseFee tests reading and writing pre-gingerbread block base fee to database +func TestReadAndWritePreGingerbreadBlockBaseFee(t *testing.T) { db := NewMemoryDatabase() hash := common.HexToHash("0x1") - data := []*PreGingerbreadFields{ - { - BaseFee: big.NewInt(0), - GasLimit: big.NewInt(2000), - }, - { - BaseFee: big.NewInt(3000), - GasLimit: big.NewInt(0), - }, - { - BaseFee: big.NewInt(5000), - GasLimit: big.NewInt(6000), - }, - } + value := big.NewInt(1234) // Make sure that the data is not found - record0, err := ReadPreGingerbreadAdditionalFields(db, hash) - assert.NoError(t, err) + record0, err := ReadPreGingerbreadBlockBaseFee(db, hash) + require.NoError(t, err) assert.Nil(t, record0) - for _, d := range data { - // Write data - err := WritePreGingerbreadAdditionalFields(db, hash, d) - assert.NoError(t, err) + // Write data + err = WritePreGingerbreadBlockBaseFee(db, hash, value) + require.NoError(t, err) - // Read data - record, err := ReadPreGingerbreadAdditionalFields(db, hash) - assert.NoError(t, err) - assert.Equal(t, d, record) - } + // Read data + record, err := ReadPreGingerbreadBlockBaseFee(db, hash) + require.NoError(t, err) + assert.Equal(t, value, record) } diff --git a/internal/ethapi/celo_block.go b/internal/ethapi/celo_block.go index c3f3915a08..072a808255 100644 --- a/internal/ethapi/celo_block.go +++ b/internal/ethapi/celo_block.go @@ -34,44 +34,37 @@ func PopulatePreGingerbreadBlockFields(ctx context.Context, backend CeloBackend, // PopulatePreGingerbreadHeaderFields populates the baseFee and gasLimit fields of the header for pre-gingerbread blocks func PopulatePreGingerbreadHeaderFields(ctx context.Context, backend CeloBackend, header *types.Header) *types.Header { - isGingerbread := backend.ChainConfig().IsGingerbread(header.Number) - if isGingerbread { + // If the block is post-Gingerbread, return the header as is + if backend.ChainConfig().IsGingerbread(header.Number) { return header } var ( - baseFee *big.Int gasLimit *big.Int + baseFee *big.Int ) - fields, err := rawdb.ReadPreGingerbreadAdditionalFields(backend.ChainDb(), header.Hash()) - if fields != nil { - if fields.BaseFee != nil && fields.BaseFee.BitLen() != 0 { - baseFee = fields.BaseFee - } - if fields.GasLimit != nil && fields.GasLimit.BitLen() != 0 { - gasLimit = fields.GasLimit - } - } else { + if chainId := backend.ChainConfig().ChainID; chainId != nil { + gasLimit = retrievePreGingerbreadGasLimit(chainId.Uint64(), header.Number) + } + + baseFee, err := rawdb.ReadPreGingerbreadBlockBaseFee(backend.ChainDb(), header.Hash()) + if baseFee == nil { if err != nil { - log.Debug("failed to read pre-gingerbread fields", "err", err) + log.Debug("failed to load pre-Gingerbread block base fee from database", "block", header.Number.Uint64(), "err", err) } // If the record is not found, get the values and store them baseFee, err = retrievePreGingerbreadBlockBaseFee(ctx, backend, header.Number) if err != nil { - log.Debug("Not adding baseFeePerGas to RPC response, failed to retrieve gas price minimum", "block", header.Number.Uint64(), "err", err) + log.Debug("Not adding to RPC response, failed to retrieve pre-Gingerbread block base fee", "block", header.Number.Uint64(), "err", err) } - gasLimit = retrievePreGingerbreadGasLimit(backend, header.Number) - - if baseFee != nil || gasLimit != nil { - err = rawdb.WritePreGingerbreadAdditionalFields(backend.ChainDb(), header.Hash(), &rawdb.PreGingerbreadFields{ - BaseFee: baseFee, - GasLimit: gasLimit, - }) + // Store the base fee for future use + if baseFee != nil { + err = rawdb.WritePreGingerbreadBlockBaseFee(backend.ChainDb(), header.Hash(), baseFee) if err != nil { - log.Debug("failed to write pre-gingerbread fields", "err", err) + log.Debug("failed to write pre-Gingerbread block base fee", "block", header.Number.Uint64(), "err", err) } } } @@ -87,15 +80,10 @@ func PopulatePreGingerbreadHeaderFields(ctx context.Context, backend CeloBackend } // retrievePreGingerbreadGasLimit retrieves a gas limit at given height from hardcoded values -func retrievePreGingerbreadGasLimit(backend CeloBackend, height *big.Int) *big.Int { - if backend.ChainConfig().ChainID == nil { - log.Debug("Not adding gasLimit to RPC response, unknown network") - return nil - } - - limits, ok := params.PreGingerbreadNetworkGasLimits[backend.ChainConfig().ChainID.Uint64()] +func retrievePreGingerbreadGasLimit(chainId uint64, height *big.Int) *big.Int { + limits, ok := params.PreGingerbreadNetworkGasLimits[chainId] if !ok { - log.Debug("Not adding gasLimit to RPC response, unknown network", "chainID", backend.ChainConfig().ChainID) + log.Debug("Not adding gasLimit to RPC response, unknown network", "chainID", chainId) return nil } diff --git a/internal/ethapi/celo_block_test.go b/internal/ethapi/celo_block_test.go index 5504ab7833..8f0981360a 100644 --- a/internal/ethapi/celo_block_test.go +++ b/internal/ethapi/celo_block_test.go @@ -14,6 +14,7 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/status-im/keycard-go/hexutils" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) // encodeGasPriceMinimumUpdatedEventBody encodes the given gas price minimum value into 32 bytes event data @@ -32,12 +33,12 @@ func TestPopulatePreGingerbreadHeaderFields(t *testing.T) { gingerBreadBeginsAt := big.NewInt(10e5) tests := []struct { - name string - beforeDbData *rawdb.PreGingerbreadFields // data to be stored in the database before the test - afterDbData *rawdb.PreGingerbreadFields // data to be stored in the database after the test - backendBaseFee *big.Int - header *types.Header - expected *types.Header + name string + beforeDbBaseFee *big.Int // BaseFee to be stored in the database before the test + afterDbBaseFee *big.Int // BaseFee to be stored in the database after the test + backendBaseFee *big.Int + header *types.Header + expected *types.Header }{ { name: "should return the same header for post-gingerbread header", @@ -53,66 +54,23 @@ func TestPopulatePreGingerbreadHeaderFields(t *testing.T) { }, }, { - name: "should return the header with baseFee and gasLimit retrieved from the database", - beforeDbData: &rawdb.PreGingerbreadFields{ - BaseFee: big.NewInt(10e4), - GasLimit: big.NewInt(10e5), - }, - afterDbData: &rawdb.PreGingerbreadFields{ - BaseFee: big.NewInt(10e4), - GasLimit: big.NewInt(10e5), - }, + name: "should return the header with baseFee and gasLimit retrieved from the database", + beforeDbBaseFee: big.NewInt(10e4), + afterDbBaseFee: big.NewInt(10e4), header: &types.Header{ Number: big.NewInt(10e3), }, expected: &types.Header{ Number: big.NewInt(10e3), BaseFee: big.NewInt(10e4), - GasLimit: 10e5, - }, - }, - { - name: "should return the header with only baseFee retrieved from the database", - beforeDbData: &rawdb.PreGingerbreadFields{ - BaseFee: big.NewInt(10e6), - }, - afterDbData: &rawdb.PreGingerbreadFields{ - BaseFee: big.NewInt(10e6), - GasLimit: big.NewInt(0), - }, - header: &types.Header{ - Number: big.NewInt(10e3), - }, - expected: &types.Header{ - Number: big.NewInt(10e3), - BaseFee: big.NewInt(10e6), + GasLimit: 1e7, }, }, { - name: "should return the header with only gasLimit retrieved from the database", - beforeDbData: &rawdb.PreGingerbreadFields{ - GasLimit: big.NewInt(10e7), - }, - afterDbData: &rawdb.PreGingerbreadFields{ - BaseFee: big.NewInt(0), - GasLimit: big.NewInt(10e7), - }, - header: &types.Header{ - Number: big.NewInt(10e3), - }, - expected: &types.Header{ - Number: big.NewInt(10e3), - GasLimit: 10e7, - }, - }, - { - name: "should return the header with baseFee and gasLimit retrieved from the backend", - beforeDbData: nil, - afterDbData: &rawdb.PreGingerbreadFields{ - BaseFee: big.NewInt(10e8), - GasLimit: big.NewInt(20e6), - }, - backendBaseFee: big.NewInt(10e8), + name: "should return the header with baseFee and gasLimit retrieved from the backend", + beforeDbBaseFee: nil, + afterDbBaseFee: big.NewInt(10e8), + backendBaseFee: big.NewInt(10e8), header: &types.Header{ Number: big.NewInt(1000), }, @@ -133,10 +91,11 @@ func TestPopulatePreGingerbreadHeaderFields(t *testing.T) { }) // set data into database and backend - if test.beforeDbData != nil { - err := rawdb.WritePreGingerbreadAdditionalFields(backend.ChainDb(), headerHash, test.beforeDbData) - assert.NoError(t, err) + if test.beforeDbBaseFee != nil { + err := rawdb.WritePreGingerbreadBlockBaseFee(backend.ChainDb(), headerHash, test.beforeDbBaseFee) + require.NoError(t, err) } + if test.backendBaseFee != nil { prevHeader := &types.Header{ Number: new(big.Int).Sub(test.header.Number, big.NewInt(1)), @@ -164,13 +123,12 @@ func TestPopulatePreGingerbreadHeaderFields(t *testing.T) { // retrieve baseFee and gasLimit newHeader := PopulatePreGingerbreadHeaderFields(context.Background(), backend, test.header) - assert.Equal(t, test.expected, newHeader) // check db data after the test - dbData, err := rawdb.ReadPreGingerbreadAdditionalFields(backend.ChainDb(), headerHash) - assert.NoError(t, err) - assert.Equal(t, test.afterDbData, dbData) + dbData, err := rawdb.ReadPreGingerbreadBlockBaseFee(backend.ChainDb(), headerHash) + require.NoError(t, err) + assert.Equal(t, test.afterDbBaseFee, dbData) }) } } @@ -181,43 +139,39 @@ func Test_retrievePreGingerbreadGasLimit(t *testing.T) { tests := []struct { name string - chainId *big.Int + chainId uint64 height *big.Int expected *big.Int }{ { - name: "should return nil for undefined chain", - chainId: nil, - height: big.NewInt(10e5), - expected: nil, - }, - { - name: "should return latest gas limit value for celo mainnet", - chainId: big.NewInt(params.CeloMainnetChainID), + name: "should return latest gas limit value for Celo Mainnet", + chainId: params.CeloMainnetChainID, height: big.NewInt(21355415), expected: big.NewInt(32e6), }, { - name: "should return latest gas limit value for celo alfajores", - chainId: big.NewInt(params.CeloAlfajoresChainID), + name: "should return latest gas limit value for Celo Alfajores", + chainId: params.CeloAlfajoresChainID, height: big.NewInt(11143973), expected: big.NewInt(35e6), }, { - name: "should return latest gas limit value for celo baklava", - chainId: big.NewInt(params.CeloBaklavaChainID), + name: "should return latest gas limit value for Celo Baklava", + chainId: params.CeloBaklavaChainID, height: big.NewInt(15158971), expected: big.NewInt(20e6), }, + { + name: "should return nil if chainId is unknown", + chainId: 12345, + height: big.NewInt(10), + expected: nil, + }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - backend := newCeloBackendMock(¶ms.ChainConfig{ - ChainID: test.chainId, - }) - - gasLimit := retrievePreGingerbreadGasLimit(backend, test.height) + gasLimit := retrievePreGingerbreadGasLimit(test.chainId, test.height) assert.Equal(t, test.expected, gasLimit) }) @@ -389,6 +343,8 @@ func Test_retrievePreGingerbreadBlockBaseFee(t *testing.T) { // Test_parseGasPriceMinimumUpdated checks the gas price minimum updated event parsing func Test_parseGasPriceMinimumUpdated(t *testing.T) { + t.Parallel() + tests := []struct { name string data []byte