Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cancun RLP #81

Merged
merged 2 commits into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions rlp/berlin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package rlp

import (
"math/big"

"github.com/Fantom-foundation/Substate/types"
)

// berlinRLP represents legacy RLP structure between Berlin and London fork starting at berlinBlock ending at londonBlock
type berlinRLP struct {
InputAlloc WorldState
OutputAlloc WorldState
Env *legacyEnv
Message *berlinMessage
Result *Result
}

// toRLP transforms r into RLP format which is compatible with the currently used Geth fork.
func (r berlinRLP) toRLP() *RLP {
return &RLP{
InputSubstate: r.InputAlloc,
OutputSubstate: r.OutputAlloc,
Env: r.Env.toEnv(),
Message: r.Message.toMessage(),
Result: r.Result,
}

}

type berlinMessage struct {
Nonce uint64
CheckNonce bool
GasPrice *big.Int
Gas uint64

From types.Address
To *types.Address `rlp:"nil"` // nil means contract creation
Value *big.Int
Data []byte

InitCodeHash *types.Hash `rlp:"nil"` // NOT nil for contract creation

AccessList types.AccessList // missing in substate DB from Geth v1.9.x
}

// toMessage transforms m into RLP format which is compatible with the currently used Geth fork.
func (m berlinMessage) toMessage() *Message {
return &Message{
Nonce: m.Nonce,
CheckNonce: m.CheckNonce,
GasPrice: m.GasPrice,
Gas: m.Gas,
From: m.From,
To: m.To,
Value: new(big.Int).Set(m.Value),
Data: m.Data,
InitCodeHash: m.InitCodeHash,
AccessList: m.AccessList,

// Same behavior as AccessListTx.gasFeeCap() and AccessListTx.gasTipCap()
GasFeeCap: m.GasPrice,
GasTipCap: m.GasPrice,
}
}
83 changes: 8 additions & 75 deletions rlp/legacy.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,6 @@ import (
"github.com/Fantom-foundation/Substate/types"
)

const (
berlinBlock = 37_455_223
londonBlock = 37_534_833
)

// IsLondonFork returns true if block is part of the london fork block range
func IsLondonFork(block uint64) bool {
return block >= londonBlock
}

// IsBerlinFork returns true if block is part of the berlin fork block range
func IsBerlinFork(block uint64) bool {
return block >= berlinBlock && block < londonBlock
}

