diff --git a/internal/ethapi/celo_block.go b/internal/ethapi/celo_block.go index 9e4afc5e3d..36f6f24b59 100644 --- a/internal/ethapi/celo_block.go +++ b/internal/ethapi/celo_block.go @@ -3,15 +3,15 @@ package ethapi import ( "context" "fmt" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/params" "math/big" "strings" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" ) @@ -25,12 +25,14 @@ func init() { gasPriceMinimumABI = parsedAbi } +// PopulatePreGingerbreadBlockFields populates the baseFee and gasLimit fields of the block for pre-gingerbread blocks func PopulatePreGingerbreadBlockFields(ctx context.Context, backend CeloBackend, block *types.Block) *types.Block { newHeader := PopulatePreGingerbreadHeaderFields(ctx, backend, block.Header()) block = block.WithSeal(newHeader) return block } +// 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 { @@ -81,6 +83,7 @@ func PopulatePreGingerbreadHeaderFields(ctx context.Context, backend CeloBackend return header } +// retrievePreGingerbreadBlockBaseFee retrieves a base fee at given height from the previous block func retrievePreGingerbreadBlockBaseFee(ctx context.Context, backend CeloBackend, height *big.Int) (*big.Int, error) { if height.Cmp(common.Big0) <= 0 { return common.Big0, nil @@ -101,26 +104,34 @@ func retrievePreGingerbreadBlockBaseFee(ctx context.Context, backend CeloBackend numTxs, numReceipts := len(prevBlock.Transactions()), len(prevReceipts) if numReceipts <= numTxs { - return nil, fmt.Errorf("receipts of block #%d do not contain system logs", height.Int64()) + return nil, fmt.Errorf("receipts of block #%d don't contain system logs", height.Int64()) } systemReceipt := prevReceipts[numTxs] for _, logRecord := range systemReceipt.Logs { + if logRecord.Topics[0] != gasPriceMinimumABI.Events["GasPriceMinimumUpdated"].ID { + continue + } + baseFee, err := parseGasPriceMinimumUpdated(logRecord.Data) - if err == nil { - return baseFee, nil + if err != nil { + return nil, err } + + return baseFee, nil } return nil, fmt.Errorf("gas price minimum updated event is not included in a receipt of block #%d", height.Int64()) } +// parseGasPriceMinimumUpdated parses the data of GasPriceMinimumUpdated event func parseGasPriceMinimumUpdated(data []byte) (*big.Int, error) { values, err := gasPriceMinimumABI.Unpack("GasPriceMinimumUpdated", data) if err != nil { return nil, err } + // safe check, actually Unpack will parse first 32 bytes as a single value if len(values) != 1 { return nil, fmt.Errorf("unexpected format of values in GasPriceMinimumUpdated event") } diff --git a/internal/ethapi/celo_block_test.go b/internal/ethapi/celo_block_test.go new file mode 100644 index 0000000000..07f8ddad2c --- /dev/null +++ b/internal/ethapi/celo_block_test.go @@ -0,0 +1,45 @@ +package ethapi + +import ( + "errors" + "math/big" + "testing" + + "github.com/status-im/keycard-go/hexutils" + "github.com/stretchr/testify/assert" +) + +func Test_parseGasPriceMinimumUpdated(t *testing.T) { + tests := []struct { + name string + data []byte + result *big.Int + err error + }{ + { + name: "should parse gas price successfully", + data: hexutils.HexToBytes("00000000000000000000000000000000000000000000000000000000000f4240"), + result: big.NewInt(1_000_000), + err: nil, + }, + { + name: "should return error if data is not in the expected format", + data: hexutils.HexToBytes("12345"), + result: nil, + err: errors.New("abi: cannot marshal in to go type: length insufficient 3 require 32"), + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + result, err := parseGasPriceMinimumUpdated(test.data) + assert.Equal(t, test.result, result) + + if test.err == nil { + assert.NoError(t, err) + } else { + assert.EqualError(t, err, test.err.Error()) + } + }) + } +} diff --git a/params/celo_config_test.go b/params/celo_config_test.go new file mode 100644 index 0000000000..502ea9549f --- /dev/null +++ b/params/celo_config_test.go @@ -0,0 +1,29 @@ +package params + +import ( + "github.com/stretchr/testify/assert" + "math/big" + "testing" +) + +func TestGasLimits_Limit(t *testing.T) { + subTest := func(t *testing.T, name string, chainId uint64, limits []LimitChange) { + t.Run(name, func(t *testing.T) { + for i, l := range limits { + beginningHeight := l.block + beginningLimit := PreGingerbreadNetworkGasLimits[chainId].Limit(beginningHeight) + assert.Equal(t, l.gasLimit, beginningLimit, "gas limit at block %d (%s)", beginningHeight, name) + + if i < len(limits)-1 { + endHeight := new(big.Int).Sub(limits[i+1].block, big.NewInt(1)) + endLimit := PreGingerbreadNetworkGasLimits[chainId].Limit(endHeight) + assert.Equal(t, l.gasLimit, endLimit, "gas limit at block %d (%s)", endHeight, name) + } + } + }) + } + + subTest(t, "mainnet", CeloMainnetChainID, mainnetGasLimits.changes) + subTest(t, "alfajores", CeloAlfajoresChainID, alfajoresGasLimits.changes) + subTest(t, "baklava", CeloBaklavaChainID, baklavaGasLimits.changes) +}