diff --git a/chain/gen/genesis/fevm.go b/chain/gen/genesis/fevm.go deleted file mode 100644 index 3de5e7cf9..000000000 --- a/chain/gen/genesis/fevm.go +++ /dev/null @@ -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 - -} diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index 3e1c916f6..ea2ba6bf7 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -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) -} diff --git a/chain/gen/genesis/genesis_eth.go b/chain/gen/genesis/genesis_eth.go new file mode 100644 index 000000000..82223e3fc --- /dev/null +++ b/chain/gen/genesis/genesis_eth.go @@ -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 +}