ychiao 2022-12-20 00:45:32 +08:00 committed by GitHub
parent 5f4ccfd790
commit 20f27af97e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 312 additions and 142 deletions

Binary file not shown.

View File

@ -39,9 +39,9 @@ type EthTx struct {
Gas EthUint64 `json:"gas"`
MaxFeePerGas EthBigInt `json:"maxFeePerGas"`
MaxPriorityFeePerGas EthBigInt `json:"maxPriorityFeePerGas"`
V EthBytes `json:"v"`
R EthBytes `json:"r"`
S EthBytes `json:"s"`
V EthBigInt `json:"v"`
R EthBigInt `json:"r"`
S EthBigInt `json:"s"`
}
type EthTxArgs struct {
@ -53,9 +53,9 @@ type EthTxArgs struct {
MaxPriorityFeePerGas big.Int `json:"maxPriorityFeePerGas"`
GasLimit int `json:"gasLimit"`
Input []byte `json:"input"`
V []byte `json:"v"`
R []byte `json:"r"`
S []byte `json:"s"`
V big.Int `json:"v"`
R big.Int `json:"r"`
S big.Int `json:"s"`
}
func NewEthTxArgsFromMessage(msg *types.Message) (EthTxArgs, error) {
@ -246,9 +246,17 @@ func (tx *EthTxArgs) OriginalRlpMsg() ([]byte, error) {
}
func (tx *EthTxArgs) Signature() (*typescrypto.Signature, error) {
sig := append([]byte{}, tx.R...)
sig = append(sig, tx.S...)
sig = append(sig, tx.V...)
r := tx.R.Int.Bytes()
s := tx.S.Int.Bytes()
v := tx.V.Int.Bytes()
sig := append([]byte{}, padLeadingZeros(r, 32)...)
sig = append(sig, padLeadingZeros(s, 32)...)
if len(v) == 0 {
sig = append(sig, 0)
} else {
sig = append(sig, v[0])
}
if len(sig) != 65 {
return nil, fmt.Errorf("signature is not 65 bytes")
@ -292,6 +300,33 @@ func (tx *EthTxArgs) Sender() (address.Address, error) {
return address.NewDelegatedAddress(builtintypes.EthereumAddressManagerActorID, ethAddr)
}
func RecoverSignature(sig typescrypto.Signature) (r, s, v EthBigInt, err error) {
if sig.Type != typescrypto.SigTypeDelegated {
return EthBigIntZero, EthBigIntZero, EthBigIntZero, fmt.Errorf("RecoverSignature only supports Delegated signature")
}
if len(sig.Data) != 65 {
return EthBigIntZero, EthBigIntZero, EthBigIntZero, fmt.Errorf("signature should be 65 bytes long, but got %d bytes", len(sig.Data))
}
r_, err := parseBigInt(sig.Data[0:32])
if err != nil {
return EthBigIntZero, EthBigIntZero, EthBigIntZero, fmt.Errorf("cannot parse r into EthBigInt")
}
s_, err := parseBigInt(sig.Data[32:64])
if err != nil {
return EthBigIntZero, EthBigIntZero, EthBigIntZero, fmt.Errorf("cannot parse s into EthBigInt")
}
v_, err := parseBigInt([]byte{sig.Data[64]})
if err != nil {
return EthBigIntZero, EthBigIntZero, EthBigIntZero, fmt.Errorf("cannot parse v into EthBigInt")
}
return EthBigInt(r_), EthBigInt(s_), EthBigInt(v_), nil
}
func parseEip1559Tx(data []byte) (*EthTxArgs, error) {
if data[0] != 2 {
return nil, fmt.Errorf("not an EIP-1559 transaction: first byte is not 2")
@ -355,21 +390,17 @@ func parseEip1559Tx(data []byte) (*EthTxArgs, error) {
return nil, fmt.Errorf("access list should be an empty list")
}
V, err := parseBytes(decoded[9])
r, err := parseBigInt(decoded[10])
if err != nil {
return nil, err
}
if len(V) == 0 {
V = []byte{0}
}
R, err := parseBytes(decoded[10])
s, err := parseBigInt(decoded[11])
if err != nil {
return nil, err
}
S, err := parseBytes(decoded[11])
v, err := parseBigInt(decoded[9])
if err != nil {
return nil, err
}
@ -383,9 +414,9 @@ func parseEip1559Tx(data []byte) (*EthTxArgs, error) {
GasLimit: gasLimit,
Value: value,
Input: input,
R: padLeadingZeros(R, 32),
S: padLeadingZeros(S, 32),
V: V,
R: r,
S: s,
V: v,
}
return &args, nil
}

View File

@ -63,6 +63,66 @@ func TestTxArgs(t *testing.T) {
}
}
func TestSignatures(t *testing.T) {
testcases := []struct {
RawTx string
ExpectedR string
ExpectedS string
ExpectedV string
ExpectErr bool
}{
{
"0x02f8598401df5e76028301d69083086a5e835532dd808080c080a0457e33227ac7ceee2ef121755e26b872b6fb04221993f9939349bb7b0a3e1595a02d8ef379e1d2a9e30fa61c92623cc9ed72d80cf6a48cfea341cb916bcc0a81bc",
`"0x457e33227ac7ceee2ef121755e26b872b6fb04221993f9939349bb7b0a3e1595"`,
`"0x2d8ef379e1d2a9e30fa61c92623cc9ed72d80cf6a48cfea341cb916bcc0a81bc"`,
`"0x0"`,
false,
},
{
"0x02f8598401df5e76038301d69083086a5e835532dd808080c001a012a232866dcb0671eb0ddc01fb9c01d6ef384ec892bb29691ed0d2d293052ddfa052a6ae38c6139930db21a00eee2a4caced9a6500991b823d64ec664d003bc4b1",
`"0x12a232866dcb0671eb0ddc01fb9c01d6ef384ec892bb29691ed0d2d293052ddf"`,
`"0x52a6ae38c6139930db21a00eee2a4caced9a6500991b823d64ec664d003bc4b1"`,
`"0x1"`,
false,
},
{
"0x00",
`""`,
`""`,
`""`,
true,
},
}
for _, tc := range testcases {
tx, err := ParseEthTxArgs(mustDecodeHex(tc.RawTx))
if tc.ExpectErr {
require.Error(t, err)
continue
}
require.Nil(t, err)
sig, err := tx.Signature()
require.Nil(t, err)
r, s, v, err := RecoverSignature(*sig)
require.Nil(t, err)
marshaledR, err := r.MarshalJSON()
require.Nil(t, err)
marshaledS, err := s.MarshalJSON()
require.Nil(t, err)
marshaledV, err := v.MarshalJSON()
require.Nil(t, err)
require.Equal(t, tc.ExpectedR, string(marshaledR))
require.Equal(t, tc.ExpectedS, string(marshaledS))
require.Equal(t, tc.ExpectedV, string(marshaledV))
}
}
func TestTransformParams(t *testing.T) {
constructorParams, err := actors.SerializeParams(&evm.ConstructorParams{
Initcode: mustDecodeHex("0x1122334455"),

View File

@ -61,12 +61,13 @@ func EthUint64FromHex(s string) (EthUint64, error) {
return EthUint64(parsedInt), nil
}
// EthBigInt represents a large integer whose zero value serializes to "0x0".
type EthBigInt big.Int
var EthBigIntZero = EthBigInt{Int: big.Zero().Int}
func (e EthBigInt) MarshalJSON() ([]byte, error) {
if e.Int == nil {
if e.Int == nil || e.Int.BitLen() == 0 {
return json.Marshal("0x0")
}
return json.Marshal(fmt.Sprintf("0x%x", e.Int))
@ -90,6 +91,7 @@ func (e *EthBigInt) UnmarshalJSON(b []byte) error {
return nil
}
// EthBytes represent arbitrary bytes. A nil or empty slice serializes to "0x".
type EthBytes []byte
func (e EthBytes) MarshalJSON() ([]byte, error) {
@ -97,9 +99,6 @@ func (e EthBytes) MarshalJSON() ([]byte, error) {
return json.Marshal("0x")
}
s := hex.EncodeToString(e)
if len(s)%2 == 1 {
s = "0" + s
}
return json.Marshal("0x" + s)
}

View File

@ -2330,9 +2330,9 @@ Response:
"gas": "0x5",
"maxFeePerGas": "0x0",
"maxPriorityFeePerGas": "0x0",
"v": "0x07",
"r": "0x07",
"s": "0x07"
"v": "0x0",
"r": "0x0",
"s": "0x0"
}
```
@ -2366,9 +2366,9 @@ Response:
"gas": "0x5",
"maxFeePerGas": "0x0",
"maxPriorityFeePerGas": "0x0",
"v": "0x07",
"r": "0x07",
"s": "0x07"
"v": "0x0",
"r": "0x0",
"s": "0x0"
}
```
@ -2401,9 +2401,9 @@ Response:
"gas": "0x5",
"maxFeePerGas": "0x0",
"maxPriorityFeePerGas": "0x0",
"v": "0x07",
"r": "0x07",
"s": "0x07"
"v": "0x0",
"r": "0x0",
"s": "0x0"
}
```

View File

@ -122,7 +122,15 @@ func (a *EthModule) StateNetworkName(ctx context.Context) (dtypes.NetworkName, e
}
func (a *EthModule) EthBlockNumber(context.Context) (ethtypes.EthUint64, error) {
height := a.Chain.GetHeaviestTipSet().Height()
// eth_blockNumber needs to return the height of the latest committed tipset.
// Ethereum clients expect all transactions included in this block to have execution outputs.
// This is the parent of the head tipset. The head tipset is speculative, has not been
// recognized by the network, and its messages are only included, not executed.
// See https://github.com/filecoin-project/ref-fvm/issues/1135.
height := a.Chain.GetHeaviestTipSet().Height() - 1
if height < 0 {
height = 0 // genesis is the first ever committed tipset.
}
return ethtypes.EthUint64(height), nil
}
@ -172,22 +180,39 @@ func (a *EthModule) EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthH
return newEthBlockFromFilecoinTipSet(ctx, ts, fullTxInfo, a.Chain, a.ChainAPI, a.StateAPI)
}
func (a *EthModule) EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) {
typ, num, err := ethtypes.ParseBlkNumOption(blkNum)
if err != nil {
return ethtypes.EthBlock{}, fmt.Errorf("cannot parse block number: %v", err)
func (a *EthModule) parseBlkParam(ctx context.Context, blkParam string) (tipset *types.TipSet, err error) {
if blkParam == "earliest" {
return nil, fmt.Errorf("block param \"earliest\" is not supported")
}
switch typ {
case ethtypes.BlkNumLatest:
num = ethtypes.EthUint64(a.Chain.GetHeaviestTipSet().Height()) - 1
case ethtypes.BlkNumPending:
num = ethtypes.EthUint64(a.Chain.GetHeaviestTipSet().Height())
head := a.Chain.GetHeaviestTipSet()
switch blkParam {
case "pending":
return head, nil
case "latest":
parent, err := a.Chain.GetTipSetFromKey(ctx, head.Parents())
if err != nil {
return nil, fmt.Errorf("cannot get parent tipset")
}
return parent, nil
default:
var num ethtypes.EthUint64
err := num.UnmarshalJSON([]byte(`"` + blkParam + `"`))
if err != nil {
return nil, fmt.Errorf("cannot parse block number: %v", err)
}
ts, err := a.Chain.GetTipsetByHeight(ctx, abi.ChainEpoch(num), nil, false)
if err != nil {
return nil, fmt.Errorf("cannot get tipset at height: %v", num)
}
return ts, nil
}
}
ts, err := a.Chain.GetTipsetByHeight(ctx, abi.ChainEpoch(num), nil, false)
func (a *EthModule) EthGetBlockByNumber(ctx context.Context, blkParam string, fullTxInfo bool) (ethtypes.EthBlock, error) {
ts, err := a.parseBlkParam(ctx, blkParam)
if err != nil {
return ethtypes.EthBlock{}, xerrors.Errorf("error loading tipset %s: %w", ts, err)
return ethtypes.EthBlock{}, err
}
return newEthBlockFromFilecoinTipSet(ctx, ts, fullTxInfo, a.Chain, a.ChainAPI, a.StateAPI)
}
@ -200,16 +225,31 @@ func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash *ethtype
cid := txHash.ToCid()
// first, try to get the cid from mined transactions
msgLookup, err := a.StateAPI.StateSearchMsg(ctx, types.EmptyTSK, cid, api.LookbackNoLimit, true)
if err != nil {
return nil, nil
if err == nil {
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, -1, a.Chain, a.ChainAPI, a.StateAPI)
if err == nil {
return &tx, nil
}
}
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, a.Chain, a.ChainAPI, a.StateAPI)
// if not found, try to get it from the mempool
pending, err := a.MpoolAPI.MpoolPending(ctx, types.EmptyTSK)
if err != nil {
return nil, nil
return nil, fmt.Errorf("cannot get pending txs from mpool: %v", err)
}
return &tx, nil
for _, p := range pending {
if p.Cid() == cid {
tx, err := newEthTxFromFilecoinMessage(ctx, p, a.StateAPI)
if err != nil {
return nil, fmt.Errorf("cannot get parse message into tx: %v", err)
}
return &tx, nil
}
}
return nil, fmt.Errorf("cannot find cid %v from the mpool", cid)
}
func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam string) (ethtypes.EthUint64, error) {
@ -217,7 +257,13 @@ func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes.
if err != nil {
return ethtypes.EthUint64(0), nil
}
nonce, err := a.Mpool.GetNonce(ctx, addr, types.EmptyTSK)
ts, err := a.parseBlkParam(ctx, blkParam)
if err != nil {
return ethtypes.EthUint64(0), xerrors.Errorf("cannot parse block param: %s", blkParam)
}
nonce, err := a.Mpool.GetNonce(ctx, addr, ts.Key())
if err != nil {
return ethtypes.EthUint64(0), nil
}
@ -232,7 +278,7 @@ func (a *EthModule) EthGetTransactionReceipt(ctx context.Context, txHash ethtype
return nil, nil
}
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, a.Chain, a.ChainAPI, a.StateAPI)
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, -1, a.Chain, a.ChainAPI, a.StateAPI)
if err != nil {
return nil, nil
}
@ -267,7 +313,7 @@ func (a *EthModule) EthGetTransactionByBlockNumberAndIndex(ctx context.Context,
}
// EthGetCode returns string value of the compiled bytecode
func (a *EthModule) EthGetCode(ctx context.Context, ethAddr ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) {
func (a *EthModule) EthGetCode(ctx context.Context, ethAddr ethtypes.EthAddress, blkParam string) (ethtypes.EthBytes, error) {
to, err := ethAddr.ToFilecoinAddress()
if err != nil {
return nil, xerrors.Errorf("cannot get Filecoin address: %w", err)
@ -289,7 +335,10 @@ func (a *EthModule) EthGetCode(ctx context.Context, ethAddr ethtypes.EthAddress,
GasPremium: big.Zero(),
}
ts := a.Chain.GetHeaviestTipSet()
ts, err := a.parseBlkParam(ctx, blkParam)
if err != nil {
return nil, xerrors.Errorf("cannot parse block param: %s", blkParam)
}
// Try calling until we find a height with no migration.
var res *api.InvocResult
@ -411,7 +460,12 @@ func (a *EthModule) EthGetBalance(ctx context.Context, address ethtypes.EthAddre
return ethtypes.EthBigInt{}, err
}
actor, err := a.StateGetActor(ctx, filAddr, types.EmptyTSK)
ts, err := a.parseBlkParam(ctx, blkParam)
if err != nil {
return ethtypes.EthBigInt{}, xerrors.Errorf("cannot parse block param: %s", blkParam)
}
actor, err := a.StateGetActor(ctx, filAddr, ts.Key())
if xerrors.Is(err, types.ErrActorNotFound) {
return ethtypes.EthBigIntZero, nil
} else if err != nil {
@ -631,8 +685,11 @@ func (a *EthModule) ethCallToFilecoinMessage(ctx context.Context, tx ethtypes.Et
}, nil
}
func (a *EthModule) applyMessage(ctx context.Context, msg *types.Message) (res *api.InvocResult, err error) {
ts := a.Chain.GetHeaviestTipSet()
func (a *EthModule) applyMessage(ctx context.Context, msg *types.Message, tsk types.TipSetKey) (res *api.InvocResult, err error) {
ts, err := a.Chain.GetTipSetFromKey(ctx, tsk)
if err != nil {
return nil, xerrors.Errorf("cannot get tipset: %w", err)
}
// Try calling until we find a height with no migration.
for {
@ -677,8 +734,12 @@ func (a *EthModule) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam s
if err != nil {
return nil, err
}
ts, err := a.parseBlkParam(ctx, blkParam)
if err != nil {
return nil, xerrors.Errorf("cannot parse block param: %s", blkParam)
}
invokeResult, err := a.applyMessage(ctx, msg)
invokeResult, err := a.applyMessage(ctx, msg, ts.Key())
if err != nil {
return nil, err
}
@ -1286,7 +1347,7 @@ func newEthBlockFromFilecoinTipSet(ctx context.Context, ts *types.TipSet, fullTx
return ethtypes.EthBlock{}, err
}
blkMsgs, err := cs.BlockMsgsForTipset(ctx, ts)
msgs, err := cs.MessagesForTipset(ctx, ts)
if err != nil {
return ethtypes.EthBlock{}, xerrors.Errorf("error loading messages for tipset: %v: %w", ts, err)
}
@ -1295,27 +1356,25 @@ func newEthBlockFromFilecoinTipSet(ctx context.Context, ts *types.TipSet, fullTx
// this seems to be a very expensive way to get gasUsed of the block. may need to find an efficient way to do it
gasUsed := int64(0)
for _, blkMsg := range blkMsgs {
for _, msg := range append(blkMsg.BlsMessages, blkMsg.SecpkMessages...) {
msgLookup, err := sa.StateSearchMsg(ctx, types.EmptyTSK, msg.Cid(), api.LookbackNoLimit, true)
if err != nil || msgLookup == nil {
for txIdx, msg := range msgs {
msgLookup, err := sa.StateSearchMsg(ctx, types.EmptyTSK, msg.Cid(), api.LookbackNoLimit, false)
if err != nil || msgLookup == nil {
return ethtypes.EthBlock{}, nil
}
gasUsed += msgLookup.Receipt.GasUsed
if fullTxInfo {
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, txIdx, cs, ca, sa)
if err != nil {
return ethtypes.EthBlock{}, nil
}
gasUsed += msgLookup.Receipt.GasUsed
if fullTxInfo {
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, cs, ca, sa)
if err != nil {
return ethtypes.EthBlock{}, nil
}
block.Transactions = append(block.Transactions, tx)
} else {
hash, err := ethtypes.NewEthHashFromCid(msg.Cid())
if err != nil {
return ethtypes.EthBlock{}, err
}
block.Transactions = append(block.Transactions, hash.String())
block.Transactions = append(block.Transactions, tx)
} else {
hash, err := ethtypes.NewEthHashFromCid(msg.Cid())
if err != nil {
return ethtypes.EthBlock{}, err
}
block.Transactions = append(block.Transactions, hash.String())
}
}
@ -1372,7 +1431,74 @@ func lookupEthAddress(ctx context.Context, addr address.Address, sa StateAPI) (e
return ethtypes.EthAddressFromFilecoinAddress(idAddr)
}
func newEthTxFromFilecoinMessageLookup(ctx context.Context, msgLookup *api.MsgLookup, cs *store.ChainStore, ca ChainAPI, sa StateAPI) (ethtypes.EthTx, error) {
func newEthTxFromFilecoinMessage(ctx context.Context, smsg *types.SignedMessage, sa StateAPI) (ethtypes.EthTx, error) {
fromEthAddr, err := lookupEthAddress(ctx, smsg.Message.From, sa)
if err != nil {
return ethtypes.EthTx{}, err
}
toEthAddr, err := lookupEthAddress(ctx, smsg.Message.To, sa)
if err != nil {
return ethtypes.EthTx{}, err
}
toAddr := &toEthAddr
input := smsg.Message.Params
// Check to see if we need to decode as contract deployment.
// We don't need to resolve the to address, because there's only one form (an ID).
if smsg.Message.To == builtintypes.EthereumAddressManagerActorAddr {
switch smsg.Message.Method {
case builtintypes.MethodsEAM.Create:
toAddr = nil
var params eam.CreateParams
err = params.UnmarshalCBOR(bytes.NewReader(smsg.Message.Params))
input = params.Initcode
case builtintypes.MethodsEAM.Create2:
toAddr = nil
var params eam.Create2Params
err = params.UnmarshalCBOR(bytes.NewReader(smsg.Message.Params))
input = params.Initcode
}
if err != nil {
return ethtypes.EthTx{}, err
}
}
// Otherwise, try to decode as a cbor byte array.
// TODO: Actually check if this is an ethereum call. This code will work for demo purposes, but is not correct.
if toAddr != nil {
if decodedParams, err := cbg.ReadByteArray(bytes.NewReader(smsg.Message.Params), uint64(len(smsg.Message.Params))); err == nil {
input = decodedParams
}
}
r, s, v, err := ethtypes.RecoverSignature(smsg.Signature)
if err != nil {
// we don't want to return error if the message is not an Eth tx
r, s, v = ethtypes.EthBigIntZero, ethtypes.EthBigIntZero, ethtypes.EthBigIntZero
}
tx := ethtypes.EthTx{
ChainID: ethtypes.EthUint64(build.Eip155ChainId),
From: fromEthAddr,
To: toAddr,
Value: ethtypes.EthBigInt(smsg.Message.Value),
Type: ethtypes.EthUint64(2),
Gas: ethtypes.EthUint64(smsg.Message.GasLimit),
MaxFeePerGas: ethtypes.EthBigInt(smsg.Message.GasFeeCap),
MaxPriorityFeePerGas: ethtypes.EthBigInt(smsg.Message.GasPremium),
V: v,
R: r,
S: s,
Input: input,
}
return tx, nil
}
// 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) {
if msgLookup == nil {
return ethtypes.EthTx{}, fmt.Errorf("msg does not exist")
}
@ -1399,18 +1525,19 @@ func newEthTxFromFilecoinMessageLookup(ctx context.Context, msgLookup *api.MsgLo
}
// lookup the transactionIndex
txIdx := -1
msgs, err := cs.MessagesForTipset(ctx, parentTs)
if err != nil {
return ethtypes.EthTx{}, err
}
for i, msg := range msgs {
if msg.Cid() == msgLookup.Message {
txIdx = i
if txIdx < 0 {
msgs, err := cs.MessagesForTipset(ctx, parentTs)
if err != nil {
return ethtypes.EthTx{}, err
}
for i, msg := range msgs {
if msg.Cid() == msgLookup.Message {
txIdx = i
}
}
if txIdx < 0 {
return ethtypes.EthTx{}, fmt.Errorf("cannot find the msg in the tipset")
}
}
if txIdx == -1 {
return ethtypes.EthTx{}, fmt.Errorf("cannot find the msg in the tipset")
}
blkHash, err := ethtypes.NewEthHashFromCid(parentTsCid)
@ -1418,68 +1545,21 @@ func newEthTxFromFilecoinMessageLookup(ctx context.Context, msgLookup *api.MsgLo
return ethtypes.EthTx{}, err
}
msg, err := ca.ChainGetMessage(ctx, msgLookup.Message)
smsg, err := cs.GetSignedMessage(ctx, msgLookup.Message)
if err != nil {
return ethtypes.EthTx{}, err
}
fromEthAddr, err := lookupEthAddress(ctx, msg.From, sa)
tx, err := newEthTxFromFilecoinMessage(ctx, smsg, sa)
if err != nil {
return ethtypes.EthTx{}, err
}
toEthAddr, err := lookupEthAddress(ctx, msg.To, sa)
if err != nil {
return ethtypes.EthTx{}, err
}
toAddr := &toEthAddr
input := msg.Params
// Check to see if we need to decode as contract deployment.
// We don't need to resolve the to address, because there's only one form (an ID).
if msg.To == builtintypes.EthereumAddressManagerActorAddr {
switch msg.Method {
case builtintypes.MethodsEAM.Create:
toAddr = nil
var params eam.CreateParams
err = params.UnmarshalCBOR(bytes.NewReader(msg.Params))
input = params.Initcode
case builtintypes.MethodsEAM.Create2:
toAddr = nil
var params eam.Create2Params
err = params.UnmarshalCBOR(bytes.NewReader(msg.Params))
input = params.Initcode
}
if err != nil {
return ethtypes.EthTx{}, err
}
}
// Otherwise, try to decode as a cbor byte array.
// TODO: Actually check if this is an ethereum call. This code will work for demo purposes, but is not correct.
if toAddr != nil {
if decodedParams, err := cbg.ReadByteArray(bytes.NewReader(msg.Params), uint64(len(msg.Params))); err == nil {
input = decodedParams
}
}
tx := ethtypes.EthTx{
ChainID: ethtypes.EthUint64(build.Eip155ChainId),
Hash: txHash,
BlockHash: blkHash,
BlockNumber: ethtypes.EthUint64(parentTs.Height()),
From: fromEthAddr,
To: toAddr,
Value: ethtypes.EthBigInt(msg.Value),
Type: ethtypes.EthUint64(2),
TransactionIndex: ethtypes.EthUint64(txIdx),
Gas: ethtypes.EthUint64(msg.GasLimit),
MaxFeePerGas: ethtypes.EthBigInt(msg.GasFeeCap),
MaxPriorityFeePerGas: ethtypes.EthBigInt(msg.GasPremium),
V: ethtypes.EthBytes{},
R: ethtypes.EthBytes{},
S: ethtypes.EthBytes{},
Input: input,
}
tx.ChainID = ethtypes.EthUint64(build.Eip155ChainId)
tx.Hash = txHash
tx.BlockHash = blkHash
tx.BlockNumber = ethtypes.EthUint64(parentTs.Height())
tx.TransactionIndex = ethtypes.EthUint64(txIdx)
return tx, nil
}