update genesis logic to create Eth Null Addresses as EthAccounts.

This commit is contained in:
Raúl Kripalani 2023-01-11 16:56:58 +00:00 committed by raulk
parent 1e0c78098c
commit d520dbbc4b
3 changed files with 155 additions and 147 deletions

View File

@ -1,113 +0,0 @@
package genesis
import (
"context"
"encoding/hex"
"fmt"
"github.com/ipfs/go-cid"
"github.com/filecoin-project/go-state-types/abi"
actorstypes "github.com/filecoin-project/go-state-types/actors"
"github.com/filecoin-project/go-state-types/big"
builtintypes "github.com/filecoin-project/go-state-types/builtin"
evm10 "github.com/filecoin-project/go-state-types/builtin/v10/evm"
init10 "github.com/filecoin-project/go-state-types/builtin/v10/init"
"github.com/filecoin-project/go-state-types/manifest"
"github.com/filecoin-project/go-state-types/network"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/vm"
)
func SetupFEVM(ctx context.Context, cs *store.ChainStore, sys vm.SyscallBuilder, sroot cid.Cid, nv network.Version) (cid.Cid, error) {
av, err := actorstypes.VersionForNetwork(nv)
if err != nil {
return cid.Undef, fmt.Errorf("failed to get actors version for network version %d: %w", nv, err)
}
if av < actorstypes.Version10 {
// Not defined before version 10; migration has to setup.
return sroot, nil
}
csc := func(context.Context, abi.ChainEpoch, *state.StateTree) (abi.TokenAmount, error) {
return big.Zero(), nil
}
newVM := func(base cid.Cid) (vm.Interface, error) {
vmopt := &vm.VMOpts{
StateBase: base,
Epoch: 0,
Rand: &fakeRand{},
Bstore: cs.StateBlockstore(),
Actors: filcns.NewActorRegistry(),
Syscalls: mkFakedSigSyscalls(sys),
CircSupplyCalc: csc,
NetworkVersion: nv,
BaseFee: big.Zero(),
}
return vm.NewVM(ctx, vmopt)
}
genesisVm, err := newVM(sroot)
if err != nil {
return cid.Undef, fmt.Errorf("creating vm: %w", err)
}
// The ETH0 address is occupied by an empty contract EVM actor
evmCodeCid, ok := actors.GetActorCodeID(av, manifest.EvmKey)
if !ok {
return cid.Undef, fmt.Errorf("failed to get CodeCID for EVM during genesis")
}
// initcode:
// %push(code_end - code_begin)
// dup1
// %push(code_begin)
// push1 0x00
// codecopy
// push1 0x00
// return
// code_begin:
// push1 0x00
// push1 0x00
// return
// code_end:
initcode, err := hex.DecodeString("600580600b6000396000f360006000f3")
if err != nil {
return cid.Undef, fmt.Errorf("failed to parse ETH0 init code during genesis: %w", err)
}
ctorParams := &evm10.ConstructorParams{
Creator: make([]byte, 20), // self!
// TODO we have a bunch of bugs in the evm constructor around empty contracts
// - empty init code is not allowed
// - returning an empty contract is not allowed
// So this uses code that constructs a just return contract until that can be fixed
// and we can pass an empty byte array
Initcode: initcode,
}
params := &init10.Exec4Params{
CodeCID: evmCodeCid,
ConstructorParams: mustEnc(ctorParams),
SubAddress: make([]byte, 20),
}
if _, err := doExecValue(ctx, genesisVm, builtintypes.InitActorAddr, builtintypes.EthereumAddressManagerActorAddr, big.Zero(), builtintypes.MethodsInit.Exec4, mustEnc(params)); err != nil {
return cid.Undef, fmt.Errorf("creating ETH0 actor: %w", err)
}
newroot, err := genesisVm.Flush(ctx)
if err != nil {
return cid.Undef, fmt.Errorf("flushing vm: %w", err)
}
return newroot, nil
}

View File

