Skip to content

Commit

Permalink
Code cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
HerbertJordan committed Nov 15, 2024
1 parent 78868e4 commit 52e3300
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 37 deletions.
9 changes: 2 additions & 7 deletions evmcore/dummy_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package evmcore

import (
"encoding/binary"
"math"
"math/big"
"time"
Expand Down Expand Up @@ -135,9 +134,6 @@ func (h *EvmHeader) EthHeader() *types.Header {
if h == nil {
return nil
}
extra := make([]byte, 16)
binary.BigEndian.PutUint64(extra[:8], uint64(h.Time))
binary.BigEndian.PutUint64(extra[8:], uint64(h.Duration))
// NOTE: incomplete conversion
ethHeader := &types.Header{
Number: h.Number,
Expand All @@ -148,7 +144,7 @@ func (h *EvmHeader) EthHeader() *types.Header {
TxHash: h.TxHash,
ParentHash: h.ParentHash,
Time: uint64(h.Time.Unix()),
Extra: extra,
Extra: inter.EncodeExtraData(h.Time.Time(), h.Duration),
BaseFee: h.BaseFee,

Difficulty: new(big.Int),
Expand Down Expand Up @@ -195,7 +191,6 @@ type EvmBlockJson struct {
}

func (h *EvmHeader) ToJson(receipts types.Receipts) *EvmHeaderJson {
ethHeader := h.EthHeader()
enc := &EvmHeaderJson{
Number: (*hexutil.Big)(h.Number),
Miner: h.Coinbase,
Expand All @@ -207,7 +202,7 @@ func (h *EvmHeader) ToJson(receipts types.Receipts) *EvmHeaderJson {
UncleHash: types.EmptyUncleHash,
Time: hexutil.Uint64(h.Time.Unix()),
TimeNano: hexutil.Uint64(h.Time),
Extra: ethHeader.Extra,
Extra: inter.EncodeExtraData(h.Time.Time(), h.Duration),
BaseFee: (*hexutil.Big)(h.BaseFee),
Difficulty: new(hexutil.Big),
PrevRandao: h.PrevRandao,
Expand Down
9 changes: 3 additions & 6 deletions gossip/apply_genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,11 @@ func (s *Store) ApplyGenesis(g genesis.Genesis) (err error) {
if rules.Upgrades.Sonic {
block := s.GetBlock(br.Idx - 1)
if block == nil {
block = &inter.Block{
BaseFee: big.NewInt(0),
}
block = &inter.Block{BaseFee: new(big.Int)}
}
header := &evmcore.EvmHeader{
GasUsed: block.GasUsed,
GasLimit: block.GasLimit,
BaseFee: block.BaseFee,
GasUsed: block.GasUsed,
BaseFee: block.BaseFee,
}
baseFee = gasprice.GetBaseFeeForNextBlock(header, rules.Economy)
duration = time.Duration(br.Time-block.Time) * time.Nanosecond
Expand Down
9 changes: 3 additions & 6 deletions gossip/c_block_callbacks.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ package gossip

import (
"fmt"
"github.com/Fantom-foundation/go-opera/utils/signers/gsignercache"
"math/big"
"sort"
"sync"
"sync/atomic"
"time"

"github.com/Fantom-foundation/go-opera/utils/signers/gsignercache"

"github.com/Fantom-foundation/lachesis-base/hash"
"github.com/Fantom-foundation/lachesis-base/inter/dag"
"github.com/Fantom-foundation/lachesis-base/inter/idx"
Expand Down Expand Up @@ -381,17 +382,13 @@ func consensusCallbackBeginBlockFn(
feed.newLogs.Send(logs)
}

lastBlockTime := evmStateReader.GetHeader(common.Hash{}, uint64(blockCtx.Idx-1)).Time.Time()
thisBlockTime := block.Time.Time()
blockTime := thisBlockTime.Sub(lastBlockTime)

now := time.Now()
blockAge := now.Sub(block.Time.Time())
log.Info("New block",
"index", blockCtx.Idx,
"id", block.Hash(),
"gas_used", evmBlock.GasUsed,
"gas_rate", float64(evmBlock.GasUsed)/blockTime.Seconds(),
"gas_rate", float64(evmBlock.GasUsed)/blockDuration.Seconds(),
"base_fee", evmBlock.BaseFee.String(),
"txs", fmt.Sprintf("%d/%d", len(evmBlock.Transactions), len(skippedTxs)),
"age", utils.PrettyDuration(blockAge),
Expand Down
47 changes: 39 additions & 8 deletions inter/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package inter

import (
"encoding/binary"
"errors"
"math/big"
"slices"
"time"
Expand Down Expand Up @@ -63,10 +64,6 @@ func (b *Block) Hash() common.Hash {

// GetEthereumHeader returns the Ethereum header corresponding to this block.
func (b *Block) GetEthereumHeader() *types.Header {
// TODO: consider condensing the extra data into a single 8-byte field.
extra := make([]byte, 16)
binary.BigEndian.PutUint64(extra[:8], uint64(b.Time)) // < only nano-second part needed
binary.BigEndian.PutUint64(extra[8:], uint64(b.Duration)) // < could be measured in microseconds instead of nanoseconds
return &types.Header{
ParentHash: b.ParentHash,
UncleHash: types.EmptyUncleHash,
Expand All @@ -80,10 +77,13 @@ func (b *Block) GetEthereumHeader() *types.Header {
GasLimit: b.GasLimit,
GasUsed: b.GasUsed,
Time: uint64(b.Time.Time().Unix()),
Extra: extra,
MixDigest: b.PrevRandao,
Nonce: types.BlockNonce{}, // constant 0 in Ethereum
BaseFee: b.BaseFee,
Extra: EncodeExtraData(
b.Time.Time(),
time.Duration(b.Duration)*time.Nanosecond,
),
MixDigest: b.PrevRandao,
Nonce: types.BlockNonce{}, // constant 0 in Ethereum
BaseFee: b.BaseFee,

// Sonic does not have a beacon chain and no withdrawals.
WithdrawalsHash: &types.EmptyWithdrawalsHash,
Expand All @@ -95,6 +95,37 @@ func (b *Block) GetEthereumHeader() *types.Header {
}
}

// EncodeExtraData produces the ExtraData field encoding Sonic-specific data
// in the Ethereum block header. This data includes:
// - the nano-second part of the block's timestamp, for sub-second precision;
// - the duration of the block, in nanoseconds, defined as the time elapsed
// between the predecessor block's timestamp and this block's timestamp.
// This is used for the computation of gas rates to adjust the base fee.
func EncodeExtraData(time time.Time, duration time.Duration) []byte {
if duration < 0 {
duration = 0
}
extra := make([]byte, 12)
binary.BigEndian.PutUint32(extra[:4], uint32(time.Nanosecond()))
binary.BigEndian.PutUint64(extra[4:], uint64(duration.Nanoseconds()))
return extra
}

// DecodeExtraData decodes the ExtraData field encoding Sonic-specific data
// in the Ethereum block header. See EncodeExtraData for details.
func DecodeExtraData(extra []byte) (
nanos int,
duration time.Duration,
err error,
) {
if len(extra) != 12 {
return 0, 0, errors.New("extra data must be 12 bytes long")
}
return int(binary.BigEndian.Uint32(extra[:4])),
time.Duration(binary.BigEndian.Uint64(extra[4:])),
nil
}

func (b *Block) EstimateSize() int {
return int(unsafe.Sizeof(*b)) +
len(b.TransactionHashes)*int(unsafe.Sizeof(common.Hash{}))
Expand Down
28 changes: 18 additions & 10 deletions tests/block_header_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ package tests

import (
"context"
"encoding/binary"
"math/big"
"testing"
"time"

"github.com/Fantom-foundation/go-opera/evmcore"
"github.com/Fantom-foundation/go-opera/gossip/gasprice"
"github.com/Fantom-foundation/go-opera/inter"
"github.com/Fantom-foundation/go-opera/opera"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
Expand Down Expand Up @@ -109,13 +109,22 @@ func testHeaders_GasUsedIsBelowGasLimit(t *testing.T, headers []*types.Header) {

func testHeaders_EncodesDurationAndNanoTimeInExtraData(t *testing.T, headers []*types.Header) {
require := require.New(t)

getUnixTime := func(header *types.Header) time.Time {
t.Helper()
nanos, _, err := inter.DecodeExtraData(header.Extra)
require.NoError(err)
return time.Unix(int64(header.Time), int64(nanos))
}

// Check the nano-time and duration encoded in the extra data field.
for i := 1; i < len(headers); i++ {
require.Equal(len(headers[i].Extra), 16, "extra data length of block %d", i)
lastTime := binary.BigEndian.Uint64(headers[i-1].Extra[:8])
currentTime := binary.BigEndian.Uint64(headers[i].Extra[:8])
wantedDuration := currentTime - lastTime
gotDuration := binary.BigEndian.Uint64(headers[i].Extra[8:])
require.Equal(len(headers[i].Extra), 12, "extra data length of block %d", i)
lastTime := getUnixTime(headers[i-1])
currentTime := getUnixTime(headers[i])
wantedDuration := currentTime.Sub(lastTime)
_, gotDuration, err := inter.DecodeExtraData(headers[i].Extra)
require.NoError(err, "decoding extra data of block %d", i)
require.Equal(wantedDuration, gotDuration, "duration of block %d", i)
}
}
Expand All @@ -132,13 +141,12 @@ func testHeaders_BaseFeeEvolutionFollowsPricingRules(t *testing.T, headers []*ty

// All other blocks compute the base-fee based on the previous block.
for i := 1; i < len(headers); i++ {
_, duration, err := inter.DecodeExtraData(headers[i-1].Extra)
require.NoError(err, "decoding extra data of block %d", i-1)
last := &evmcore.EvmHeader{
BaseFee: headers[i-1].BaseFee,
GasLimit: headers[i-1].GasLimit,
GasUsed: headers[i-1].GasUsed,
Duration: time.Duration(
binary.BigEndian.Uint64(headers[i-1].Extra[8:]),
),
Duration: duration,
}
require.Equal(
gasprice.GetBaseFeeForNextBlock(last, rules),
Expand Down

0 comments on commit 52e3300

Please sign in to comment.