api: ethrpc: implement eth_sendRawTransaction (#9334)
Co-authored-by: Raúl Kripalani <raul@protocol.ai>
This commit is contained in:
parent
b53d5924a1
commit
6c7fd94aa7
@ -771,10 +771,10 @@ type FullNode interface {
|
||||
EthGetBlockTransactionCountByHash(ctx context.Context, blkHash EthHash) (EthInt, error) //perm:read
|
||||
|
||||
EthGetBlockByHash(ctx context.Context, blkHash EthHash, fullTxInfo bool) (EthBlock, error) //perm:read
|
||||
EthGetBlockByNumber(ctx context.Context, blkNum EthInt, fullTxInfo bool) (EthBlock, error) //perm:read
|
||||
EthGetTransactionByHash(ctx context.Context, txHash EthHash) (EthTx, error) //perm:read
|
||||
EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (EthBlock, error) //perm:read
|
||||
EthGetTransactionByHash(ctx context.Context, txHash *EthHash) (*EthTx, error) //perm:read
|
||||
EthGetTransactionCount(ctx context.Context, sender EthAddress, blkOpt string) (EthInt, error) //perm:read
|
||||
EthGetTransactionReceipt(ctx context.Context, txHash EthHash) (EthTxReceipt, error) //perm:read
|
||||
EthGetTransactionReceipt(ctx context.Context, txHash EthHash) (*EthTxReceipt, error) //perm:read
|
||||
EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash EthHash, txIndex EthInt) (EthTx, error) //perm:read
|
||||
EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum EthInt, txIndex EthInt) (EthTx, error) //perm:read
|
||||
|
||||
@ -787,9 +787,9 @@ type FullNode interface {
|
||||
EthProtocolVersion(ctx context.Context) (EthInt, error) //perm:read
|
||||
EthGasPrice(ctx context.Context) (EthBigInt, error) //perm:read
|
||||
|
||||
EthMaxPriorityFeePerGas(ctx context.Context) (EthBigInt, error) //perm:read
|
||||
EthEstimateGas(ctx context.Context, tx EthCall, blkParam string) (EthInt, error) //perm:read
|
||||
EthCall(ctx context.Context, tx EthCall, blkParam string) (EthBytes, error) //perm:read
|
||||
EthMaxPriorityFeePerGas(ctx context.Context) (EthBigInt, error) //perm:read
|
||||
EthEstimateGas(ctx context.Context, tx EthCall) (EthInt, error) //perm:read
|
||||
EthCall(ctx context.Context, tx EthCall, blkParam string) (EthBytes, error) //perm:read
|
||||
|
||||
EthSendRawTransaction(ctx context.Context, rawTx EthBytes) (EthHash, error) //perm:read
|
||||
|
||||
|
@ -346,6 +346,7 @@ func init() {
|
||||
Conns: 4,
|
||||
FD: 5,
|
||||
})
|
||||
|
||||
addExample(map[string]bitfield.BitField{
|
||||
"": bitfield.NewFromSet([]uint64{5, 6, 7, 10}),
|
||||
})
|
||||
@ -361,6 +362,15 @@ func init() {
|
||||
Headers: nil,
|
||||
},
|
||||
})
|
||||
|
||||
ethint := api.EthInt(5)
|
||||
addExample(ethint)
|
||||
addExample(ðint)
|
||||
ethaddr, _ := api.EthAddressFromHex("0x5CbEeCF99d3fDB3f25E309Cc264f240bb0664031")
|
||||
addExample(ðaddr)
|
||||
ethhash, _ := api.EthHashFromCid(c)
|
||||
addExample(ðhash)
|
||||
|
||||
}
|
||||
|
||||
func GetAPIType(name, pkg string) (i interface{}, t reflect.Type, permStruct []reflect.Type) {
|
||||
|
478
api/eth_transactions.go
Normal file
478
api/eth_transactions.go
Normal file
@ -0,0 +1,478 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
mathbig "math/big"
|
||||
|
||||
"golang.org/x/crypto/sha3"
|
||||
xerrors "golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
gocrypto "github.com/filecoin-project/go-crypto"
|
||||
"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/v8/evm"
|
||||
init8 "github.com/filecoin-project/go-state-types/builtin/v8/init"
|
||||
typescrypto "github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
type EthTx struct {
|
||||
ChainID EthInt `json:"chainId"`
|
||||
Nonce EthInt `json:"nonce"`
|
||||
Hash EthHash `json:"hash"`
|
||||
BlockHash EthHash `json:"blockHash"`
|
||||
BlockNumber EthInt `json:"blockNumber"`
|
||||
TransactionIndex EthInt `json:"transacionIndex"`
|
||||
From EthAddress `json:"from"`
|
||||
To *EthAddress `json:"to"`
|
||||
Value EthBigInt `json:"value"`
|
||||
Type EthInt `json:"type"`
|
||||
Input EthBytes `json:"input"`
|
||||
Gas EthInt `json:"gas"`
|
||||
GasLimit *EthInt `json:"gasLimit,omitempty"`
|
||||
MaxFeePerGas EthBigInt `json:"maxFeePerGas"`
|
||||
MaxPriorityFeePerGas EthBigInt `json:"maxPriorityFeePerGas"`
|
||||
V EthBytes `json:"v"`
|
||||
R EthBytes `json:"r"`
|
||||
S EthBytes `json:"s"`
|
||||
}
|
||||
|
||||
type EthTxArgs struct {
|
||||
ChainID int `json:"chainId"`
|
||||
Nonce int `json:"nonce"`
|
||||
To *EthAddress `json:"to"`
|
||||
Value big.Int `json:"value"`
|
||||
MaxFeePerGas big.Int `json:"maxFeePerGas"`
|
||||
MaxPriorityFeePerGas big.Int `json:"maxPrioritiyFeePerGas"`
|
||||
GasLimit int `json:"gasLimit"`
|
||||
Input []byte `json:"input"`
|
||||
V []byte `json:"v"`
|
||||
R []byte `json:"r"`
|
||||
S []byte `json:"s"`
|
||||
}
|
||||
|
||||
func NewEthTxArgsFromMessage(msg *types.Message) (EthTxArgs, error) {
|
||||
var to *EthAddress
|
||||
params := msg.Params
|
||||
if msg.To == builtintypes.InitActorAddr {
|
||||
to = nil
|
||||
|
||||
var exec init8.ExecParams
|
||||
reader := bytes.NewReader(msg.Params)
|
||||
if err := exec.UnmarshalCBOR(reader); err != nil {
|
||||
return EthTxArgs{}, err
|
||||
}
|
||||
|
||||
var evmParams evm.ConstructorParams
|
||||
reader1 := bytes.NewReader(exec.ConstructorParams)
|
||||
if err := evmParams.UnmarshalCBOR(reader1); err != nil {
|
||||
return EthTxArgs{}, err
|
||||
}
|
||||
params = evmParams.Bytecode
|
||||
} else {
|
||||
addr, err := EthAddressFromFilecoinIDAddress(msg.To)
|
||||
if err != nil {
|
||||
return EthTxArgs{}, nil
|
||||
}
|
||||
to = &addr
|
||||
}
|
||||
|
||||
return EthTxArgs{
|
||||
ChainID: build.Eip155ChainId,
|
||||
Nonce: int(msg.Nonce),
|
||||
To: to,
|
||||
Value: msg.Value,
|
||||
Input: params,
|
||||
MaxFeePerGas: msg.GasFeeCap,
|
||||
MaxPriorityFeePerGas: msg.GasPremium,
|
||||
GasLimit: int(msg.GasLimit),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (tx *EthTxArgs) ToSignedMessage() (*types.SignedMessage, error) {
|
||||
from, err := tx.Sender()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var to address.Address
|
||||
var params []byte
|
||||
|
||||
if tx.To == nil && tx.Input == nil {
|
||||
return nil, fmt.Errorf("to and input cannot both be empty")
|
||||
}
|
||||
|
||||
if tx.To == nil {
|
||||
// this is a contract creation
|
||||
to = builtintypes.InitActorAddr
|
||||
|
||||
constructorParams, err := actors.SerializeParams(&evm.ConstructorParams{
|
||||
Bytecode: tx.Input,
|
||||
InputData: []byte{},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to serialize constructor params: %w", err)
|
||||
}
|
||||
|
||||
evmActorCid, ok := actors.GetActorCodeID(actors.Version8, "evm")
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to lookup evm actor code CID")
|
||||
}
|
||||
|
||||
params, err = actors.SerializeParams(&init8.ExecParams{
|
||||
CodeCID: evmActorCid,
|
||||
ConstructorParams: constructorParams,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to serialize init actor exec params: %w", err)
|
||||
}
|
||||
} else {
|
||||
addr, err := tx.To.ToFilecoinAddress()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
to = addr
|
||||
params = tx.Input
|
||||
}
|
||||
|
||||
msg := &types.Message{
|
||||
Nonce: uint64(tx.Nonce),
|
||||
From: from,
|
||||
To: to,
|
||||
Value: tx.Value,
|
||||
Method: 2,
|
||||
Params: params,
|
||||
GasLimit: int64(tx.GasLimit),
|
||||
GasFeeCap: tx.MaxFeePerGas,
|
||||
GasPremium: tx.MaxPriorityFeePerGas,
|
||||
}
|
||||
|
||||
sig, err := tx.Signature()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
signedMsg := types.SignedMessage{
|
||||
Message: *msg,
|
||||
Signature: *sig,
|
||||
}
|
||||
return &signedMsg, nil
|
||||
|
||||
}
|
||||
|
||||
func (tx *EthTxArgs) HashedOriginalRlpMsg() ([]byte, error) {
|
||||
msg, err := tx.OriginalRlpMsg()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hasher := sha3.NewLegacyKeccak256()
|
||||
hasher.Write(msg)
|
||||
hash := hasher.Sum(nil)
|
||||
return hash, nil
|
||||
}
|
||||
|
||||
func (tx *EthTxArgs) OriginalRlpMsg() ([]byte, error) {
|
||||
chainId, err := formatInt(tx.ChainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nonce, err := formatInt(tx.Nonce)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
maxPriorityFeePerGas, err := formatBigInt(tx.MaxPriorityFeePerGas)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
maxFeePerGas, err := formatBigInt(tx.MaxFeePerGas)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gasLimit, err := formatInt(tx.GasLimit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
value, err := formatBigInt(tx.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := []interface{}{
|
||||
chainId,
|
||||
nonce,
|
||||
maxPriorityFeePerGas,
|
||||
maxFeePerGas,
|
||||
gasLimit,
|
||||
formatEthAddr(tx.To),
|
||||
value,
|
||||
tx.Input,
|
||||
[]interface{}{}, // access list
|
||||
}
|
||||
|
||||
encoded, err := EncodeRLP(res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append([]byte{0x02}, encoded...), nil
|
||||
}
|
||||
|
||||
func (tx *EthTxArgs) Signature() (*typescrypto.Signature, error) {
|
||||
if tx.V == nil || tx.R == nil || tx.S == nil {
|
||||
return nil, fmt.Errorf("one of V, R, or S is nil")
|
||||
}
|
||||
sig := append([]byte{}, tx.R...)
|
||||
sig = append(sig, tx.S...)
|
||||
sig = append(sig, tx.V...)
|
||||
|
||||
if len(sig) != 65 {
|
||||
return nil, fmt.Errorf("signature is not 65 bytes")
|
||||
}
|
||||
return &typescrypto.Signature{
|
||||
Type: typescrypto.SigTypeDelegated, Data: sig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (tx *EthTxArgs) Sender() (address.Address, error) {
|
||||
msg, err := tx.OriginalRlpMsg()
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
hasher := sha3.NewLegacyKeccak256()
|
||||
hasher.Write(msg)
|
||||
hash := hasher.Sum(nil)
|
||||
|
||||
sig, err := tx.Signature()
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
pubk, err := gocrypto.EcRecover(hash, sig.Data)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
return address.NewSecp256k1Address(pubk)
|
||||
}
|
||||
|
||||
func parseEip1559Tx(data []byte) (*EthTxArgs, error) {
|
||||
if data[0] != 2 {
|
||||
return nil, xerrors.Errorf("not an EIP-1559 transaction: first byte is not 2")
|
||||
}
|
||||
|
||||
d, err := DecodeRLP(data[1:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
decoded, ok := d.([]interface{})
|
||||
if !ok {
|
||||
return nil, xerrors.Errorf("not an EIP-1559 transaction: decoded data is not a list")
|
||||
}
|
||||
|
||||
if len(decoded) != 9 && len(decoded) != 12 {
|
||||
return nil, xerrors.Errorf("not an EIP-1559 transaction: should have 6 or 9 elements in the list")
|
||||
}
|
||||
|
||||
chainId, err := parseInt(decoded[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nonce, err := parseInt(decoded[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
maxPriorityFeePerGas, err := parseBigInt(decoded[2])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
maxFeePerGas, err := parseBigInt(decoded[3])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gasLimit, err := parseInt(decoded[4])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
to, err := parseEthAddr(decoded[5])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
value, err := parseBigInt(decoded[6])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
input, err := parseBytes(decoded[7])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
accessList, ok := decoded[8].([]interface{})
|
||||
if !ok || (ok && len(accessList) != 0) {
|
||||
return nil, fmt.Errorf("access list should be an empty list")
|
||||
}
|
||||
|
||||
V, err := parseBytes(decoded[9])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(V) == 0 {
|
||||
V = []byte{0}
|
||||
}
|
||||
|
||||
R, err := parseBytes(decoded[10])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
S, err := parseBytes(decoded[11])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
args := EthTxArgs{
|
||||
ChainID: chainId,
|
||||
Nonce: nonce,
|
||||
To: to,
|
||||
MaxPriorityFeePerGas: maxPriorityFeePerGas,
|
||||
MaxFeePerGas: maxFeePerGas,
|
||||
GasLimit: gasLimit,
|
||||
Value: value,
|
||||
Input: input,
|
||||
R: padLeadingZeros(R, 32),
|
||||
S: padLeadingZeros(S, 32),
|
||||
V: V,
|
||||
}
|
||||
return &args, nil
|
||||
}
|
||||
|
||||
func ParseEthTxArgs(data []byte) (*EthTxArgs, error) {
|
||||
if data[0] > 0x7f {
|
||||
// legacy transaction
|
||||
return nil, xerrors.Errorf("legacy transaction is not supported")
|
||||
} else if data[0] == 1 {
|
||||
// EIP-2930
|
||||
return nil, xerrors.Errorf("EIP-2930 transaction is not supported")
|
||||
} else if data[0] == 2 {
|
||||
// EIP-1559
|
||||
return parseEip1559Tx(data)
|
||||
}
|
||||
return nil, xerrors.Errorf("unsupported transaction type")
|
||||
}
|
||||
|
||||
func padLeadingZeros(data []byte, length int) []byte {
|
||||
if len(data) >= length {
|
||||
return data
|
||||
}
|
||||
zeros := make([]byte, length-len(data))
|
||||
return append(zeros, data...)
|
||||
}
|
||||
|
||||
func removeLeadingZeros(data []byte) []byte {
|
||||
firstNonZeroIndex := len(data)
|
||||
for i, b := range data {
|
||||
if b > 0 {
|
||||
firstNonZeroIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
return data[firstNonZeroIndex:]
|
||||
}
|
||||
|
||||
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 formatEthAddr(addr *EthAddress) []byte {
|
||||
if addr == nil {
|
||||
return nil
|
||||
}
|
||||
return addr[:]
|
||||
}
|
||||
|
||||
func formatBigInt(val big.Int) ([]byte, error) {
|
||||
b, err := val.Bytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return removeLeadingZeros(b), nil
|
||||
}
|
||||
|
||||
func parseInt(v interface{}) (int, error) {
|
||||
data, ok := v.([]byte)
|
||||
if !ok {
|
||||
return 0, xerrors.Errorf("cannot parse interface to int: input is not a byte array")
|
||||
}
|
||||
if len(data) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
if len(data) > 8 {
|
||||
return 0, xerrors.Errorf("cannot parse interface to int: length is more than 8 bytes")
|
||||
}
|
||||
var value int64
|
||||
r := bytes.NewReader(append(make([]byte, 8-len(data)), data...))
|
||||
if err := binary.Read(r, binary.BigEndian, &value); err != nil {
|
||||
return 0, xerrors.Errorf("cannot parse interface to EthInt: %w", err)
|
||||
}
|
||||
return int(value), nil
|
||||
}
|
||||
|
||||
func parseBigInt(v interface{}) (big.Int, error) {
|
||||
data, ok := v.([]byte)
|
||||
if !ok {
|
||||
return big.Zero(), xerrors.Errorf("cannot parse interface to big.Int: input is not a byte array")
|
||||
}
|
||||
if len(data) == 0 {
|
||||
return big.Zero(), nil
|
||||
}
|
||||
var b mathbig.Int
|
||||
b.SetBytes(data)
|
||||
return big.NewFromGo(&b), nil
|
||||
}
|
||||
|
||||
func parseBytes(v interface{}) ([]byte, error) {
|
||||
val, ok := v.([]byte)
|
||||
if !ok {
|
||||
return nil, xerrors.Errorf("cannot parse interface into bytes: input is not a byte array")
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func parseEthAddr(v interface{}) (*EthAddress, error) {
|
||||
b, err := parseBytes(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if b == nil || len(b) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
addr, err := EthAddressFromBytes(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &addr, nil
|
||||
}
|
185
api/eth_transactions_test.go
Normal file
185
api/eth_transactions_test.go
Normal file
File diff suppressed because one or more lines are too long
@ -24,6 +24,9 @@ import (
|
||||
type EthInt int64
|
||||
|
||||
func (e EthInt) MarshalJSON() ([]byte, error) {
|
||||
if e == 0 {
|
||||
return json.Marshal("0x0")
|
||||
}
|
||||
return json.Marshal(fmt.Sprintf("0x%x", e))
|
||||
}
|
||||
|
||||
@ -75,8 +78,14 @@ func (e *EthBigInt) UnmarshalJSON(b []byte) error {
|
||||
type EthBytes []byte
|
||||
|
||||
func (e EthBytes) MarshalJSON() ([]byte, error) {
|
||||
encoded := "0x" + hex.EncodeToString(e)
|
||||
return json.Marshal(encoded)
|
||||
if len(e) == 0 {
|
||||
return json.Marshal("0x00")
|
||||
}
|
||||
s := hex.EncodeToString(e)
|
||||
if len(s)%2 == 1 {
|
||||
s = "0" + s
|
||||
}
|
||||
return json.Marshal("0x" + s)
|
||||
}
|
||||
|
||||
func (e *EthBytes) UnmarshalJSON(b []byte) error {
|
||||
@ -144,33 +153,13 @@ func NewEthBlock() EthBlock {
|
||||
}
|
||||
}
|
||||
|
||||
type EthTx struct {
|
||||
ChainID EthInt `json:"chainId"`
|
||||
Nonce uint64 `json:"nonce"`
|
||||
Hash EthHash `json:"hash"`
|
||||
BlockHash EthHash `json:"blockHash"`
|
||||
BlockNumber EthInt `json:"blockNumber"`
|
||||
TransactionIndex EthInt `json:"transacionIndex"`
|
||||
From EthAddress `json:"from"`
|
||||
To *EthAddress `json:"to"`
|
||||
Value EthBigInt `json:"value"`
|
||||
Type EthInt `json:"type"`
|
||||
Input EthBytes `json:"input"`
|
||||
Gas EthInt `json:"gas"`
|
||||
MaxFeePerGas EthBigInt `json:"maxFeePerGas"`
|
||||
MaxPriorityFeePerGas EthBigInt `json:"maxPriorityFeePerGas"`
|
||||
V EthBigInt `json:"v"`
|
||||
R EthBigInt `json:"r"`
|
||||
S EthBigInt `json:"s"`
|
||||
}
|
||||
|
||||
type EthCall struct {
|
||||
From EthAddress `json:"from"`
|
||||
To EthAddress `json:"to"`
|
||||
Gas EthInt `json:"gas"`
|
||||
GasPrice EthBigInt `json:"gasPrice"`
|
||||
Value EthBigInt `json:"value"`
|
||||
Data EthBytes `json:"data"`
|
||||
From EthAddress `json:"from"`
|
||||
To *EthAddress `json:"to"`
|
||||
Gas EthInt `json:"gas"`
|
||||
GasPrice EthBigInt `json:"gasPrice"`
|
||||
Value EthBigInt `json:"value"`
|
||||
Data EthBytes `json:"data"`
|
||||
}
|
||||
|
||||
func (c *EthCall) UnmarshalJSON(b []byte) error {
|
||||
@ -186,7 +175,7 @@ func (c *EthCall) UnmarshalJSON(b []byte) error {
|
||||
|
||||
type EthTxReceipt struct {
|
||||
TransactionHash EthHash `json:"transactionHash"`
|
||||
TransactionIndex EthInt `json:"transacionIndex"`
|
||||
TransactionIndex EthInt `json:"transactionIndex"`
|
||||
BlockHash EthHash `json:"blockHash"`
|
||||
BlockNumber EthInt `json:"blockNumber"`
|
||||
From EthAddress `json:"from"`
|
||||
@ -199,6 +188,8 @@ type EthTxReceipt struct {
|
||||
CumulativeGasUsed EthInt `json:"cumulativeGasUsed"`
|
||||
GasUsed EthInt `json:"gasUsed"`
|
||||
EffectiveGasPrice EthBigInt `json:"effectiveGasPrice"`
|
||||
LogsBloom EthBytes `json:"logsBloom"`
|
||||
Logs []string `json:"logs"`
|
||||
}
|
||||
|
||||
func NewEthTxReceipt(tx EthTx, lookup *MsgLookup, replay *InvocResult) (EthTxReceipt, error) {
|
||||
@ -210,6 +201,8 @@ func NewEthTxReceipt(tx EthTx, lookup *MsgLookup, replay *InvocResult) (EthTxRec
|
||||
From: tx.From,
|
||||
To: tx.To,
|
||||
StateRoot: EmptyEthHash,
|
||||
LogsBloom: []byte{0},
|
||||
Logs: []string{},
|
||||
}
|
||||
|
||||
contractAddr, err := CheckContractCreation(lookup)
|
||||
@ -318,6 +311,15 @@ func EthAddressFromHex(s string) (EthAddress, error) {
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func EthAddressFromBytes(b []byte) (EthAddress, error) {
|
||||
var a EthAddress
|
||||
if len(b) != ETH_ADDRESS_LENGTH {
|
||||
return EthAddress{}, xerrors.Errorf("cannot initiate a new EthAddress: incorrect input length")
|
||||
}
|
||||
copy(a[:], b[:])
|
||||
return a, nil
|
||||
}
|
||||
|
||||
type EthHash [ETH_HASH_LENGTH]byte
|
||||
|
||||
func (h EthHash) MarshalJSON() ([]byte, error) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
//stm: #unit
|
||||
// stm: #unit
|
||||
package api
|
||||
|
||||
import (
|
||||
|
@ -982,18 +982,18 @@ func (mr *MockFullNodeMockRecorder) EthChainId(arg0 interface{}) *gomock.Call {
|
||||
}
|
||||
|
||||
// EthEstimateGas mocks base method.
|
||||
func (m *MockFullNode) EthEstimateGas(arg0 context.Context, arg1 api.EthCall, arg2 string) (api.EthInt, error) {
|
||||
func (m *MockFullNode) EthEstimateGas(arg0 context.Context, arg1 api.EthCall) (api.EthInt, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthEstimateGas", arg0, arg1, arg2)
|
||||
ret := m.ctrl.Call(m, "EthEstimateGas", arg0, arg1)
|
||||
ret0, _ := ret[0].(api.EthInt)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthEstimateGas indicates an expected call of EthEstimateGas.
|
||||
func (mr *MockFullNodeMockRecorder) EthEstimateGas(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
func (mr *MockFullNodeMockRecorder) EthEstimateGas(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthEstimateGas", reflect.TypeOf((*MockFullNode)(nil).EthEstimateGas), arg0, arg1, arg2)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthEstimateGas", reflect.TypeOf((*MockFullNode)(nil).EthEstimateGas), arg0, arg1)
|
||||
}
|
||||
|
||||
// EthGasPrice mocks base method.
|
||||
@ -1042,7 +1042,7 @@ func (mr *MockFullNodeMockRecorder) EthGetBlockByHash(arg0, arg1, arg2 interface
|
||||
}
|
||||
|
||||
// EthGetBlockByNumber mocks base method.
|
||||
func (m *MockFullNode) EthGetBlockByNumber(arg0 context.Context, arg1 api.EthInt, arg2 bool) (api.EthBlock, error) {
|
||||
func (m *MockFullNode) EthGetBlockByNumber(arg0 context.Context, arg1 string, arg2 bool) (api.EthBlock, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthGetBlockByNumber", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(api.EthBlock)
|
||||
@ -1147,10 +1147,10 @@ func (mr *MockFullNodeMockRecorder) EthGetTransactionByBlockNumberAndIndex(arg0,
|
||||
}
|
||||
|
||||
// EthGetTransactionByHash mocks base method.
|
||||
func (m *MockFullNode) EthGetTransactionByHash(arg0 context.Context, arg1 api.EthHash) (api.EthTx, error) {
|
||||
func (m *MockFullNode) EthGetTransactionByHash(arg0 context.Context, arg1 *api.EthHash) (*api.EthTx, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthGetTransactionByHash", arg0, arg1)
|
||||
ret0, _ := ret[0].(api.EthTx)
|
||||
ret0, _ := ret[0].(*api.EthTx)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@ -1177,10 +1177,10 @@ func (mr *MockFullNodeMockRecorder) EthGetTransactionCount(arg0, arg1, arg2 inte
|
||||
}
|
||||
|
||||
// EthGetTransactionReceipt mocks base method.
|
||||
func (m *MockFullNode) EthGetTransactionReceipt(arg0 context.Context, arg1 api.EthHash) (api.EthTxReceipt, error) {
|
||||
func (m *MockFullNode) EthGetTransactionReceipt(arg0 context.Context, arg1 api.EthHash) (*api.EthTxReceipt, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthGetTransactionReceipt", arg0, arg1)
|
||||
ret0, _ := ret[0].(api.EthTxReceipt)
|
||||
ret0, _ := ret[0].(*api.EthTxReceipt)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
@ -10,12 +10,15 @@ import (
|
||||
"github.com/google/uuid"
|
||||
blocks "github.com/ipfs/go-block-format"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/metrics"
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-bitfield"
|
||||
datatransfer "github.com/filecoin-project/go-data-transfer"
|
||||
@ -37,6 +40,7 @@ import (
|
||||
lminer "github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/journal/alerting"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
"github.com/filecoin-project/lotus/node/repo/imports"
|
||||
"github.com/filecoin-project/lotus/storage/pipeline/sealiface"
|
||||
@ -226,7 +230,7 @@ type FullNodeStruct struct {
|
||||
|
||||
EthChainId func(p0 context.Context) (EthInt, error) `perm:"read"`
|
||||
|
||||
EthEstimateGas func(p0 context.Context, p1 EthCall, p2 string) (EthInt, error) `perm:"read"`
|
||||
EthEstimateGas func(p0 context.Context, p1 EthCall) (EthInt, error) `perm:"read"`
|
||||
|
||||
EthGasPrice func(p0 context.Context) (EthBigInt, error) `perm:"read"`
|
||||
|
||||
@ -234,7 +238,7 @@ type FullNodeStruct struct {
|
||||
|
||||
EthGetBlockByHash func(p0 context.Context, p1 EthHash, p2 bool) (EthBlock, error) `perm:"read"`
|
||||
|
||||
EthGetBlockByNumber func(p0 context.Context, p1 EthInt, p2 bool) (EthBlock, error) `perm:"read"`
|
||||
EthGetBlockByNumber func(p0 context.Context, p1 string, p2 bool) (EthBlock, error) `perm:"read"`
|
||||
|
||||
EthGetBlockTransactionCountByHash func(p0 context.Context, p1 EthHash) (EthInt, error) `perm:"read"`
|
||||
|
||||
@ -248,11 +252,11 @@ type FullNodeStruct struct {
|
||||
|
||||
EthGetTransactionByBlockNumberAndIndex func(p0 context.Context, p1 EthInt, p2 EthInt) (EthTx, error) `perm:"read"`
|
||||
|
||||
EthGetTransactionByHash func(p0 context.Context, p1 EthHash) (EthTx, error) `perm:"read"`
|
||||
EthGetTransactionByHash func(p0 context.Context, p1 *EthHash) (*EthTx, error) `perm:"read"`
|
||||
|
||||
EthGetTransactionCount func(p0 context.Context, p1 EthAddress, p2 string) (EthInt, error) `perm:"read"`
|
||||
|
||||
EthGetTransactionReceipt func(p0 context.Context, p1 EthHash) (EthTxReceipt, error) `perm:"read"`
|
||||
EthGetTransactionReceipt func(p0 context.Context, p1 EthHash) (*EthTxReceipt, error) `perm:"read"`
|
||||
|
||||
EthMaxPriorityFeePerGas func(p0 context.Context) (EthBigInt, error) `perm:"read"`
|
||||
|
||||
@ -1881,14 +1885,14 @@ func (s *FullNodeStub) EthChainId(p0 context.Context) (EthInt, error) {
|
||||
return *new(EthInt), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthEstimateGas(p0 context.Context, p1 EthCall, p2 string) (EthInt, error) {
|
||||
func (s *FullNodeStruct) EthEstimateGas(p0 context.Context, p1 EthCall) (EthInt, error) {
|
||||
if s.Internal.EthEstimateGas == nil {
|
||||
return *new(EthInt), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthEstimateGas(p0, p1, p2)
|
||||
return s.Internal.EthEstimateGas(p0, p1)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthEstimateGas(p0 context.Context, p1 EthCall, p2 string) (EthInt, error) {
|
||||
func (s *FullNodeStub) EthEstimateGas(p0 context.Context, p1 EthCall) (EthInt, error) {
|
||||
return *new(EthInt), ErrNotSupported
|
||||
}
|
||||
|
||||
@ -1925,14 +1929,14 @@ func (s *FullNodeStub) EthGetBlockByHash(p0 context.Context, p1 EthHash, p2 bool
|
||||
return *new(EthBlock), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGetBlockByNumber(p0 context.Context, p1 EthInt, p2 bool) (EthBlock, error) {
|
||||
func (s *FullNodeStruct) EthGetBlockByNumber(p0 context.Context, p1 string, p2 bool) (EthBlock, error) {
|
||||
if s.Internal.EthGetBlockByNumber == nil {
|
||||
return *new(EthBlock), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthGetBlockByNumber(p0, p1, p2)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthGetBlockByNumber(p0 context.Context, p1 EthInt, p2 bool) (EthBlock, error) {
|
||||
func (s *FullNodeStub) EthGetBlockByNumber(p0 context.Context, p1 string, p2 bool) (EthBlock, error) {
|
||||
return *new(EthBlock), ErrNotSupported
|
||||
}
|
||||
|
||||
@ -2002,15 +2006,15 @@ func (s *FullNodeStub) EthGetTransactionByBlockNumberAndIndex(p0 context.Context
|
||||
return *new(EthTx), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGetTransactionByHash(p0 context.Context, p1 EthHash) (EthTx, error) {
|
||||
func (s *FullNodeStruct) EthGetTransactionByHash(p0 context.Context, p1 *EthHash) (*EthTx, error) {
|
||||
if s.Internal.EthGetTransactionByHash == nil {
|
||||
return *new(EthTx), ErrNotSupported
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthGetTransactionByHash(p0, p1)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthGetTransactionByHash(p0 context.Context, p1 EthHash) (EthTx, error) {
|
||||
return *new(EthTx), ErrNotSupported
|
||||
func (s *FullNodeStub) EthGetTransactionByHash(p0 context.Context, p1 *EthHash) (*EthTx, error) {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGetTransactionCount(p0 context.Context, p1 EthAddress, p2 string) (EthInt, error) {
|
||||
@ -2024,15 +2028,15 @@ func (s *FullNodeStub) EthGetTransactionCount(p0 context.Context, p1 EthAddress,
|
||||
return *new(EthInt), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGetTransactionReceipt(p0 context.Context, p1 EthHash) (EthTxReceipt, error) {
|
||||
func (s *FullNodeStruct) EthGetTransactionReceipt(p0 context.Context, p1 EthHash) (*EthTxReceipt, error) {
|
||||
if s.Internal.EthGetTransactionReceipt == nil {
|
||||
return *new(EthTxReceipt), ErrNotSupported
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthGetTransactionReceipt(p0, p1)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthGetTransactionReceipt(p0 context.Context, p1 EthHash) (EthTxReceipt, error) {
|
||||
return *new(EthTxReceipt), ErrNotSupported
|
||||
func (s *FullNodeStub) EthGetTransactionReceipt(p0 context.Context, p1 EthHash) (*EthTxReceipt, error) {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthMaxPriorityFeePerGas(p0 context.Context) (EthBigInt, error) {
|
||||
|
176
api/rlp.go
Normal file
176
api/rlp.go
Normal file
@ -0,0 +1,176 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func EncodeRLP(val interface{}) ([]byte, error) {
|
||||
return encodeRLP(val)
|
||||
}
|
||||
|
||||
func encodeRLPListItems(list []interface{}) (result []byte, err error) {
|
||||
res := []byte{}
|
||||
for _, elem := range list {
|
||||
encoded, err := encodeRLP(elem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = append(res, encoded...)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func encodeLength(length int) (lenInBytes []byte, err error) {
|
||||
if length == 0 {
|
||||
return nil, fmt.Errorf("cannot encode length: length should be larger than 0")
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
err = binary.Write(buf, binary.BigEndian, int64(length))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
firstNonZeroIndex := len(buf.Bytes()) - 1
|
||||
for i, b := range buf.Bytes() {
|
||||
if b != 0 {
|
||||
firstNonZeroIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
res := buf.Bytes()[firstNonZeroIndex:]
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func encodeRLP(val interface{}) ([]byte, error) {
|
||||
if data, ok := val.([]byte); ok {
|
||||
if len(data) == 1 && data[0] <= 0x7f {
|
||||
return data, nil
|
||||
} else if len(data) <= 55 {
|
||||
prefix := byte(0x80 + len(data))
|
||||
return append([]byte{prefix}, data...), nil
|
||||
} else {
|
||||
lenInBytes, err := encodeLength(len(data))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
prefix := byte(0xb7 + len(lenInBytes))
|
||||
return append(
|
||||
[]byte{prefix},
|
||||
append(lenInBytes, data...)...,
|
||||
), nil
|
||||
}
|
||||
} else if data, ok := val.([]interface{}); ok {
|
||||
encodedList, err := encodeRLPListItems(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(encodedList) <= 55 {
|
||||
prefix := byte(0xc0 + len(encodedList))
|
||||
return append(
|
||||
[]byte{prefix},
|
||||
encodedList...,
|
||||
), nil
|
||||
}
|
||||
lenInBytes, err := encodeLength(len(encodedList))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
prefix := byte(0xf7 + len(lenInBytes))
|
||||
return append(
|
||||
[]byte{prefix},
|
||||
append(lenInBytes, encodedList...)...,
|
||||
), nil
|
||||
}
|
||||
return nil, fmt.Errorf("input data should either be a list or a byte array")
|
||||
}
|
||||
|
||||
func DecodeRLP(data []byte) (interface{}, error) {
|
||||
res, consumed, err := decodeRLP(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if consumed != len(data) {
|
||||
return nil, xerrors.Errorf("invalid rlp data: length %d, consumed %d", len(data), consumed)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func decodeRLP(data []byte) (res interface{}, consumed int, err error) {
|
||||
if len(data) == 0 {
|
||||
return data, 0, xerrors.Errorf("invalid rlp data: data cannot be empty")
|
||||
}
|
||||
if data[0] >= 0xf8 {
|
||||
listLenInBytes := int(data[0]) - 0xf7
|
||||
listLen, err := decodeLength(data[1:], listLenInBytes)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
if 1+listLenInBytes+listLen > len(data) {
|
||||
return nil, 0, xerrors.Errorf("invalid rlp data: out of bound while parsing list")
|
||||
}
|
||||
result, err := decodeListElems(data[1+listLenInBytes:], listLen)
|
||||
return result, 1 + listLenInBytes + listLen, err
|
||||
} else if data[0] >= 0xc0 {
|
||||
length := int(data[0]) - 0xc0
|
||||
result, err := decodeListElems(data[1:], length)
|
||||
return result, 1 + length, err
|
||||
} else if data[0] >= 0xb8 {
|
||||
strLenInBytes := int(data[0]) - 0xb7
|
||||
strLen, err := decodeLength(data[1:], strLenInBytes)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
totalLen := 1 + strLenInBytes + strLen
|
||||
if totalLen > len(data) {
|
||||
return nil, 0, xerrors.Errorf("invalid rlp data: out of bound while parsing string")
|
||||
}
|
||||
return data[1+strLenInBytes : totalLen], totalLen, nil
|
||||
} else if data[0] >= 0x80 {
|
||||
length := int(data[0]) - 0x80
|
||||
if 1+length > len(data) {
|
||||
return nil, 0, xerrors.Errorf("invalid rlp data: out of bound while parsing string")
|
||||
}
|
||||
return data[1 : 1+length], 1 + length, nil
|
||||
}
|
||||
return []byte{data[0]}, 1, nil
|
||||
}
|
||||
|
||||
func decodeLength(data []byte, lenInBytes int) (length int, err error) {
|
||||
if lenInBytes > len(data) || lenInBytes > 8 {
|
||||
return 0, xerrors.Errorf("invalid rlp data: out of bound while parsing list length")
|
||||
}
|
||||
var decodedLength int64
|
||||
r := bytes.NewReader(append(make([]byte, 8-lenInBytes), data[:lenInBytes]...))
|
||||
if err := binary.Read(r, binary.BigEndian, &decodedLength); err != nil {
|
||||
return 0, xerrors.Errorf("invalid rlp data: cannot parse string length: %w", err)
|
||||
}
|
||||
if lenInBytes+int(decodedLength) > len(data) {
|
||||
return 0, xerrors.Errorf("invalid rlp data: out of bound while parsing list")
|
||||
}
|
||||
return int(decodedLength), nil
|
||||
}
|
||||
|
||||
func decodeListElems(data []byte, length int) (res []interface{}, err error) {
|
||||
totalConsumed := 0
|
||||
result := []interface{}{}
|
||||
|
||||
// set a limit to make sure it doesn't loop infinitely
|
||||
for i := 0; totalConsumed < length && i < 5000; i++ {
|
||||
elem, consumed, err := decodeRLP(data[totalConsumed:])
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("invalid rlp data: cannot decode list element: %w", err)
|
||||
}
|
||||
totalConsumed += consumed
|
||||
result = append(result, elem)
|
||||
}
|
||||
if totalConsumed != length {
|
||||
return nil, xerrors.Errorf("invalid rlp data: incorrect list length")
|
||||
}
|
||||
return result, nil
|
||||
}
|
175
api/rlp_test.go
Normal file
175
api/rlp_test.go
Normal file
@ -0,0 +1,175 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestEncode(t *testing.T) {
|
||||
testcases := []TestCase{
|
||||
{[]byte(""), mustDecodeHex("0x80")},
|
||||
{mustDecodeHex("0x01"), mustDecodeHex("0x01")},
|
||||
{mustDecodeHex("0xaa"), mustDecodeHex("0x81aa")},
|
||||
{mustDecodeHex("0x0402"), mustDecodeHex("0x820402")},
|
||||
{
|
||||
[]interface{}{},
|
||||
mustDecodeHex("0xc0"),
|
||||
},
|
||||
{
|
||||
mustDecodeHex("0xabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"),
|
||||
mustDecodeHex("0xb83cabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"),
|
||||
},
|
||||
{
|
||||
mustDecodeHex("0xabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"),
|
||||
mustDecodeHex("0xb8aaabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"),
|
||||
},
|
||||
{
|
||||
[]interface{}{
|
||||
mustDecodeHex("0xaaaa"),
|
||||
mustDecodeHex("0xbbbb"),
|
||||
mustDecodeHex("0xcccc"),
|
||||
mustDecodeHex("0xdddd"),
|
||||
},
|
||||
mustDecodeHex("0xcc82aaaa82bbbb82cccc82dddd"),
|
||||
},
|
||||
{
|
||||
[]interface{}{
|
||||
mustDecodeHex("0xaaaaaaaaaaaaaaaaaaaa"),
|
||||
mustDecodeHex("0xbbbbbbbbbbbbbbbbbbbb"),
|
||||
[]interface{}{
|
||||
mustDecodeHex("0xc1c1c1c1c1c1c1c1c1c1"),
|
||||
mustDecodeHex("0xc2c2c2c2c2c2c2c2c2c2"),
|
||||
mustDecodeHex("0xc3c3c3c3c3c3c3c3c3c3"),
|
||||
},
|
||||
mustDecodeHex("0xdddddddddddddddddddd"),
|
||||
mustDecodeHex("0xeeeeeeeeeeeeeeeeeeee"),
|
||||
mustDecodeHex("0xffffffffffffffffffff"),
|
||||
},
|
||||
mustDecodeHex("0xf8598aaaaaaaaaaaaaaaaaaaaa8abbbbbbbbbbbbbbbbbbbbe18ac1c1c1c1c1c1c1c1c1c18ac2c2c2c2c2c2c2c2c2c28ac3c3c3c3c3c3c3c3c3c38adddddddddddddddddddd8aeeeeeeeeeeeeeeeeeeee8affffffffffffffffffff"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
result, err := EncodeRLP(tc.Input)
|
||||
require.Nil(t, err)
|
||||
|
||||
require.Equal(t, tc.Output.([]byte), result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeString(t *testing.T) {
|
||||
testcases := []TestCase{
|
||||
{"0x00", "0x00"},
|
||||
{"0x80", "0x"},
|
||||
{"0x0f", "0x0f"},
|
||||
{"0x81aa", "0xaa"},
|
||||
{"0x820400", "0x0400"},
|
||||
{"0xb83cabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
|
||||
"0xabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
input, err := hex.DecodeString(strings.Replace(tc.Input.(string), "0x", "", -1))
|
||||
require.Nil(t, err)
|
||||
|
||||
output, err := hex.DecodeString(strings.Replace(tc.Output.(string), "0x", "", -1))
|
||||
require.Nil(t, err)
|
||||
|
||||
result, err := DecodeRLP(input)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, output, result.([]byte))
|
||||
}
|
||||
}
|
||||
|
||||
func mustDecodeHex(s string) []byte {
|
||||
d, err := hex.DecodeString(strings.Replace(s, "0x", "", -1))
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("err must be nil: %w", err))
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func TestDecodeList(t *testing.T) {
|
||||
testcases := []TestCase{
|
||||
{"0xc0", []interface{}{}},
|
||||
{"0xc100", []interface{}{[]byte{0}}},
|
||||
{"0xc3000102", []interface{}{[]byte{0}, []byte{1}, []byte{2}}},
|
||||
{"0xc4000181aa", []interface{}{[]byte{0}, []byte{1}, []byte{0xaa}}},
|
||||
{"0xc6000181aa81ff", []interface{}{[]byte{0}, []byte{1}, []byte{0xaa}, []byte{0xff}}},
|
||||
{"0xf8428aabcdabcdabcdabcdabcd8aabcdabcdabcdabcdabcd8aabcdabcdabcdabcdabcd8aabcdabcdabcdabcdabcd8aabcdabcdabcdabcdabcd8aabcdabcdabcdabcdabcd",
|
||||
[]interface{}{
|
||||
mustDecodeHex("0xabcdabcdabcdabcdabcd"),
|
||||
mustDecodeHex("0xabcdabcdabcdabcdabcd"),
|
||||
mustDecodeHex("0xabcdabcdabcdabcdabcd"),
|
||||
mustDecodeHex("0xabcdabcdabcdabcdabcd"),
|
||||
mustDecodeHex("0xabcdabcdabcdabcdabcd"),
|
||||
mustDecodeHex("0xabcdabcdabcdabcdabcd"),
|
||||
},
|
||||
},
|
||||
{"0xf1030185012a05f2008504a817c800825208942b87d1cb599bc2a606db9a0169fcec96af04ad3a880de0b6b3a764000080c0",
|
||||
[]interface{}{
|
||||
[]byte{3},
|
||||
[]byte{1},
|
||||
mustDecodeHex("0x012a05f200"),
|
||||
mustDecodeHex("0x04a817c800"),
|
||||
mustDecodeHex("0x5208"),
|
||||
mustDecodeHex("0x2b87d1CB599Bc2a606Db9A0169fcEc96Af04ad3a"),
|
||||
mustDecodeHex("0x0de0b6b3a7640000"),
|
||||
[]byte{},
|
||||
[]interface{}{},
|
||||
}},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
input, err := hex.DecodeString(strings.Replace(tc.Input.(string), "0x", "", -1))
|
||||
require.Nil(t, err)
|
||||
|
||||
result, err := DecodeRLP(input)
|
||||
require.Nil(t, err)
|
||||
|
||||
fmt.Println(result)
|
||||
r := result.([]interface{})
|
||||
require.Equal(t, len(tc.Output.([]interface{})), len(r))
|
||||
|
||||
for i, v := range r {
|
||||
require.Equal(t, tc.Output.([]interface{})[i], v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeEncodeTx(t *testing.T) {
|
||||
testcases := [][]byte{
|
||||
mustDecodeHex("0xdc82013a0185012a05f2008504a817c8008080872386f26fc1000000c0"),
|
||||
mustDecodeHex("0xf85f82013a0185012a05f2008504a817c8008080872386f26fc1000000c001a027fa36fb9623e4d71fcdd7f7dce71eb814c9560dcf3908c1719386e2efd122fba05fb4e4227174eeb0ba84747a4fb883c8d4e0fdb129c4b1f42e90282c41480234"),
|
||||
mustDecodeHex("0xf9061c82013a0185012a05f2008504a817c8008080872386f26fc10000b905bb608060405234801561001057600080fd5b506127106000803273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610556806100656000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80637bd703e81461004657806390b98a1114610076578063f8b2cb4f146100a6575b600080fd5b610060600480360381019061005b919061030a565b6100d6565b60405161006d9190610350565b60405180910390f35b610090600480360381019061008b9190610397565b6100f4565b60405161009d91906103f2565b60405180910390f35b6100c060048036038101906100bb919061030a565b61025f565b6040516100cd9190610350565b60405180910390f35b600060026100e38361025f565b6100ed919061043c565b9050919050565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156101455760009050610259565b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546101939190610496565b92505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546101e891906104ca565b925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161024c9190610350565b60405180910390a3600190505b92915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102d7826102ac565b9050919050565b6102e7816102cc565b81146102f257600080fd5b50565b600081359050610304816102de565b92915050565b6000602082840312156103205761031f6102a7565b5b600061032e848285016102f5565b91505092915050565b6000819050919050565b61034a81610337565b82525050565b60006020820190506103656000830184610341565b92915050565b61037481610337565b811461037f57600080fd5b50565b6000813590506103918161036b565b92915050565b600080604083850312156103ae576103ad6102a7565b5b60006103bc858286016102f5565b92505060206103cd85828601610382565b9150509250929050565b60008115159050919050565b6103ec816103d7565b82525050565b600060208201905061040760008301846103e3565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061044782610337565b915061045283610337565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561048b5761048a61040d565b5b828202905092915050565b60006104a182610337565b91506104ac83610337565b9250828210156104bf576104be61040d565b5b828203905092915050565b60006104d582610337565b91506104e083610337565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156105155761051461040d565b5b82820190509291505056fea26469706673582212208e5b4b874c839967f88008ed2fa42d6c2d9c9b0ae05d1d2c61faa7d229c134e664736f6c634300080d0033c080a0c4e9477f57c6848b2f1ea73a14809c1f44529d20763c947f3ac8ffd3d1629d93a011485a215457579bb13ac7b53bb9d6804763ae6fe5ce8ddd41642cea55c9a09a"),
|
||||
mustDecodeHex("0xf9063082013a0185012a05f2008504a817c8008094025b594a4f1c4888cafcfaf2bb24ed95507749e0872386f26fc10000b905bb608060405234801561001057600080fd5b506127106000803273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610556806100656000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80637bd703e81461004657806390b98a1114610076578063f8b2cb4f146100a6575b600080fd5b610060600480360381019061005b919061030a565b6100d6565b60405161006d9190610350565b60405180910390f35b610090600480360381019061008b9190610397565b6100f4565b60405161009d91906103f2565b60405180910390f35b6100c060048036038101906100bb919061030a565b61025f565b6040516100cd9190610350565b60405180910390f35b600060026100e38361025f565b6100ed919061043c565b9050919050565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156101455760009050610259565b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546101939190610496565b92505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546101e891906104ca565b925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161024c9190610350565b60405180910390a3600190505b92915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102d7826102ac565b9050919050565b6102e7816102cc565b81146102f257600080fd5b50565b600081359050610304816102de565b92915050565b6000602082840312156103205761031f6102a7565b5b600061032e848285016102f5565b91505092915050565b6000819050919050565b61034a81610337565b82525050565b60006020820190506103656000830184610341565b92915050565b61037481610337565b811461037f57600080fd5b50565b6000813590506103918161036b565b92915050565b600080604083850312156103ae576103ad6102a7565b5b60006103bc858286016102f5565b92505060206103cd85828601610382565b9150509250929050565b60008115159050919050565b6103ec816103d7565b82525050565b600060208201905061040760008301846103e3565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061044782610337565b915061045283610337565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561048b5761048a61040d565b5b828202905092915050565b60006104a182610337565b91506104ac83610337565b9250828210156104bf576104be61040d565b5b828203905092915050565b60006104d582610337565b91506104e083610337565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156105155761051461040d565b5b82820190509291505056fea26469706673582212208e5b4b874c839967f88008ed2fa42d6c2d9c9b0ae05d1d2c61faa7d229c134e664736f6c634300080d0033c080a0fe38720928596f9e9dfbf891d00311638efce3713f03cdd67b212ecbbcf18f29a05993e656c0b35b8a580da6aff7c89b3d3e8b1c6f83a7ce09473c0699a8500b9c"),
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
decoded, err := DecodeRLP(tc)
|
||||
require.Nil(t, err)
|
||||
|
||||
encoded, err := EncodeRLP(decoded)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, tc, encoded)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeError(t *testing.T) {
|
||||
testcases := [][]byte{
|
||||
mustDecodeHex("0xdc82013a0185012a05f2008504a817c8008080872386f26fc1000000"),
|
||||
mustDecodeHex("0xdc013a01012a05f2008504a817c8008080872386f26fc1000000"),
|
||||
mustDecodeHex("0xdc82013a0185012a05f28504a817c08080872386f26fc1000000"),
|
||||
mustDecodeHex("0xdc82013a0185012a05f504a817c080872386ffc1000000"),
|
||||
mustDecodeHex("0x013a018505f2008504a817c8008080872386f26fc1000000"),
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
_, err := DecodeRLP(tc)
|
||||
require.NotNil(t, err, hex.EncodeToString(tc))
|
||||
}
|
||||
}
|
@ -26,6 +26,7 @@ import (
|
||||
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
"github.com/filecoin-project/specs-actors/v7/actors/runtime/proof"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
bstore "github.com/filecoin-project/lotus/blockstore"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain"
|
||||
@ -543,7 +544,7 @@ func (filec *FilecoinEC) checkBlockMessages(ctx context.Context, b *types.FullBl
|
||||
smArr := blockadt.MakeEmptyArray(tmpstore)
|
||||
for i, m := range b.SecpkMessages {
|
||||
if filec.sm.GetNetworkVersion(ctx, b.Header.Height) >= network.Version14 {
|
||||
if m.Signature.Type != crypto.SigTypeSecp256k1 {
|
||||
if m.Signature.Type != crypto.SigTypeSecp256k1 && m.Signature.Type != crypto.SigTypeDelegated {
|
||||
return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
@ -559,7 +560,20 @@ func (filec *FilecoinEC) checkBlockMessages(ctx context.Context, b *types.FullBl
|
||||
return xerrors.Errorf("failed to resolve key addr: %w", err)
|
||||
}
|
||||
|
||||
if err := sigs.Verify(&m.Signature, kaddr, m.Message.Cid().Bytes()); err != nil {
|
||||
digest := m.Message.Cid().Bytes()
|
||||
if m.Signature.Type == crypto.SigTypeDelegated {
|
||||
txArgs, err := api.NewEthTxArgsFromMessage(&m.Message)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msg, err := txArgs.OriginalRlpMsg()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
digest = msg
|
||||
}
|
||||
|
||||
if err := sigs.Verify(&m.Signature, kaddr, digest); err != nil {
|
||||
return xerrors.Errorf("secpk message %s has invalid signature: %w", m.Cid(), err)
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@ func (filec *FilecoinEC) CreateBlock(ctx context.Context, w api.Wallet, bt *api.
|
||||
}
|
||||
|
||||
blsMsgCids = append(blsMsgCids, c)
|
||||
} else if msg.Signature.Type == crypto.SigTypeSecp256k1 {
|
||||
} else if msg.Signature.Type == crypto.SigTypeSecp256k1 || msg.Signature.Type == crypto.SigTypeDelegated {
|
||||
c, err := filec.sm.ChainStore().PutMessage(ctx, msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -3,6 +3,7 @@ package messagepool
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
@ -770,6 +771,16 @@ func sigCacheKey(m *types.SignedMessage) (string, error) {
|
||||
return string(hashCache[:]), nil
|
||||
case crypto.SigTypeSecp256k1:
|
||||
return string(m.Cid().Bytes()), nil
|
||||
case crypto.SigTypeDelegated:
|
||||
txArgs, err := api.NewEthTxArgsFromMessage(&m.Message)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
msg, err := txArgs.HashedOriginalRlpMsg()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return hex.EncodeToString(msg), nil
|
||||
default:
|
||||
return "", xerrors.Errorf("unrecognized signature type: %d", m.Signature.Type)
|
||||
}
|
||||
@ -787,7 +798,19 @@ func (mp *MessagePool) VerifyMsgSig(m *types.SignedMessage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := sigs.Verify(&m.Signature, m.Message.From, m.Message.Cid().Bytes()); err != nil {
|
||||
if m.Signature.Type == crypto.SigTypeDelegated {
|
||||
txArgs, err := api.NewEthTxArgsFromMessage(&m.Message)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msg, err := txArgs.OriginalRlpMsg()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := sigs.Verify(&m.Signature, m.Message.From, msg); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err := sigs.Verify(&m.Signature, m.Message.From, m.Message.Cid().Bytes()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,7 @@ func (sm *selectedMessages) tryToAdd(mc *msgChain) bool {
|
||||
sm.msgs = append(sm.msgs, mc.msgs...)
|
||||
sm.blsLimit -= l
|
||||
sm.gasLimit -= mc.gasLimit
|
||||
} else if mc.sigType == crypto.SigTypeSecp256k1 {
|
||||
} else if mc.sigType == crypto.SigTypeSecp256k1 || mc.sigType == crypto.SigTypeDelegated {
|
||||
if sm.secpLimit < l {
|
||||
return false
|
||||
}
|
||||
@ -123,7 +123,7 @@ func (sm *selectedMessages) tryToAddWithDeps(mc *msgChain, mp *MessagePool, base
|
||||
|
||||
if mc.sigType == crypto.SigTypeBLS {
|
||||
smMsgLimit = sm.blsLimit
|
||||
} else if mc.sigType == crypto.SigTypeSecp256k1 {
|
||||
} else if mc.sigType == crypto.SigTypeSecp256k1 || mc.sigType == crypto.SigTypeDelegated {
|
||||
smMsgLimit = sm.secpLimit
|
||||
} else {
|
||||
return false
|
||||
@ -174,7 +174,7 @@ func (sm *selectedMessages) tryToAddWithDeps(mc *msgChain, mp *MessagePool, base
|
||||
|
||||
if mc.sigType == crypto.SigTypeBLS {
|
||||
sm.blsLimit -= chainMsgLimit
|
||||
} else if mc.sigType == crypto.SigTypeSecp256k1 {
|
||||
} else if mc.sigType == crypto.SigTypeSecp256k1 || mc.sigType == crypto.SigTypeDelegated {
|
||||
sm.secpLimit -= chainMsgLimit
|
||||
}
|
||||
|
||||
@ -187,7 +187,7 @@ func (sm *selectedMessages) trimChain(mc *msgChain, mp *MessagePool, baseFee typ
|
||||
if msgLimit > sm.blsLimit {
|
||||
msgLimit = sm.blsLimit
|
||||
}
|
||||
} else if mc.sigType == crypto.SigTypeSecp256k1 {
|
||||
} else if mc.sigType == crypto.SigTypeSecp256k1 || mc.sigType == crypto.SigTypeDelegated {
|
||||
if msgLimit > sm.secpLimit {
|
||||
msgLimit = sm.secpLimit
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types/mock"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
)
|
||||
|
||||
|
@ -1145,7 +1145,7 @@ func persistMessages(ctx context.Context, bs bstore.Blockstore, bst *exchange.Co
|
||||
}
|
||||
}
|
||||
for _, m := range bst.Secpk {
|
||||
if m.Signature.Type != crypto.SigTypeSecp256k1 {
|
||||
if m.Signature.Type != crypto.SigTypeSecp256k1 && m.Signature.Type != crypto.SigTypeDelegated {
|
||||
return xerrors.Errorf("unknown signature type on message %s: %q", m.Cid(), m.Signature.Type)
|
||||
}
|
||||
//log.Infof("putting secp256k1 message: %s", m.Cid())
|
||||
|
@ -39,6 +39,8 @@ func (kt *KeyType) UnmarshalJSON(bb []byte) error {
|
||||
*kt = KTBLS
|
||||
case crypto.SigTypeSecp256k1:
|
||||
*kt = KTSecp256k1
|
||||
case crypto.SigTypeDelegated:
|
||||
*kt = KTDelegated
|
||||
default:
|
||||
return fmt.Errorf("unknown sigtype: %d", bst)
|
||||
}
|
||||
@ -51,6 +53,7 @@ const (
|
||||
KTBLS KeyType = "bls"
|
||||
KTSecp256k1 KeyType = "secp256k1"
|
||||
KTSecp256k1Ledger KeyType = "secp256k1-ledger"
|
||||
KTDelegated KeyType = "delegated"
|
||||
)
|
||||
|
||||
// KeyInfo is used for storing keys in KeyStore
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/vectors"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
)
|
||||
|
||||
|
@ -111,6 +111,7 @@ var Prices = map[abi.ChainEpoch]Pricelist{
|
||||
verifySignature: map[crypto.SigType]int64{
|
||||
crypto.SigTypeBLS: 16598605,
|
||||
crypto.SigTypeSecp256k1: 1637292,
|
||||
crypto.SigTypeDelegated: 1637292,
|
||||
},
|
||||
|
||||
hashingBase: 31355,
|
||||
|
@ -45,7 +45,7 @@ func NewKey(keyinfo types.KeyInfo) (*Key, error) {
|
||||
}
|
||||
|
||||
switch k.Type {
|
||||
case types.KTSecp256k1:
|
||||
case types.KTSecp256k1, types.KTDelegated:
|
||||
k.Address, err = address.NewSecp256k1Address(k.PublicKey)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("converting Secp256k1 to address: %w", err)
|
||||
@ -68,6 +68,8 @@ func ActSigType(typ types.KeyType) crypto.SigType {
|
||||
return crypto.SigTypeBLS
|
||||
case types.KTSecp256k1:
|
||||
return crypto.SigTypeSecp256k1
|
||||
case types.KTDelegated:
|
||||
return crypto.SigTypeDelegated
|
||||
default:
|
||||
return crypto.SigTypeUnknown
|
||||
}
|
||||
|
@ -16,7 +16,8 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/wallet/key"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls" // enable bls signatures
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls" // enable bls signatures
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp" // enable secp signatures
|
||||
)
|
||||
|
||||
|
@ -41,6 +41,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
"github.com/filecoin-project/lotus/storage/sealer/ffiwrapper"
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
)
|
||||
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
"github.com/filecoin-project/lotus/chain/wallet/key"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
"github.com/filecoin-project/lotus/node/modules"
|
||||
"github.com/filecoin-project/lotus/node/modules/lp2p"
|
||||
|
@ -27,7 +27,8 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/conformance/chaos"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls" // enable bls signatures
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls" // enable bls signatures
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp" // enable secp signatures
|
||||
"github.com/filecoin-project/lotus/storage/sealer/ffiwrapper"
|
||||
)
|
||||
|
@ -2186,7 +2186,7 @@ Inputs:
|
||||
[
|
||||
{
|
||||
"from": "0x0707070707070707070707070707070707070707",
|
||||
"to": "0x0707070707070707070707070707070707070707",
|
||||
"to": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031",
|
||||
"gas": "0x5",
|
||||
"gasPrice": "0x0",
|
||||
"value": "0x0",
|
||||
@ -2217,13 +2217,12 @@ Inputs:
|
||||
[
|
||||
{
|
||||
"from": "0x0707070707070707070707070707070707070707",
|
||||
"to": "0x0707070707070707070707070707070707070707",
|
||||
"to": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031",
|
||||
"gas": "0x5",
|
||||
"gasPrice": "0x0",
|
||||
"value": "0x0",
|
||||
"data": "0x07"
|
||||
},
|
||||
"string value"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
@ -2302,7 +2301,7 @@ Perms: read
|
||||
Inputs:
|
||||
```json
|
||||
[
|
||||
"0x5",
|
||||
"string value",
|
||||
true
|
||||
]
|
||||
```
|
||||
@ -2412,7 +2411,7 @@ Response:
|
||||
```json
|
||||
{
|
||||
"chainId": "0x5",
|
||||
"nonce": 42,
|
||||
"nonce": "0x5",
|
||||
"hash": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||
"blockHash": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||
"blockNumber": "0x5",
|
||||
@ -2423,11 +2422,12 @@ Response:
|
||||
"type": "0x5",
|
||||
"input": "0x07",
|
||||
"gas": "0x5",
|
||||
"gasLimit": "0x5",
|
||||
"maxFeePerGas": "0x0",
|
||||
"maxPriorityFeePerGas": "0x0",
|
||||
"v": "0x0",
|
||||
"r": "0x0",
|
||||
"s": "0x0"
|
||||
"v": "0x07",
|
||||
"r": "0x07",
|
||||
"s": "0x07"
|
||||
}
|
||||
```
|
||||
|
||||
@ -2448,7 +2448,7 @@ Response:
|
||||
```json
|
||||
{
|
||||
"chainId": "0x5",
|
||||
"nonce": 42,
|
||||
"nonce": "0x5",
|
||||
"hash": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||
"blockHash": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||
"blockNumber": "0x5",
|
||||
@ -2459,11 +2459,12 @@ Response:
|
||||
"type": "0x5",
|
||||
"input": "0x07",
|
||||
"gas": "0x5",
|
||||
"gasLimit": "0x5",
|
||||
"maxFeePerGas": "0x0",
|
||||
"maxPriorityFeePerGas": "0x0",
|
||||
"v": "0x0",
|
||||
"r": "0x0",
|
||||
"s": "0x0"
|
||||
"v": "0x07",
|
||||
"r": "0x07",
|
||||
"s": "0x07"
|
||||
}
|
||||
```
|
||||
|
||||
@ -2475,7 +2476,7 @@ Perms: read
|
||||
Inputs:
|
||||
```json
|
||||
[
|
||||
"0x0707070707070707070707070707070707070707070707070707070707070707"
|
||||
"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"
|
||||
]
|
||||
```
|
||||
|
||||
@ -2483,7 +2484,7 @@ Response:
|
||||
```json
|
||||
{
|
||||
"chainId": "0x5",
|
||||
"nonce": 42,
|
||||
"nonce": "0x5",
|
||||
"hash": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||
"blockHash": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||
"blockNumber": "0x5",
|
||||
@ -2494,11 +2495,12 @@ Response:
|
||||
"type": "0x5",
|
||||
"input": "0x07",
|
||||
"gas": "0x5",
|
||||
"gasLimit": "0x5",
|
||||
"maxFeePerGas": "0x0",
|
||||
"maxPriorityFeePerGas": "0x0",
|
||||
"v": "0x0",
|
||||
"r": "0x0",
|
||||
"s": "0x0"
|
||||
"v": "0x07",
|
||||
"r": "0x07",
|
||||
"s": "0x07"
|
||||
}
|
||||
```
|
||||
|
||||
@ -2533,7 +2535,7 @@ Response:
|
||||
```json
|
||||
{
|
||||
"transactionHash": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||
"transacionIndex": "0x5",
|
||||
"transactionIndex": "0x5",
|
||||
"blockHash": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||
"blockNumber": "0x5",
|
||||
"from": "0x0707070707070707070707070707070707070707",
|
||||
@ -2543,7 +2545,11 @@ Response:
|
||||
"contractAddress": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031",
|
||||
"cumulativeGasUsed": "0x5",
|
||||
"gasUsed": "0x5",
|
||||
"effectiveGasPrice": "0x0"
|
||||
"effectiveGasPrice": "0x0",
|
||||
"logsBloom": "0x07",
|
||||
"logs": [
|
||||
"string value"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
"github.com/filecoin-project/lotus/metrics"
|
||||
"github.com/filecoin-project/lotus/node/impl/full"
|
||||
|
2
go.sum
2
go.sum
@ -345,6 +345,8 @@ github.com/filecoin-project/go-state-types v0.1.8/go.mod h1:UwGVoMsULoCK+bWjEdd/
|
||||
github.com/filecoin-project/go-state-types v0.1.10/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q=
|
||||
github.com/filecoin-project/go-state-types v0.9.10-0.20221109071515-5536f160fe27 h1:1/o3al2zThas9rW6xqPKAzjs4q2tiBHaBNBP2sx0Vc4=
|
||||
github.com/filecoin-project/go-state-types v0.9.10-0.20221109071515-5536f160fe27/go.mod h1:7ty480tvttEAqWKywhAaDCElk7ksTqEXtXWAzTSdEKo=
|
||||
github.com/filecoin-project/go-state-types v0.1.11-0.20220923222823-af1291888ee8 h1:iu/6jTVXyZDN/RBh2M2+K0i1ML+4DxydDJ/Bm7BjhjA=
|
||||
github.com/filecoin-project/go-state-types v0.1.11-0.20220923222823-af1291888ee8/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q=
|
||||
github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig=
|
||||
github.com/filecoin-project/go-statemachine v1.0.2 h1:421SSWBk8GIoCoWYYTE/d+qCWccgmRH0uXotXRDjUbc=
|
||||
github.com/filecoin-project/go-statemachine v1.0.2/go.mod h1:jZdXXiHa61n4NmgWFG4w8tnqgvZVHYbJ3yW7+y8bF54=
|
||||
|
57
lib/sigs/delegated/init.go
Normal file
57
lib/sigs/delegated/init.go
Normal file
@ -0,0 +1,57 @@
|
||||
package delegated
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/crypto/sha3"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
gocrypto "github.com/filecoin-project/go-crypto"
|
||||
crypto1 "github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
)
|
||||
|
||||
type delegatedSigner struct{}
|
||||
|
||||
func (delegatedSigner) GenPrivate() ([]byte, error) {
|
||||
priv, err := gocrypto.GenerateKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return priv, nil
|
||||
}
|
||||
|
||||
func (delegatedSigner) ToPublic(pk []byte) ([]byte, error) {
|
||||
return gocrypto.PublicKey(pk), nil
|
||||
}
|
||||
|
||||
func (delegatedSigner) Sign(pk []byte, msg []byte) ([]byte, error) {
|
||||
return nil, fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
func (delegatedSigner) Verify(sig []byte, a address.Address, msg []byte) error {
|
||||
hasher := sha3.NewLegacyKeccak256()
|
||||
hasher.Write(msg)
|
||||
hash := hasher.Sum(nil)
|
||||
|
||||
pubk, err := gocrypto.EcRecover(hash, sig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
maybeaddr, err := address.NewSecp256k1Address(pubk)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if maybeaddr != a {
|
||||
return fmt.Errorf("signature did not match")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
sigs.RegisterSignature(crypto1.SigTypeDelegated, delegatedSigner{})
|
||||
}
|
@ -6,7 +6,7 @@ import (
|
||||
"github.com/minio/blake2b-simd"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-crypto"
|
||||
gocrypto "github.com/filecoin-project/go-crypto"
|
||||
crypto2 "github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
@ -15,7 +15,7 @@ import (
|
||||
type secpSigner struct{}
|
||||
|
||||
func (secpSigner) GenPrivate() ([]byte, error) {
|
||||
priv, err := crypto.GenerateKey()
|
||||
priv, err := gocrypto.GenerateKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -23,12 +23,12 @@ func (secpSigner) GenPrivate() ([]byte, error) {
|
||||
}
|
||||
|
||||
func (secpSigner) ToPublic(pk []byte) ([]byte, error) {
|
||||
return crypto.PublicKey(pk), nil
|
||||
return gocrypto.PublicKey(pk), nil
|
||||
}
|
||||
|
||||
func (secpSigner) Sign(pk []byte, msg []byte) ([]byte, error) {
|
||||
b2sum := blake2b.Sum256(msg)
|
||||
sig, err := crypto.Sign(pk, b2sum[:])
|
||||
sig, err := gocrypto.Sign(pk, b2sum[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -38,7 +38,7 @@ func (secpSigner) Sign(pk []byte, msg []byte) ([]byte, error) {
|
||||
|
||||
func (secpSigner) Verify(sig []byte, a address.Address, msg []byte) error {
|
||||
b2sum := blake2b.Sum256(msg)
|
||||
pubk, err := crypto.EcRecover(b2sum[:], sig)
|
||||
pubk, err := gocrypto.EcRecover(b2sum[:], sig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/lib/lotuslog"
|
||||
"github.com/filecoin-project/lotus/lib/peermgr"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
"github.com/filecoin-project/lotus/markets/storageadapter"
|
||||
"github.com/filecoin-project/lotus/node/config"
|
||||
|
@ -2,18 +2,25 @@ package full
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"go.uber.org/fx"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"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/v8/evm"
|
||||
init8 "github.com/filecoin-project/go-state-types/builtin/v8/init"
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
builtinactors "github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/messagepool"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
@ -27,10 +34,10 @@ type EthModuleAPI interface {
|
||||
EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum api.EthInt) (api.EthInt, error)
|
||||
EthGetBlockTransactionCountByHash(ctx context.Context, blkHash api.EthHash) (api.EthInt, error)
|
||||
EthGetBlockByHash(ctx context.Context, blkHash api.EthHash, fullTxInfo bool) (api.EthBlock, error)
|
||||
EthGetBlockByNumber(ctx context.Context, blkNum api.EthInt, fullTxInfo bool) (api.EthBlock, error)
|
||||
EthGetTransactionByHash(ctx context.Context, txHash api.EthHash) (api.EthTx, error)
|
||||
EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (api.EthBlock, error)
|
||||
EthGetTransactionByHash(ctx context.Context, txHash *api.EthHash) (*api.EthTx, error)
|
||||
EthGetTransactionCount(ctx context.Context, sender api.EthAddress, blkOpt string) (api.EthInt, error)
|
||||
EthGetTransactionReceipt(ctx context.Context, txHash api.EthHash) (api.EthTxReceipt, error)
|
||||
EthGetTransactionReceipt(ctx context.Context, txHash api.EthHash) (*api.EthTxReceipt, error)
|
||||
EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash api.EthHash, txIndex api.EthInt) (api.EthTx, error)
|
||||
EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum api.EthInt, txIndex api.EthInt) (api.EthTx, error)
|
||||
EthGetCode(ctx context.Context, address api.EthAddress) (string, error)
|
||||
@ -41,7 +48,7 @@ type EthModuleAPI interface {
|
||||
NetListening(ctx context.Context) (bool, error)
|
||||
EthProtocolVersion(ctx context.Context) (api.EthInt, error)
|
||||
EthGasPrice(ctx context.Context) (api.EthBigInt, error)
|
||||
EthEstimateGas(ctx context.Context, tx api.EthCall, blkParam string) (api.EthInt, error)
|
||||
EthEstimateGas(ctx context.Context, tx api.EthCall) (api.EthInt, error)
|
||||
EthCall(ctx context.Context, tx api.EthCall, blkParam string) (api.EthBytes, error)
|
||||
EthMaxPriorityFeePerGas(ctx context.Context) (api.EthBigInt, error)
|
||||
EthSendRawTransaction(ctx context.Context, rawTx api.EthBytes) (api.EthHash, error)
|
||||
@ -129,27 +136,38 @@ func (a *EthModule) EthGetBlockByHash(ctx context.Context, blkHash api.EthHash,
|
||||
return a.ethBlockFromFilecoinTipSet(ctx, ts, fullTxInfo)
|
||||
}
|
||||
|
||||
func (a *EthModule) EthGetBlockByNumber(ctx context.Context, blkNum api.EthInt, fullTxInfo bool) (api.EthBlock, error) {
|
||||
ts, err := a.Chain.GetTipsetByHeight(ctx, abi.ChainEpoch(blkNum), nil, false)
|
||||
func (a *EthModule) EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (api.EthBlock, error) {
|
||||
var num api.EthInt
|
||||
err := num.UnmarshalJSON([]byte(`"` + blkNum + `"`))
|
||||
if err != nil {
|
||||
num = api.EthInt(a.Chain.GetHeaviestTipSet().Height())
|
||||
}
|
||||
|
||||
ts, err := a.Chain.GetTipsetByHeight(ctx, abi.ChainEpoch(num), nil, false)
|
||||
if err != nil {
|
||||
return api.EthBlock{}, xerrors.Errorf("error loading tipset %s: %w", ts, err)
|
||||
}
|
||||
return a.ethBlockFromFilecoinTipSet(ctx, ts, fullTxInfo)
|
||||
}
|
||||
|
||||
func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash api.EthHash) (api.EthTx, error) {
|
||||
func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash *api.EthHash) (*api.EthTx, error) {
|
||||
// Ethereum's behavior is to return null when the txHash is invalid, so we use nil to check if txHash is valid
|
||||
if txHash == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
cid := txHash.ToCid()
|
||||
|
||||
msgLookup, err := a.StateAPI.StateSearchMsg(ctx, types.EmptyTSK, cid, api.LookbackNoLimit, true)
|
||||
if err != nil {
|
||||
return api.EthTx{}, nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
tx, err := a.ethTxFromFilecoinMessageLookup(ctx, msgLookup)
|
||||
if err != nil {
|
||||
return api.EthTx{}, err
|
||||
return nil, nil
|
||||
}
|
||||
return tx, nil
|
||||
return &tx, nil
|
||||
}
|
||||
|
||||
func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender api.EthAddress, blkParam string) (api.EthInt, error) {
|
||||
@ -164,29 +182,29 @@ func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender api.EthAd
|
||||
return api.EthInt(nonce), nil
|
||||
}
|
||||
|
||||
func (a *EthModule) EthGetTransactionReceipt(ctx context.Context, txHash api.EthHash) (api.EthTxReceipt, error) {
|
||||
func (a *EthModule) EthGetTransactionReceipt(ctx context.Context, txHash api.EthHash) (*api.EthTxReceipt, error) {
|
||||
cid := txHash.ToCid()
|
||||
|
||||
msgLookup, err := a.StateAPI.StateSearchMsg(ctx, types.EmptyTSK, cid, api.LookbackNoLimit, true)
|
||||
if err != nil {
|
||||
return api.EthTxReceipt{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tx, err := a.ethTxFromFilecoinMessageLookup(ctx, msgLookup)
|
||||
if err != nil {
|
||||
return api.EthTxReceipt{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
replay, err := a.StateAPI.StateReplay(ctx, types.EmptyTSK, cid)
|
||||
if err != nil {
|
||||
return api.EthTxReceipt{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
receipt, err := api.NewEthTxReceipt(tx, msgLookup, replay)
|
||||
if err != nil {
|
||||
return api.EthTxReceipt{}, err
|
||||
return nil, err
|
||||
}
|
||||
return receipt, nil
|
||||
return &receipt, nil
|
||||
}
|
||||
|
||||
func (a *EthModule) EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash api.EthHash, txIndex api.EthInt) (api.EthTx, error) {
|
||||
@ -267,24 +285,93 @@ func (a *EthModule) EthGasPrice(ctx context.Context) (api.EthBigInt, error) {
|
||||
}
|
||||
|
||||
func (a *EthModule) EthSendRawTransaction(ctx context.Context, rawTx api.EthBytes) (api.EthHash, error) {
|
||||
return api.EthHash{}, nil
|
||||
txArgs, err := api.ParseEthTxArgs(rawTx)
|
||||
if err != nil {
|
||||
return api.EmptyEthHash, err
|
||||
}
|
||||
|
||||
smsg, err := txArgs.ToSignedMessage()
|
||||
if err != nil {
|
||||
return api.EmptyEthHash, err
|
||||
}
|
||||
|
||||
cid, err := a.MpoolAPI.MpoolPush(ctx, smsg)
|
||||
if err != nil {
|
||||
return api.EmptyEthHash, err
|
||||
}
|
||||
return api.EthHashFromCid(cid)
|
||||
}
|
||||
|
||||
func (a *EthModule) applyEvmMsg(ctx context.Context, tx api.EthCall) (*api.InvocResult, error) {
|
||||
from, err := tx.From.ToFilecoinAddress()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// FIXME: this is a workaround, remove this when f4 address is ready
|
||||
var from address.Address
|
||||
var err error
|
||||
if tx.From[0] == 0xff && tx.From[1] == 0 && tx.From[2] == 0 {
|
||||
addr, err := tx.From.ToFilecoinAddress()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
from = addr
|
||||
} else {
|
||||
id := uint64(100)
|
||||
for ; id < 300; id++ {
|
||||
idAddr, err := address.NewIDAddress(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
from = idAddr
|
||||
act, err := a.StateGetActor(ctx, idAddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if builtinactors.IsAccountActor(act.Code) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if id == 300 {
|
||||
return nil, fmt.Errorf("cannot find a dummy account")
|
||||
}
|
||||
}
|
||||
to, err := tx.To.ToFilecoinAddress()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("cannot get Filecoin address: %w", err)
|
||||
|
||||
var params []byte
|
||||
var to address.Address
|
||||
if tx.To == nil {
|
||||
to = builtintypes.InitActorAddr
|
||||
constructorParams, err := actors.SerializeParams(&evm.ConstructorParams{
|
||||
Bytecode: tx.Data,
|
||||
InputData: []byte{},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to serialize constructor params: %w", err)
|
||||
}
|
||||
|
||||
evmActorCid, ok := actors.GetActorCodeID(actors.Version8, "evm")
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to lookup evm actor code CID")
|
||||
}
|
||||
|
||||
params, err = actors.SerializeParams(&init8.ExecParams{
|
||||
CodeCID: evmActorCid,
|
||||
ConstructorParams: constructorParams,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to serialize init actor exec params: %w", err)
|
||||
}
|
||||
} else {
|
||||
addr, err := tx.To.ToFilecoinAddress()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("cannot get Filecoin address: %w", err)
|
||||
}
|
||||
to = addr
|
||||
params = tx.Data
|
||||
}
|
||||
|
||||
msg := &types.Message{
|
||||
From: from,
|
||||
To: to,
|
||||
Value: big.Int(tx.Value),
|
||||
Method: abi.MethodNum(2),
|
||||
Params: tx.Data,
|
||||
Params: params,
|
||||
GasLimit: build.BlockGasLimit,
|
||||
GasFeeCap: big.Zero(),
|
||||
GasPremium: big.Zero(),
|
||||
@ -312,7 +399,7 @@ func (a *EthModule) applyEvmMsg(ctx context.Context, tx api.EthCall) (*api.Invoc
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (a *EthModule) EthEstimateGas(ctx context.Context, tx api.EthCall, blkParam string) (api.EthInt, error) {
|
||||
func (a *EthModule) EthEstimateGas(ctx context.Context, tx api.EthCall) (api.EthInt, error) {
|
||||
invokeResult, err := a.applyEvmMsg(ctx, tx)
|
||||
if err != nil {
|
||||
return api.EthInt(0), err
|
||||
@ -388,6 +475,9 @@ func (a *EthModule) ethBlockFromFilecoinTipSet(ctx context.Context, ts *types.Ti
|
||||
}
|
||||
|
||||
func (a *EthModule) ethTxFromFilecoinMessageLookup(ctx context.Context, msgLookup *api.MsgLookup) (api.EthTx, error) {
|
||||
if msgLookup == nil {
|
||||
return api.EthTx{}, fmt.Errorf("msg does not exist")
|
||||
}
|
||||
cid := msgLookup.Message
|
||||
txHash, err := api.EthHashFromCid(cid)
|
||||
if err != nil {
|
||||
@ -447,9 +537,9 @@ func (a *EthModule) ethTxFromFilecoinMessageLookup(ctx context.Context, msgLooku
|
||||
Gas: api.EthInt(msg.GasLimit),
|
||||
MaxFeePerGas: api.EthBigInt(msg.GasFeeCap),
|
||||
MaxPriorityFeePerGas: api.EthBigInt(msg.GasPremium),
|
||||
V: api.EthBigIntZero,
|
||||
R: api.EthBigIntZero,
|
||||
S: api.EthBigIntZero,
|
||||
V: api.EthBytes{},
|
||||
R: api.EthBytes{},
|
||||
S: api.EthBytes{},
|
||||
Input: msg.Params,
|
||||
}
|
||||
return tx, nil
|
||||
|
Loading…
Reference in New Issue
Block a user