@ -16,7 +16,6 @@ import (
"github.com/filecoin-project/go-state-types/abi"
actorstypes "github.com/filecoin-project/go-state-types/actors"
"github.com/filecoin-project/go-state-types/big"
builtintypes "github.com/filecoin-project/go-state-types/builtin"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/go-state-types/manifest"
"github.com/filecoin-project/go-state-types/network"
@ -60,6 +59,8 @@ type GenesisBootstrap struct {
Genesis *types.BlockHeader
}
var EmptyObjCid = cid.Undef
/*
From a list of parameters, create a genesis block / initial state
@ -124,9 +125,10 @@ Genesis: {
func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template genesis.Template) (*state.StateTree, map[address.Address]address.Address, error) {
// Create empty state tree
cst := cbor.NewCborStore(bs)
_, err := cst.Put(context.TODO(), []struct{}{})
var err error
EmptyObjCid, err = cst.Put(context.TODO(), []struct{}{})
if err != nil {
return nil, nil, xerrors.Errorf("putting empty object: %w", err)
}
@ -239,15 +241,12 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
// Create accounts
for _, info := range template.Accounts {
switch info.Type {
case genesis.TAccount:
if err := CreateAccountActor(ctx, cst, state, info, keyIDs, av); err != nil {
return nil, nil, xerrors.Errorf("failed to create account actor: %w", err)
}
case genesis.TMultisig:
ida, err := address.NewIDAddress(uint64(idStart))
if err != nil {
return nil, nil, err
@ -592,12 +591,21 @@ func MakeGenesisBlock(ctx context.Context, j journal.Journal, bs bstore.Blocksto
return nil, xerrors.Errorf("setup miners failed: %w", err)
}
// setup FEVM
stateroot, err = SetupFEVM(ctx, cs, sys, stateroot, template.NetworkVersion)
st, err = state.LoadStateTree(st.Store, stateroot)
if err != nil {
return nil, xerrors.Errorf("failed to setup FEVM functionality: %w", err)
return nil, xerrors.Errorf("failed to load updated state tree: %w", err)
}
// Set up Eth null addresses.
if _, err := SetupEthNullAddresses(ctx, st, template.NetworkVersion); err != nil {
return nil, xerrors.Errorf("failed to set up Eth null addresses: %w", err)
}
stateroot, err = st.Flush(ctx)
if err != nil {
return nil, xerrors.Errorf("failed to flush state tree: %w", err)
}
store := adt.WrapStore(ctx, cbor.NewCborStore(bs))
emptyroot, err := adt0.MakeEmptyArray(store).Root()
if err != nil {
@ -681,28 +689,3 @@ func MakeGenesisBlock(ctx context.Context, j journal.Journal, bs bstore.Blocksto
Genesis: b,
}, nil
}
func SetupEAM(_ context.Context, nst *state.StateTree, nv network.Version) error {
av, err := actorstypes.VersionForNetwork(nv)
if err != nil {
return fmt.Errorf("failed to get actors version for network version %d: %w", nv, err)
}
if av < actorstypes.Version10 {
// Not defined before version 10; migration has to create.
return nil
}
codecid, ok := actors.GetActorCodeID(av, manifest.EamKey)
if !ok {
return fmt.Errorf("failed to get CodeCID for EAM during genesis")
}
header := &types.Actor{
Code: codecid,
Head: vm.EmptyObjectCid,
Balance: big.Zero(),
Address: &builtintypes.EthereumAddressManagerActorAddr, // so that it can create ETH0
}
return nst.SetActor(builtintypes.EthereumAddressManagerActorAddr, header)
}

View File

@ -0,0 +1,138 @@
package genesis
import (
"context"
"fmt"
"github.com/filecoin-project/go-address"
actorstypes "github.com/filecoin-project/go-state-types/actors"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/go-state-types/builtin"
"github.com/filecoin-project/go-state-types/manifest"
"github.com/filecoin-project/go-state-types/network"
"github.com/filecoin-project/lotus/chain/actors/adt"
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/ethtypes"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/chain/actors"
)
// EthNullAddresses are the Ethereum addresses we want to create zero-balanced EthAccounts in.
// We may want to add null addresses for precompiles going forward.
var EthNullAddresses = []string{
"0x0000000000000000000000000000000000000000",
}
func SetupEAM(_ context.Context, nst *state.StateTree, nv network.Version) error {
av, err := actorstypes.VersionForNetwork(nv)
if err != nil {
return fmt.Errorf("failed to get actors version for network version %d: %w", nv, err)
}
if av < actorstypes.Version10 {
// Not defined before version 10; migration has to create.
return nil
}
codecid, ok := actors.GetActorCodeID(av, manifest.EamKey)
if !ok {
return fmt.Errorf("failed to get CodeCID for EAM during genesis")
}
header := &types.Actor{
Code: codecid,
Head: EmptyObjCid,
Balance: big.Zero(),
Address: &builtin.EthereumAddressManagerActorAddr, // so that it can create ETH0
}
return nst.SetActor(builtin.EthereumAddressManagerActorAddr, header)
}
// MakeEthNullAddressActor creates a null address actor at the specified Ethereum address.
func MakeEthNullAddressActor(av actorstypes.Version, addr address.Address) (*types.Actor, error) {
actcid, ok := actors.GetActorCodeID(av, manifest.EthAccountKey)
if !ok {
return nil, xerrors.Errorf("failed to get account actor code ID for actors version %d", av)
}
act := &types.Actor{
Code: actcid,
Head: EmptyObjCid,
Nonce: 0,
Balance: big.Zero(),
Address: &addr,
}
return act, nil
}
func SetupEthNullAddresses(ctx context.Context, st *state.StateTree, nv network.Version) ([]address.Address, error) {
av, err := actorstypes.VersionForNetwork(nv)
if err != nil {
return nil, xerrors.Errorf("failed to resolve actors version for network version %d: %w", err)
}
if av < actorstypes.Version10 {
// Not defined before version 10.
return nil, nil
}
var ethAddresses []ethtypes.EthAddress
for _, addr := range EthNullAddresses {
a, err := ethtypes.EthAddressFromHex(addr)
if err != nil {
return nil, xerrors.Errorf("failed to represent the 0x0 as an EthAddress: %w", err)
}
ethAddresses = append(ethAddresses, a)
}
initAct, err := st.GetActor(builtin.InitActorAddr)
if err != nil {
return nil, xerrors.Errorf("failed to load init actor: %w", err)
}
initState, err := init_.Load(adt.WrapStore(ctx, st.Store), initAct)
if err != nil {
return nil, xerrors.Errorf("failed to load init actor state: %w", err)
}
var ret []address.Address
for _, ethAddr := range ethAddresses {
// Place an EthAccount at the 0x0 Eth Null Address.
f4Addr, err := ethAddr.ToFilecoinAddress()
if err != nil {
return nil, xerrors.Errorf("failed to compute Filecoin address for Eth addr 0x0: %w", err)
}
idAddr, err := initState.MapAddressToNewID(f4Addr)
if err != nil {
return nil, xerrors.Errorf("failed to map addr in init actor: %w", err)
}
actState, err := MakeEthNullAddressActor(av, f4Addr)
if err != nil {
return nil, xerrors.Errorf("failed to create EthAccount actor for null address: %w", err)
}
if err := st.SetActor(idAddr, actState); err != nil {
return nil, xerrors.Errorf("failed to set Eth Null Address EthAccount actor state: %w", err)
}
ret = append(ret, idAddr)
}
initAct.Head, err = st.Store.Put(ctx, initState)
if err != nil {
return nil, xerrors.Errorf("failed to add init actor state to store: %w", err)
}
if err := st.SetActor(builtin.InitActorAddr, initAct); err != nil {
return nil, xerrors.Errorf("failed to set updated state for init actor: %w", err)
}
return ret, nil
}