diff --git a/chain/actors/builtin/evm/actor.go.template b/chain/actors/builtin/evm/actor.go.template index 76d3cbe54..aa23b5f11 100644 --- a/chain/actors/builtin/evm/actor.go.template +++ b/chain/actors/builtin/evm/actor.go.template @@ -50,6 +50,7 @@ type State interface { Nonce() (uint64, error) GetState() interface{} + GetBytecode() ([]byte, error) GetBytecodeCID() (cid.Cid, error) GetBytecodeHash() ([32]byte, error) } diff --git a/chain/actors/builtin/evm/evm.go b/chain/actors/builtin/evm/evm.go index b96761c65..f55a2177d 100644 --- a/chain/actors/builtin/evm/evm.go +++ b/chain/actors/builtin/evm/evm.go @@ -50,6 +50,7 @@ type State interface { Nonce() (uint64, error) GetState() interface{} + GetBytecode() ([]byte, error) GetBytecodeCID() (cid.Cid, error) GetBytecodeHash() ([32]byte, error) } diff --git a/chain/actors/builtin/evm/state.go.template b/chain/actors/builtin/evm/state.go.template index 71fb553b7..eb55a8463 100644 --- a/chain/actors/builtin/evm/state.go.template +++ b/chain/actors/builtin/evm/state.go.template @@ -51,3 +51,17 @@ func (s *state{{.v}}) GetBytecodeCID() (cid.Cid, error) { func (s *state{{.v}}) GetBytecodeHash() ([32]byte, error) { return s.State.BytecodeHash, nil } + +func (s *state{{.v}}) GetBytecode() ([]byte, error) { + bc, err := s.GetBytecodeCID() + if err != nil { + return nil, err + } + + var byteCode abi.CborBytesTransparent + if err := s.store.Get(s.store.Context(), bc, &byteCode); err != nil { + return nil, err + } + + return byteCode, nil +} diff --git a/chain/actors/builtin/evm/v10.go b/chain/actors/builtin/evm/v10.go index e651b6701..77a09037b 100644 --- a/chain/actors/builtin/evm/v10.go +++ b/chain/actors/builtin/evm/v10.go @@ -3,6 +3,7 @@ package evm import ( "github.com/ipfs/go-cid" + "github.com/filecoin-project/go-state-types/abi" evm10 "github.com/filecoin-project/go-state-types/builtin/v10/evm" "github.com/filecoin-project/lotus/chain/actors/adt" @@ -51,3 +52,17 @@ func (s *state10) GetBytecodeCID() (cid.Cid, error) { func (s *state10) GetBytecodeHash() ([32]byte, error) { return s.State.BytecodeHash, nil } + +func (s *state10) GetBytecode() ([]byte, error) { + bc, err := s.GetBytecodeCID() + if err != nil { + return nil, err + } + + var byteCode abi.CborBytesTransparent + if err := s.store.Get(s.store.Context(), bc, &byteCode); err != nil { + return nil, err + } + + return byteCode, nil +} diff --git a/itests/eth_deploy_test.go b/itests/eth_deploy_test.go index 98038de7b..bbdadb1d5 100644 --- a/itests/eth_deploy_test.go +++ b/itests/eth_deploy_test.go @@ -11,12 +11,16 @@ import ( "time" "github.com/stretchr/testify/require" + "golang.org/x/crypto/sha3" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/manifest" + gstStore "github.com/filecoin-project/go-state-types/store" "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/blockstore" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/builtin/evm" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types/ethtypes" "github.com/filecoin-project/lotus/itests/kit" @@ -219,4 +223,32 @@ func TestDeployment(t *testing.T) { require.NoError(t, err) client.AssertActorType(ctx, contractAddr, "evm") + + // Check bytecode and bytecode hash match. + contractAct, err := client.StateGetActor(ctx, contractAddr, types.EmptyTSK) + require.NoError(t, err) + + bs := blockstore.NewAPIBlockstore(client) + ctxStore := gstStore.WrapBlockStore(ctx, bs) + + evmSt, err := evm.Load(ctxStore, contractAct) + require.NoError(t, err) + + byteCodeCid, err := evmSt.GetBytecodeCID() + require.NoError(t, err) + + byteCode, err := bs.Get(ctx, byteCodeCid) + require.NoError(t, err) + + byteCodeHashChain, err := evmSt.GetBytecodeHash() + require.NoError(t, err) + + hasher := sha3.NewLegacyKeccak256() + hasher.Write(byteCode.RawData()) + byteCodeHash := hasher.Sum(nil) + require.Equal(t, byteCodeHashChain[:], byteCodeHash) + + byteCodeSt, err := evmSt.GetBytecode() + require.NoError(t, err) + require.Equal(t, byteCode.RawData(), byteCodeSt) }