add a basic FEVM integration test. (#9922)
* add a basic FEVM integration test. Exercises f4 addresses, placeholder transitions, Ethereum Account. * remove unused parameter from newEthTxFromFilecoinMessageLookup. * break when found in newEthTxFromFilecoinMessageLookup. * fixup test. * lint and gen. * move test to itests root package. Co-authored-by: Shrenuj Bansal <shrenuj.bansal@protocol.ai>
This commit is contained in:
parent
7073b33d9b
commit
e7aa7cb04f
@ -769,6 +769,11 @@ workflows:
|
||||
suite: itest-eth_account_abstraction
|
||||
target: "./itests/eth_account_abstraction_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-eth_deploy
|
||||
suite: itest-eth_deploy
|
||||
target: "./itests/eth_deploy_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-eth_filter
|
||||
suite: itest-eth_filter
|
||||
|
@ -581,7 +581,7 @@ func (filec *FilecoinEC) checkBlockMessages(ctx context.Context, b *types.FullBl
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msg, err := txArgs.OriginalRlpMsg()
|
||||
msg, err := txArgs.ToRlpUnsignedMsg()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -796,7 +796,7 @@ func (mp *MessagePool) VerifyMsgSig(m *types.SignedMessage) error {
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to convert to eth tx args: %w", err)
|
||||
}
|
||||
msg, err := txArgs.OriginalRlpMsg()
|
||||
msg, err := txArgs.ToRlpUnsignedMsg()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
)
|
||||
|
||||
const Eip1559TxType = 2
|
||||
@ -183,7 +184,50 @@ func (tx *EthTxArgs) ToSignedMessage() (*types.SignedMessage, error) {
|
||||
|
||||
}
|
||||
|
||||
func (tx *EthTxArgs) OriginalRlpMsg() ([]byte, error) {
|
||||
func (tx *EthTxArgs) HashedOriginalRlpMsg() ([]byte, error) {
|
||||
msg, err := tx.ToRlpUnsignedMsg()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hasher := sha3.NewLegacyKeccak256()
|
||||
hasher.Write(msg)
|
||||
hash := hasher.Sum(nil)
|
||||
return hash, nil
|
||||
}
|
||||
|
||||
func (tx *EthTxArgs) ToRlpUnsignedMsg() ([]byte, error) {
|
||||
packed, err := tx.packTxFields()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
encoded, err := EncodeRLP(packed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append([]byte{0x02}, encoded...), nil
|
||||
}
|
||||
|
||||
func (tx *EthTxArgs) ToRlpSignedMsg() ([]byte, error) {
|
||||
packed1, err := tx.packTxFields()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
packed2, err := tx.packSigFields()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
encoded, err := EncodeRLP(append(packed1, packed2...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append([]byte{0x02}, encoded...), nil
|
||||
}
|
||||
|
||||
func (tx *EthTxArgs) packTxFields() ([]interface{}, error) {
|
||||
chainId, err := formatInt(tx.ChainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -225,12 +269,27 @@ func (tx *EthTxArgs) OriginalRlpMsg() ([]byte, error) {
|
||||
tx.Input,
|
||||
[]interface{}{}, // access list
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
encoded, err := EncodeRLP(res)
|
||||
func (tx *EthTxArgs) packSigFields() ([]interface{}, error) {
|
||||
r, err := formatBigInt(tx.R)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append([]byte{0x02}, encoded...), nil
|
||||
|
||||
s, err := formatBigInt(tx.S)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v, err := formatBigInt(tx.V)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := []interface{}{v, r, s}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (tx *EthTxArgs) Signature() (*typescrypto.Signature, error) {
|
||||
@ -255,7 +314,7 @@ func (tx *EthTxArgs) Signature() (*typescrypto.Signature, error) {
|
||||
}
|
||||
|
||||
func (tx *EthTxArgs) Sender() (address.Address, error) {
|
||||
msg, err := tx.OriginalRlpMsg()
|
||||
msg, err := tx.ToRlpUnsignedMsg()
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
@ -274,17 +333,11 @@ func (tx *EthTxArgs) Sender() (address.Address, error) {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
// if we get an uncompressed public key (that's what we get from the library,
|
||||
// but putting this check here for defensiveness), strip the prefix
|
||||
if pubk[0] == 0x04 {
|
||||
pubk = pubk[1:]
|
||||
ethAddr, err := delegated.EthAddressFromPubKey(pubk)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
// Calculate the f4 address based on the keccak hash of the pubkey.
|
||||
hasher.Reset()
|
||||
hasher.Write(pubk)
|
||||
ethAddr := hasher.Sum(nil)[12:]
|
||||
|
||||
return address.NewDelegatedAddress(builtintypes.EthereumAddressManagerActorID, ethAddr)
|
||||
}
|
||||
|
||||
@ -402,9 +455,9 @@ func parseEip1559Tx(data []byte) (*EthTxArgs, error) {
|
||||
GasLimit: gasLimit,
|
||||
Value: value,
|
||||
Input: input,
|
||||
V: v,
|
||||
R: r,
|
||||
S: s,
|
||||
V: v,
|
||||
}
|
||||
return &args, nil
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
"github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
)
|
||||
|
||||
@ -42,7 +43,7 @@ func TestTxArgs(t *testing.T) {
|
||||
txArgs, err := ParseEthTxArgs(tc.Input)
|
||||
require.NoError(t, err)
|
||||
|
||||
msgRecovered, err := txArgs.OriginalRlpMsg()
|
||||
msgRecovered, err := txArgs.ToRlpUnsignedMsg()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.NosigTx, "0x"+hex.EncodeToString(msgRecovered), comment)
|
||||
|
||||
@ -198,14 +199,8 @@ func TestDelegatedSigner(t *testing.T) {
|
||||
r := mustDecodeHex(rHex)
|
||||
s := mustDecodeHex(sHex)
|
||||
|
||||
if pubk[0] == 0x04 {
|
||||
pubk = pubk[1:]
|
||||
}
|
||||
|
||||
hasher := sha3.NewLegacyKeccak256()
|
||||
hasher.Reset()
|
||||
hasher.Write(pubk)
|
||||
addrHash := hasher.Sum(nil)
|
||||
addrHash, err := delegated.EthAddressFromPubKey(pubk)
|
||||
require.NoError(t, err)
|
||||
|
||||
from, err := address.NewDelegatedAddress(builtintypes.EthereumAddressManagerActorID, addrHash[12:])
|
||||
require.NoError(t, err)
|
||||
|
@ -1,7 +1,6 @@
|
||||
package key
|
||||
|
||||
import (
|
||||
"golang.org/x/crypto/sha3"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
@ -10,6 +9,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
"github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
)
|
||||
|
||||
func GenerateKey(typ types.KeyType) (*Key, error) {
|
||||
@ -54,17 +54,12 @@ func NewKey(keyinfo types.KeyInfo) (*Key, error) {
|
||||
}
|
||||
case types.KTDelegated:
|
||||
// Assume eth for now
|
||||
hasher := sha3.NewLegacyKeccak256()
|
||||
pubk := k.PublicKey
|
||||
// if we get an uncompressed public key (that's what we get from the library,
|
||||
// but putting this check here for defensiveness), strip the prefix
|
||||
if pubk[0] == 0x04 {
|
||||
pubk = pubk[1:]
|
||||
ethAddr, err := delegated.EthAddressFromPubKey(k.PublicKey)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to calculate Eth address from public key: %w", err)
|
||||
}
|
||||
|
||||
hasher.Write(pubk)
|
||||
|
||||
k.Address, err = address.NewDelegatedAddress(builtin.EthereumAddressManagerActorID, hasher.Sum(nil)[12:])
|
||||
k.Address, err = address.NewDelegatedAddress(builtin.EthereumAddressManagerActorID, ethAddr)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("converting Delegated to address: %w", err)
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ func TestEthAccountAbstraction(t *testing.T) {
|
||||
txArgs, err := ethtypes.NewEthTxArgsFromMessage(msgFromEmbryo)
|
||||
require.NoError(t, err)
|
||||
|
||||
digest, err := txArgs.OriginalRlpMsg()
|
||||
digest, err := txArgs.ToRlpUnsignedMsg()
|
||||
require.NoError(t, err)
|
||||
|
||||
siggy, err := client.WalletSign(ctx, embryoAddress, digest)
|
||||
@ -107,7 +107,7 @@ func TestEthAccountAbstraction(t *testing.T) {
|
||||
txArgs, err = ethtypes.NewEthTxArgsFromMessage(msgFromEmbryo)
|
||||
require.NoError(t, err)
|
||||
|
||||
digest, err = txArgs.OriginalRlpMsg()
|
||||
digest, err = txArgs.ToRlpUnsignedMsg()
|
||||
require.NoError(t, err)
|
||||
|
||||
siggy, err = client.WalletSign(ctx, embryoAddress, digest)
|
||||
|
136
itests/eth_deploy_test.go
Normal file
136
itests/eth_deploy_test.go
Normal file
@ -0,0 +1,136 @@
|
||||
package itests
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/manifest"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||
"github.com/filecoin-project/lotus/itests/kit"
|
||||
"github.com/filecoin-project/lotus/node/config"
|
||||
)
|
||||
|
||||
// TestDeployment smoke tests the deployment of a contract via the
|
||||
// Ethereum JSON-RPC endpoint, from an EEOA.
|
||||
func TestDeployment(t *testing.T) {
|
||||
// TODO the contract installation and invocation can be lifted into utility methods
|
||||
// He who writes the second test, shall do that.
|
||||
// kit.QuietMiningLogs()
|
||||
|
||||
blockTime := 100 * time.Millisecond
|
||||
client, _, ens := kit.EnsembleMinimal(
|
||||
t,
|
||||
kit.MockProofs(),
|
||||
kit.ThroughRPC(),
|
||||
kit.WithCfgOpt(func(cfg *config.FullNode) error {
|
||||
cfg.ActorEvent.EnableRealTimeFilterAPI = true
|
||||
return nil
|
||||
}),
|
||||
)
|
||||
ens.InterconnectAll().BeginMining(blockTime)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancel()
|
||||
|
||||
// install contract
|
||||
contractHex, err := os.ReadFile("./contracts/SimpleCoin.bin")
|
||||
require.NoError(t, err)
|
||||
|
||||
contract, err := hex.DecodeString(string(contractHex))
|
||||
require.NoError(t, err)
|
||||
|
||||
// create a new Ethereum account
|
||||
key, ethAddr, deployer := client.EVM().NewAccount()
|
||||
|
||||
// send some funds to the f410 address
|
||||
kit.SendFunds(ctx, t, client, deployer, types.FromFil(10))
|
||||
|
||||
// verify balances.
|
||||
bal := client.EVM().AssertAddressBalanceConsistent(ctx, deployer)
|
||||
require.Equal(t, types.FromFil(10), bal)
|
||||
|
||||
// verify the deployer address is an embryo.
|
||||
client.AssertActorType(ctx, deployer, manifest.EmbryoKey)
|
||||
|
||||
gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{
|
||||
From: ðAddr,
|
||||
Data: contract,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// now deploy a contract from the embryo, and validate it went well
|
||||
tx := ethtypes.EthTxArgs{
|
||||
ChainID: build.Eip155ChainId,
|
||||
Value: big.Zero(),
|
||||
Nonce: 0,
|
||||
MaxFeePerGas: types.NanoFil,
|
||||
MaxPriorityFeePerGas: big.Int(maxPriorityFeePerGas),
|
||||
GasLimit: int(gaslimit),
|
||||
Input: contract,
|
||||
V: big.Zero(),
|
||||
R: big.Zero(),
|
||||
S: big.Zero(),
|
||||
}
|
||||
|
||||
client.EVM().SignTransaction(&tx, key.PrivateKey)
|
||||
|
||||
pendingFilter, err := client.EthNewPendingTransactionFilter(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
hash := client.EVM().SubmitTransaction(ctx, &tx)
|
||||
fmt.Println(hash)
|
||||
|
||||
changes, err := client.EthGetFilterChanges(ctx, pendingFilter)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, changes.Results, 1)
|
||||
require.Equal(t, hash.String(), changes.Results[0])
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
var receipt *api.EthTxReceipt
|
||||
for i := 0; i < 10000000000; i++ {
|
||||
receipt, err = client.EthGetTransactionReceipt(ctx, hash)
|
||||
fmt.Println(receipt, err)
|
||||
if err != nil || receipt == nil {
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, receipt)
|
||||
|
||||
// Success.
|
||||
require.EqualValues(t, ethtypes.EthUint64(0x1), receipt.Status)
|
||||
|
||||
// Verify that the deployer is now an account.
|
||||
client.AssertActorType(ctx, deployer, manifest.EthAccountKey)
|
||||
|
||||
// Verify that the nonce was incremented.
|
||||
nonce, err := client.MpoolGetNonce(ctx, deployer)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, nonce)
|
||||
|
||||
// Verify that the deployer is now an account.
|
||||
client.AssertActorType(ctx, deployer, manifest.EthAccountKey)
|
||||
|
||||
// Get contract address.
|
||||
contractAddr, err := client.EVM().ComputeContractAddress(ethAddr, 0).ToFilecoinAddress()
|
||||
require.NoError(t, err)
|
||||
|
||||
client.AssertActorType(ctx, contractAddr, "evm")
|
||||
}
|
@ -7,8 +7,10 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/multiformats/go-varint"
|
||||
"github.com/stretchr/testify/require"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/crypto/sha3"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
amt4 "github.com/filecoin-project/go-amt-ipld/v4"
|
||||
@ -16,10 +18,15 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
builtintypes "github.com/filecoin-project/go-state-types/builtin"
|
||||
"github.com/filecoin-project/go-state-types/builtin/v10/eam"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||
"github.com/filecoin-project/lotus/chain/wallet/key"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
"github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
)
|
||||
|
||||
// EVM groups EVM-related actions.
|
||||
@ -122,6 +129,89 @@ func (e *EVM) LoadEvents(ctx context.Context, eventsRoot cid.Cid) []types.Event
|
||||
return ret
|
||||
}
|
||||
|
||||
func (e *EVM) NewAccount() (*key.Key, ethtypes.EthAddress, address.Address) {
|
||||
// Generate a secp256k1 key; this will back the Ethereum identity.
|
||||
key, err := key.GenerateKey(types.KTSecp256k1)
|
||||
require.NoError(e.t, err)
|
||||
|
||||
ethAddr, err := delegated.EthAddressFromPubKey(key.PublicKey)
|
||||
require.NoError(e.t, err)
|
||||
|
||||
addr, err := address.NewDelegatedAddress(builtintypes.EthereumAddressManagerActorID, ethAddr)
|
||||
require.NoError(e.t, err)
|
||||
|
||||
return key, *(*ethtypes.EthAddress)(ethAddr), addr
|
||||
}
|
||||
|
||||
// AssertAddressBalanceConsistent checks that the balance reported via the
|
||||
// Filecoin and Ethereum operations for an f410 address is identical, returning
|
||||
// the balance.
|
||||
func (e *EVM) AssertAddressBalanceConsistent(ctx context.Context, addr address.Address) big.Int {
|
||||
// Validate the arg is an f410 address.
|
||||
require.Equal(e.t, address.Delegated, addr.Protocol())
|
||||
payload := addr.Payload()
|
||||
namespace, _, err := varint.FromUvarint(payload)
|
||||
require.NoError(e.t, err)
|
||||
require.Equal(e.t, builtintypes.EthereumAddressManagerActorID, namespace)
|
||||
|
||||
fbal, err := e.WalletBalance(ctx, addr)
|
||||
require.NoError(e.t, err)
|
||||
|
||||
ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(addr)
|
||||
require.NoError(e.t, err)
|
||||
|
||||
ebal, err := e.EthGetBalance(ctx, ethAddr, "latest")
|
||||
require.NoError(e.t, err)
|
||||
|
||||
require.Equal(e.t, fbal, types.BigInt(ebal))
|
||||
return fbal
|
||||
}
|
||||
|
||||
// SignTransaction signs an Ethereum transaction in place with the supplied private key.
|
||||
func (e *EVM) SignTransaction(tx *ethtypes.EthTxArgs, privKey []byte) {
|
||||
preimage, err := tx.ToRlpUnsignedMsg()
|
||||
require.NoError(e.t, err)
|
||||
|
||||
// sign the RLP payload
|
||||
signature, err := sigs.Sign(crypto.SigTypeDelegated, privKey, preimage)
|
||||
require.NoError(e.t, err)
|
||||
|
||||
r, s, v, err := ethtypes.RecoverSignature(*signature)
|
||||
require.NoError(e.t, err)
|
||||
|
||||
tx.V = big.Int(v)
|
||||
tx.R = big.Int(r)
|
||||
tx.S = big.Int(s)
|
||||
}
|
||||
|
||||
// SubmitTransaction submits the transaction via the Eth endpoint.
|
||||
func (e *EVM) SubmitTransaction(ctx context.Context, tx *ethtypes.EthTxArgs) ethtypes.EthHash {
|
||||
signed, err := tx.ToRlpSignedMsg()
|
||||
require.NoError(e.t, err)
|
||||
|
||||
hash, err := e.EthSendRawTransaction(ctx, signed)
|
||||
require.NoError(e.t, err)
|
||||
|
||||
return hash
|
||||
}
|
||||
|
||||
// ComputeContractAddress computes the address of a contract deployed by the
|
||||
// specified address with the specified nonce.
|
||||
func (e *EVM) ComputeContractAddress(deployer ethtypes.EthAddress, nonce uint64) ethtypes.EthAddress {
|
||||
nonceRlp, err := formatInt(int(nonce))
|
||||
require.NoError(e.t, err)
|
||||
|
||||
encoded, err := ethtypes.EncodeRLP([]interface{}{
|
||||
deployer[:],
|
||||
nonceRlp,
|
||||
})
|
||||
require.NoError(e.t, err)
|
||||
|
||||
hasher := sha3.NewLegacyKeccak256()
|
||||
hasher.Write(encoded)
|
||||
return *(*ethtypes.EthAddress)(hasher.Sum(nil)[12:])
|
||||
}
|
||||
|
||||
// TODO: cleanup and put somewhere reusable.
|
||||
type apiIpldStore struct {
|
||||
ctx context.Context
|
||||
@ -152,3 +242,23 @@ func (ht *apiIpldStore) Get(ctx context.Context, c cid.Cid, out interface{}) err
|
||||
func (ht *apiIpldStore) Put(ctx context.Context, v interface{}) (cid.Cid, error) {
|
||||
panic("No mutations allowed")
|
||||
}
|
||||
|
||||
func formatInt(val int) ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
err := binary.Write(buf, binary.BigEndian, int64(val))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return removeLeadingZeros(buf.Bytes()), nil
|
||||
}
|
||||
|
||||
func removeLeadingZeros(data []byte) []byte {
|
||||
firstNonZeroIndex := len(data)
|
||||
for i, b := range data {
|
||||
if b > 0 {
|
||||
firstNonZeroIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
return data[firstNonZeroIndex:]
|
||||
}
|
||||
|
33
itests/kit/state.go
Normal file
33
itests/kit/state.go
Normal file
@ -0,0 +1,33 @@
|
||||
package kit
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
actorstypes "github.com/filecoin-project/go-state-types/actors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
// AssertActorType verifies that the supplied address is an actor of the
|
||||
// specified type (as per its manifest key).
|
||||
func (f *TestFullNode) AssertActorType(ctx context.Context, addr address.Address, actorType string) {
|
||||
// validate that an embryo was created
|
||||
act, err := f.StateGetActor(ctx, addr, types.EmptyTSK)
|
||||
require.NoError(f.t, err)
|
||||
|
||||
nv, err := f.StateNetworkVersion(ctx, types.EmptyTSK)
|
||||
require.NoError(f.t, err)
|
||||
|
||||
av, err := actorstypes.VersionForNetwork(nv)
|
||||
require.NoError(f.t, err)
|
||||
|
||||
codecid, exists := actors.GetActorCodeID(av, actorType)
|
||||
require.True(f.t, exists)
|
||||
|
||||
// check the code CID
|
||||
require.Equal(f.t, codecid, act.Code)
|
||||
}
|
26
lib/sigs/delegated/eth.go
Normal file
26
lib/sigs/delegated/eth.go
Normal file
@ -0,0 +1,26 @@
|
||||
package delegated
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
// EthAddressFromPubKey returns the Ethereum address corresponding to an
|
||||
// uncompressed secp256k1 public key.
|
||||
//
|
||||
// TODO move somewhere else, this likely doesn't belong here.
|
||||
func EthAddressFromPubKey(pubk []byte) ([]byte, error) {
|
||||
// if we get an uncompressed public key (that's what we get from the library,
|
||||
// but putting this check here for defensiveness), strip the prefix
|
||||
if pubk[0] != 0x04 {
|
||||
return nil, fmt.Errorf("expected first byte of secp256k1 to be 0x04 (uncompressed)")
|
||||
}
|
||||
pubk = pubk[1:]
|
||||
|
||||
// Calculate the Ethereum address based on the keccak hash of the pubkey.
|
||||
hasher := sha3.NewLegacyKeccak256()
|
||||
hasher.Write(pubk)
|
||||
ethAddr := hasher.Sum(nil)[12:]
|
||||
return ethAddr, nil
|
||||
}
|
@ -228,7 +228,7 @@ func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash *ethtype
|
||||
// first, try to get the cid from mined transactions
|
||||
msgLookup, err := a.StateAPI.StateSearchMsg(ctx, types.EmptyTSK, cid, api.LookbackNoLimit, true)
|
||||
if err == nil {
|
||||
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, -1, a.Chain, a.ChainAPI, a.StateAPI)
|
||||
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, -1, a.Chain, a.StateAPI)
|
||||
if err == nil {
|
||||
return &tx, nil
|
||||
}
|
||||
@ -278,7 +278,7 @@ func (a *EthModule) EthGetTransactionReceipt(ctx context.Context, txHash ethtype
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, -1, a.Chain, a.ChainAPI, a.StateAPI)
|
||||
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, -1, a.Chain, a.StateAPI)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
@ -1364,7 +1364,7 @@ func newEthBlockFromFilecoinTipSet(ctx context.Context, ts *types.TipSet, fullTx
|
||||
gasUsed += msgLookup.Receipt.GasUsed
|
||||
|
||||
if fullTxInfo {
|
||||
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, txIdx, cs, ca, sa)
|
||||
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, txIdx, cs, sa)
|
||||
if err != nil {
|
||||
return ethtypes.EthBlock{}, nil
|
||||
}
|
||||
@ -1498,7 +1498,7 @@ func newEthTxFromFilecoinMessage(ctx context.Context, smsg *types.SignedMessage,
|
||||
// newEthTxFromFilecoinMessageLookup creates an ethereum transaction from filecoin message lookup. If a negative txIdx is passed
|
||||
// into the function, it looksup the transaction index of the message in the tipset, otherwise it uses the txIdx passed into the
|
||||
// function
|
||||
func newEthTxFromFilecoinMessageLookup(ctx context.Context, msgLookup *api.MsgLookup, txIdx int, cs *store.ChainStore, ca ChainAPI, sa StateAPI) (ethtypes.EthTx, error) {
|
||||
func newEthTxFromFilecoinMessageLookup(ctx context.Context, msgLookup *api.MsgLookup, txIdx int, cs *store.ChainStore, sa StateAPI) (ethtypes.EthTx, error) {
|
||||
if msgLookup == nil {
|
||||
return ethtypes.EthTx{}, fmt.Errorf("msg does not exist")
|
||||
}
|
||||
@ -1533,6 +1533,7 @@ func newEthTxFromFilecoinMessageLookup(ctx context.Context, msgLookup *api.MsgLo
|
||||
for i, msg := range msgs {
|
||||
if msg.Cid() == msgLookup.Message {
|
||||
txIdx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if txIdx < 0 {
|
||||
|
Loading…
Reference in New Issue
Block a user