// legacySubstateRLP represents legacy RLP structure between before Berlin fork thus before berlinBlock
type legacySubstateRLP struct {
InputAlloc WorldState
Expand All @@ -30,12 +15,13 @@ type legacySubstateRLP struct {
Result *Result
}

func (r legacySubstateRLP) toLondon() *RLP {
// toRLP transforms r into RLP format which is compatible with the currently used Geth fork.
func (r legacySubstateRLP) toRLP() *RLP {
return &RLP{
InputSubstate: r.InputAlloc,
OutputSubstate: r.OutputAlloc,
Env: r.Env.toLondon(),
Message: r.Message.toLondon(),
Env: r.Env.toEnv(),
Message: r.Message.toMessage(),
Result: r.Result,
}
}
Expand All @@ -54,7 +40,8 @@ type legacyMessage struct {
InitCodeHash *types.Hash `rlp:"nil"` // NOT nil for contract creation
}

func (m legacyMessage) toLondon() *Message {
// toMessage transforms m into RLP format which is compatible with the currently used Geth fork.
func (m legacyMessage) toMessage() *Message {
return &Message{
Nonce: m.Nonce,
CheckNonce: m.CheckNonce,
Expand Down Expand Up @@ -82,7 +69,8 @@ type legacyEnv struct {
BlockHashes [][2]types.Hash
}

func (e legacyEnv) toLondon() *Env {
// toEnv transforms e into RLP format which is compatible with the currently used Geth fork.
func (e legacyEnv) toEnv() *Env {
return &Env{
Coinbase: e.Coinbase,
Difficulty: e.Difficulty,
Expand All @@ -92,58 +80,3 @@ func (e legacyEnv) toLondon() *Env {
BlockHashes: e.BlockHashes,
}
}

// berlinRLP represents legacy RLP structure between Berlin and London fork starting at berlinBlock ending at londonBlock
type berlinRLP struct {
InputAlloc WorldState
OutputAlloc WorldState
Env *legacyEnv
Message *berlinMessage
Result *Result
}

func (r berlinRLP) toLondon() *RLP {
return &RLP{
InputSubstate: r.InputAlloc,
OutputSubstate: r.OutputAlloc,
Env: r.Env.toLondon(),
Message: r.Message.toLondon(),
Result: r.Result,
}

}

type berlinMessage struct {
Nonce uint64
CheckNonce bool
GasPrice *big.Int
Gas uint64

From types.Address
To *types.Address `rlp:"nil"` // nil means contract creation
Value *big.Int
Data []byte

InitCodeHash *types.Hash `rlp:"nil"` // NOT nil for contract creation

AccessList types.AccessList // missing in substate DB from Geth v1.9.x
}

func (m berlinMessage) toLondon() *Message {
return &Message{
Nonce: m.Nonce,
CheckNonce: m.CheckNonce,
GasPrice: m.GasPrice,
Gas: m.Gas,
From: m.From,
To: m.To,
Value: new(big.Int).Set(m.Value),
Data: m.Data,
InitCodeHash: m.InitCodeHash,
AccessList: m.AccessList,

// Same behavior as AccessListTx.gasFeeCap() and AccessListTx.gasTipCap()
GasFeeCap: m.GasPrice,
GasTipCap: m.GasPrice,
}
}
158 changes: 158 additions & 0 deletions rlp/london.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package rlp

import (
"math/big"

"github.com/Fantom-foundation/Substate/substate"
"github.com/Fantom-foundation/Substate/types"
)

func NewLondonRLP(substate *substate.Substate) *londonRLP {
return &londonRLP{
InputSubstate: NewWorldState(substate.InputSubstate),
OutputSubstate: NewWorldState(substate.OutputSubstate),
Env: newLondonEnv(substate.Env),
Message: newLondonMessage(substate.Message),
Result: NewResult(substate.Result),
}
}

// londonRLP represents RLP structure after londonBlock and before cancun fork.
type londonRLP struct {
InputSubstate WorldState
OutputSubstate WorldState
Env londonEnv
Message londonMessage
Result *Result
}

// toRLP transforms r into RLP format which is compatible with the currently used Geth fork.
func (r londonRLP) toRLP() *RLP {
return &RLP{
InputSubstate: r.InputSubstate,
OutputSubstate: r.OutputSubstate,
Env: r.Env.toEnv(),
Message: r.Message.toMessage(),
Result: r.Result,
}
}

func newLondonEnv(env *substate.Env) londonEnv {
e := londonEnv{
Coinbase: env.Coinbase,
Difficulty: env.Difficulty,
GasLimit: env.GasLimit,
Number: env.Number,
Timestamp: env.Timestamp,
BlockHashes: createBlockHashes(env.BlockHashes),
}

e.BaseFee = nil
if env.BaseFee != nil {
baseFeeHash := types.BigToHash(env.BaseFee)
e.BaseFee = &baseFeeHash
}

return e
}

func createBlockHashes(m map[uint64]types.Hash) (blockHashes [][2]types.Hash) {
var sortedNum64 []uint64
for num64 := range m {
sortedNum64 = append(sortedNum64, num64)
}

for _, num64 := range sortedNum64 {
num := types.BigToHash(new(big.Int).SetUint64(num64))
blockHash := m[num64]
pair := [2]types.Hash{num, blockHash}
blockHashes = append(blockHashes, pair)
}
return blockHashes
}

type londonEnv struct {
Coinbase types.Address
Difficulty *big.Int
GasLimit uint64
Number uint64
Timestamp uint64
BlockHashes [][2]types.Hash

BaseFee *types.Hash `rlp:"nil"` // missing in substate DB from Geth <= v1.10.3
}

// toEnv transforms m into RLP format which is compatible with the currently used Geth fork.
func (e londonEnv) toEnv() *Env {
return &Env{
Coinbase: e.Coinbase,
Difficulty: e.Difficulty,
GasLimit: e.GasLimit,
Number: e.Number,
Timestamp: e.Timestamp,
BlockHashes: e.BlockHashes,
BaseFee: e.BaseFee,
}
}

func newLondonMessage(message *substate.Message) londonMessage {
m := londonMessage{
Nonce: message.Nonce,
CheckNonce: message.CheckNonce,
GasPrice: message.GasPrice,
Gas: message.Gas,
From: message.From,
To: message.To,
Value: new(big.Int).Set(message.Value),
Data: message.Data,
InitCodeHash: nil,
AccessList: message.AccessList,
GasFeeCap: message.GasFeeCap,
GasTipCap: message.GasTipCap,
}

if m.To == nil {
// put contract creation init code into codeDB
dataHash := message.DataHash()
m.InitCodeHash = &dataHash
m.Data = nil
}

return m
}

type londonMessage struct {
Nonce uint64
CheckNonce bool
GasPrice *big.Int
Gas uint64

From types.Address
To *types.Address `rlp:"nil"` // nil means contract creation
Value *big.Int
Data []byte

InitCodeHash *types.Hash `rlp:"nil"` // NOT nil for contract creation

AccessList types.AccessList // missing in substate DB from Geth v1.9.x

GasFeeCap *big.Int // missing in substate DB from Geth <= v1.10.3
GasTipCap *big.Int // missing in substate DB from Geth <= v1.10.3
}

// toMessage transforms m into RLP format which is compatible with the currently used Geth fork.
func (m londonMessage) toMessage() *Message {
return &Message{
Nonce: m.Nonce,
CheckNonce: m.CheckNonce,
GasPrice: m.GasPrice,
From: m.From,
To: m.To,
Value: m.Value,
Data: m.Data,
InitCodeHash: m.InitCodeHash,
AccessList: m.AccessList,
GasFeeCap: m.GasFeeCap,
GasTipCap: m.GasFeeCap,
}
}
26 changes: 16 additions & 10 deletions rlp/rlp.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,29 +26,35 @@ type RLP struct {

// Decode decodes val into RLP and returns it.
func Decode(val []byte) (*RLP, error) {
var (
substateRLP = new(RLP)
err error
)
var err error

err = rlp.DecodeBytes(val, substateRLP)
// londonRLP has currently the biggest representation the DB, so it should always be first.
var london londonRLP
err = rlp.DecodeBytes(val, &london)
if err == nil {
return substateRLP, nil
return london.toRLP(), nil
}

var berlin berlinRLP
err = rlp.DecodeBytes(val, &berlin)
if err == nil {
return berlin.toLondon(), nil
return berlin.toRLP(), nil
}

var legacy legacySubstateRLP
err = rlp.DecodeBytes(val, &legacy)
if err != nil {
return nil, err
if err == nil {
return legacy.toRLP(), nil
}

// cancun
var substateRLP RLP
err = rlp.DecodeBytes(val, &substateRLP)
if err == nil {
return &substateRLP, nil
}

return legacy.toLondon(), nil
return nil, err
}

// ToSubstate transforms every attribute of r from RLP to substate.Substate.
Expand Down
Loading
Loading