api: ethrpc: implement eth_sendRawTransaction (#9334)
Co-authored-by: Raúl Kripalani <raul@protocol.ai>
This commit is contained in:
parent
c3ee957cc6
commit
9d1208c9ff
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
@ -36,6 +36,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"
|
||||
|
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))
|
||||
}
|
||||
}
|
@ -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
|
||||
)
|
||||
|
||||
|
@ -42,6 +42,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"
|
||||
|
@ -26,7 +26,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"
|
||||
)
|
||||
|
@ -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"
|
||||
|
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"
|
||||
|
Loading…
Reference in New Issue
Block a user