Skip to content

Commit

Permalink
Support genesis constructors for Chiado (erigontech#6103)
Browse files Browse the repository at this point in the history
This is a continuation of PR erigontech#6058 and fixes Chiado genesis state root
by supporting genesis constructors (deployment code).
  • Loading branch information
yperbasis authored Nov 21, 2022
1 parent c582f75 commit 0b28c7a
Show file tree
Hide file tree
Showing 15 changed files with 358 additions and 234 deletions.
2 changes: 1 addition & 1 deletion cmd/evm/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ func runCmd(ctx *cli.Context) error {
if chainConfig != nil {
runtimeConfig.ChainConfig = chainConfig
} else {
runtimeConfig.ChainConfig = params.AllEthashProtocolChanges
runtimeConfig.ChainConfig = params.AllProtocolChanges
}

var hexInput []byte
Expand Down
4 changes: 2 additions & 2 deletions cmd/pics/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ func initialState1() error {
address2 = crypto.PubkeyToAddress(key2.PublicKey)
theAddr = common.Address{1}
gspec = &core.Genesis{
Config: params.AllEthashProtocolChanges,
Config: params.AllProtocolChanges,
Alloc: core.GenesisAlloc{
address: {Balance: big.NewInt(9000000000000000000)},
address1: {Balance: big.NewInt(200000000000000000)},
Expand All @@ -281,7 +281,7 @@ func initialState1() error {
GasLimit: 10000000,
}
// this code generates a log
signer = types.MakeSigner(params.AllEthashProtocolChanges, 1)
signer = types.MakeSigner(params.AllProtocolChanges, 1)
)
m := stages.MockWithGenesis(nil, gspec, key, false)
defer m.DB.Close()
Expand Down
34 changes: 17 additions & 17 deletions core/allocs/chiado.json

Large diffs are not rendered by default.

35 changes: 30 additions & 5 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -507,11 +507,36 @@ func SysCallContract(contract common.Address, data []byte, chainConfig params.Ch
return ret, err
}

// from the null sender, with 50M gas.
func SysCallContractTx(contract common.Address, data []byte) (tx types.Transaction, err error) {
//nonce := ibs.GetNonce(SystemAddress)
tx = types.NewTransaction(0, contract, u256.Num0, 50_000_000, u256.Num0, data)
return tx.FakeSign(state.SystemAddress)
// SysCreate is a special (system) contract creation methods for genesis constructors.
func SysCreate(contract common.Address, data []byte, chainConfig params.ChainConfig, ibs *state.IntraBlockState, header *types.Header) (result []byte, err error) {
if chainConfig.DAOForkSupport && chainConfig.DAOForkBlock != nil && chainConfig.DAOForkBlock.Cmp(header.Number) == 0 {
misc.ApplyDAOHardFork(ibs)
}

msg := types.NewMessage(
contract,
nil, // to
0, u256.Num0,
math.MaxUint64, u256.Num0,
nil, nil,
data, nil, false,
true, // isFree
)
vmConfig := vm.Config{NoReceipts: true}
// Create a new context to be used in the EVM environment
author := &contract
txContext := NewEVMTxContext(msg)
blockContext := NewEVMBlockContext(header, GetHashFn(header, nil), nil, author)
evm := vm.NewEVM(blockContext, txContext, ibs, &chainConfig, vmConfig)

ret, _, err := evm.SysCreate(
vm.AccountRef(msg.From()),
msg.Data(),
msg.Gas(),
msg.Value(),
contract,
)
return ret, err
}

func CallContract(contract common.Address, data []byte, chainConfig params.ChainConfig, ibs *state.IntraBlockState, header *types.Header, engine consensus.Engine) (result []byte, err error) {
Expand Down
26 changes: 16 additions & 10 deletions core/gen_genesis_account.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

133 changes: 88 additions & 45 deletions core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ import (
"github.com/holiman/uint256"
"github.com/ledgerwatch/erigon-lib/kv"
"github.com/ledgerwatch/erigon-lib/kv/mdbx"
"github.com/ledgerwatch/log/v3"
"golang.org/x/exp/slices"

"github.com/ledgerwatch/erigon/common"
"github.com/ledgerwatch/erigon/common/hexutil"
"github.com/ledgerwatch/erigon/common/math"
Expand All @@ -44,7 +47,6 @@ import (
"github.com/ledgerwatch/erigon/params"
"github.com/ledgerwatch/erigon/params/networkname"
"github.com/ledgerwatch/erigon/turbo/trie"
"github.com/ledgerwatch/log/v3"
)

//go:generate gencodec -type Genesis -field-override genesisSpecMarshaling -out gen_genesis.go
Expand Down Expand Up @@ -101,12 +103,14 @@ func (ga *GenesisAlloc) UnmarshalJSON(data []byte) error {
}

// GenesisAccount is an account in the state of the genesis block.
// Either use "constructor" for deployment code or "code" directly for the final code.
type GenesisAccount struct {
Code []byte `json:"code,omitempty"`
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
Balance *big.Int `json:"balance" gencodec:"required"`
Nonce uint64 `json:"nonce,omitempty"`
PrivateKey []byte `json:"secretKey,omitempty"` // for tests
Constructor []byte `json:"constructor,omitempty"` // deployment code
Code []byte `json:"code,omitempty"` // final contract code
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
Balance *big.Int `json:"balance" gencodec:"required"`
Nonce uint64 `json:"nonce,omitempty"`
PrivateKey []byte `json:"secretKey,omitempty"` // for tests
}

// field type overrides for gencodec
Expand All @@ -123,11 +127,12 @@ type genesisSpecMarshaling struct {
}

type genesisAccountMarshaling struct {
Code hexutil.Bytes
Balance *math.HexOrDecimal256
Nonce math.HexOrDecimal64
Storage map[storageJSON]storageJSON
PrivateKey hexutil.Bytes
Constructor hexutil.Bytes
Code hexutil.Bytes
Balance *math.HexOrDecimal256
Nonce math.HexOrDecimal64
Storage map[storageJSON]storageJSON
PrivateKey hexutil.Bytes
}

// storageJSON represents a 256 bit byte array, but allows less than 256 bits when
Expand Down Expand Up @@ -208,7 +213,7 @@ func MustCommitGenesisBlock(db kv.RwDB, genesis *Genesis) (*params.ChainConfig,

func WriteGenesisBlock(db kv.RwTx, genesis *Genesis, overrideMergeNetsplitBlock, overrideTerminalTotalDifficulty *big.Int) (*params.ChainConfig, *types.Block, error) {
if genesis != nil && genesis.Config == nil {
return params.AllEthashProtocolChanges, nil, ErrGenesisNoConfig
return params.AllProtocolChanges, nil, ErrGenesisNoConfig
}
// Just commit the new block if there is no stored genesis block.
storedHash, storedErr := rawdb.ReadCanonicalHash(db, 0)
Expand Down Expand Up @@ -307,19 +312,61 @@ func (g *Genesis) configOrDefault(genesisHash common.Hash) *params.ChainConfig {
if config != nil {
return config
} else {
return params.AllEthashProtocolChanges
return params.AllProtocolChanges
}
}

func sortedAllocKeys(m GenesisAlloc) []string {
keys := make([]string, len(m))
i := 0
for k := range m {
keys[i] = string(k.Bytes())
i++
}
slices.Sort(keys)
return keys
}

// ToBlock creates the genesis block and writes state of a genesis specification
// to the given database (or discards it if nil).
func (g *Genesis) ToBlock() (*types.Block, *state.IntraBlockState, error) {
_ = g.Alloc //nil-check

head := &types.Header{
Number: new(big.Int).SetUint64(g.Number),
Nonce: types.EncodeNonce(g.Nonce),
Time: g.Timestamp,
ParentHash: g.ParentHash,
Extra: g.ExtraData,
GasLimit: g.GasLimit,
GasUsed: g.GasUsed,
Difficulty: g.Difficulty,
MixDigest: g.Mixhash,
Coinbase: g.Coinbase,
BaseFee: g.BaseFee,
AuRaStep: g.AuRaStep,
AuRaSeal: g.AuRaSeal,
}
if g.GasLimit == 0 {
head.GasLimit = params.GenesisGasLimit
}
if g.Difficulty == nil {
head.Difficulty = params.GenesisDifficulty
}
if g.Config != nil && (g.Config.IsLondon(0)) {
if g.BaseFee != nil {
head.BaseFee = g.BaseFee
} else {
head.BaseFee = new(big.Int).SetUint64(params.InitialBaseFee)
}
}

var root common.Hash
var statedb *state.IntraBlockState
wg := sync.WaitGroup{}
wg.Add(1)
go func() { // we may run inside write tx, can't open 2nd write tx in same goroutine
// TODO(yperbasis): use memdb.MemoryMutation instead
defer wg.Done()
tmpDB := mdbx.NewMDBX(log.New()).InMem("").MapSize(2 * datasize.GB).MustOpen()
defer tmpDB.Close()
Expand All @@ -330,7 +377,24 @@ func (g *Genesis) ToBlock() (*types.Block, *state.IntraBlockState, error) {
defer tx.Rollback()
r, w := state.NewDbStateReader(tx), state.NewDbStateWriter(tx, 0)
statedb = state.New(r)
for addr, account := range g.Alloc {

hasConstructorAllocation := false
for _, account := range g.Alloc {
if len(account.Constructor) > 0 {
hasConstructorAllocation = true
break
}
}
// See https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Consensus.AuRa/InitializationSteps/LoadGenesisBlockAuRa.cs
if hasConstructorAllocation && g.Config.Aura != nil {
statedb.CreateAccount(common.Address{}, false)
}

keys := sortedAllocKeys(g.Alloc)
for _, key := range keys {
addr := common.BytesToAddress([]byte(key))
account := g.Alloc[addr]

balance, overflow := uint256.FromBig(account.Balance)
if overflow {
panic("overflow at genesis allocs")
Expand All @@ -344,7 +408,14 @@ func (g *Genesis) ToBlock() (*types.Block, *state.IntraBlockState, error) {
statedb.SetState(addr, &key, *val)
}

if len(account.Code) > 0 || len(account.Storage) > 0 {
if len(account.Constructor) > 0 {
_, err := SysCreate(addr, account.Constructor, *g.Config, statedb, head)
if err != nil {
panic(err)
}
}

if len(account.Code) > 0 || len(account.Storage) > 0 || len(account.Constructor) > 0 {
statedb.SetIncarnation(addr, state.FirstContractIncarnation)
}
}
Expand All @@ -358,35 +429,7 @@ func (g *Genesis) ToBlock() (*types.Block, *state.IntraBlockState, error) {
}()
wg.Wait()

head := &types.Header{
Number: new(big.Int).SetUint64(g.Number),
Nonce: types.EncodeNonce(g.Nonce),
Time: g.Timestamp,
ParentHash: g.ParentHash,
Extra: g.ExtraData,
GasLimit: g.GasLimit,
GasUsed: g.GasUsed,
Difficulty: g.Difficulty,
MixDigest: g.Mixhash,
Coinbase: g.Coinbase,
Root: root,
BaseFee: g.BaseFee,
AuRaStep: g.AuRaStep,
AuRaSeal: g.AuRaSeal,
}
if g.GasLimit == 0 {
head.GasLimit = params.GenesisGasLimit
}
if g.Difficulty == nil {
head.Difficulty = params.GenesisDifficulty
}
if g.Config != nil && (g.Config.IsLondon(0)) {
if g.BaseFee != nil {
head.BaseFee = g.BaseFee
} else {
head.BaseFee = new(big.Int).SetUint64(params.InitialBaseFee)
}
}
head.Root = root

return types.NewBlock(head, nil, nil, nil), statedb, nil
}
Expand Down Expand Up @@ -442,7 +485,7 @@ func (g *Genesis) Write(tx kv.RwTx) (*types.Block, *state.IntraBlockState, error
}
config := g.Config
if config == nil {
config = params.AllEthashProtocolChanges
config = params.AllProtocolChanges
}
if err := config.CheckConfigForkOrder(); err != nil {
return nil, nil, err
Expand Down
Loading

0 comments on commit 0b28c7a

Please sign in to comment.