Merge branch 'feat/nv18-events' into raulk/events-integrate-fvm
This commit is contained in:
commit
28ec43cdea
@ -916,6 +916,11 @@ workflows:
|
|||||||
suite: itest-dup_mpool_messages
|
suite: itest-dup_mpool_messages
|
||||||
target: "./itests/dup_mpool_messages_test.go"
|
target: "./itests/dup_mpool_messages_test.go"
|
||||||
|
|
||||||
|
- test:
|
||||||
|
name: test-itest-fevm
|
||||||
|
suite: itest-fevm
|
||||||
|
target: "./itests/fevm_test.go"
|
||||||
|
|
||||||
- test:
|
- test:
|
||||||
name: test-itest-gas_estimation
|
name: test-itest-gas_estimation
|
||||||
suite: itest-gas_estimation
|
suite: itest-gas_estimation
|
||||||
|
@ -372,7 +372,7 @@ func init() {
|
|||||||
addExample(ðint)
|
addExample(ðint)
|
||||||
ethaddr, _ := api.EthAddressFromHex("0x5CbEeCF99d3fDB3f25E309Cc264f240bb0664031")
|
ethaddr, _ := api.EthAddressFromHex("0x5CbEeCF99d3fDB3f25E309Cc264f240bb0664031")
|
||||||
addExample(ðaddr)
|
addExample(ðaddr)
|
||||||
ethhash, _ := api.EthHashFromCid(c)
|
ethhash, _ := api.NewEthHashFromCid(c)
|
||||||
addExample(ðhash)
|
addExample(ðhash)
|
||||||
|
|
||||||
ethFeeHistoryReward := [][]api.EthBigInt{}
|
ethFeeHistoryReward := [][]api.EthBigInt{}
|
||||||
|
@ -37,7 +37,6 @@ type EthTx struct {
|
|||||||
Type EthUint64 `json:"type"`
|
Type EthUint64 `json:"type"`
|
||||||
Input EthBytes `json:"input"`
|
Input EthBytes `json:"input"`
|
||||||
Gas EthUint64 `json:"gas"`
|
Gas EthUint64 `json:"gas"`
|
||||||
GasLimit *EthUint64 `json:"gasLimit,omitempty"`
|
|
||||||
MaxFeePerGas EthBigInt `json:"maxFeePerGas"`
|
MaxFeePerGas EthBigInt `json:"maxFeePerGas"`
|
||||||
MaxPriorityFeePerGas EthBigInt `json:"maxPriorityFeePerGas"`
|
MaxPriorityFeePerGas EthBigInt `json:"maxPriorityFeePerGas"`
|
||||||
V EthBytes `json:"v"`
|
V EthBytes `json:"v"`
|
||||||
|
@ -110,6 +110,7 @@ func (e *EthBytes) UnmarshalJSON(b []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type EthBlock struct {
|
type EthBlock struct {
|
||||||
|
Hash EthHash `json:"hash"`
|
||||||
ParentHash EthHash `json:"parentHash"`
|
ParentHash EthHash `json:"parentHash"`
|
||||||
Sha3Uncles EthHash `json:"sha3Uncles"`
|
Sha3Uncles EthHash `json:"sha3Uncles"`
|
||||||
Miner EthAddress `json:"miner"`
|
Miner EthAddress `json:"miner"`
|
||||||
@ -118,6 +119,7 @@ type EthBlock struct {
|
|||||||
ReceiptsRoot EthHash `json:"receiptsRoot"`
|
ReceiptsRoot EthHash `json:"receiptsRoot"`
|
||||||
// TODO: include LogsBloom
|
// TODO: include LogsBloom
|
||||||
Difficulty EthUint64 `json:"difficulty"`
|
Difficulty EthUint64 `json:"difficulty"`
|
||||||
|
TotalDifficulty EthUint64 `json:"totalDifficulty"`
|
||||||
Number EthUint64 `json:"number"`
|
Number EthUint64 `json:"number"`
|
||||||
GasLimit EthUint64 `json:"gasLimit"`
|
GasLimit EthUint64 `json:"gasLimit"`
|
||||||
GasUsed EthUint64 `json:"gasUsed"`
|
GasUsed EthUint64 `json:"gasUsed"`
|
||||||
@ -406,7 +408,7 @@ func decodeHexString(s string, length int) ([]byte, error) {
|
|||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func EthHashFromCid(c cid.Cid) (EthHash, error) {
|
func NewEthHashFromCid(c cid.Cid) (EthHash, error) {
|
||||||
return EthHashFromHex(c.Hash().HexString()[8:])
|
return EthHashFromHex(c.Hash().HexString()[8:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ func TestEthHash(t *testing.T) {
|
|||||||
require.Equal(t, h.String(), strings.Replace(hash, `"`, "", -1))
|
require.Equal(t, h.String(), strings.Replace(hash, `"`, "", -1))
|
||||||
|
|
||||||
c := h.ToCid()
|
c := h.ToCid()
|
||||||
h1, err := EthHashFromCid(c)
|
h1, err := NewEthHashFromCid(c)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
require.Equal(t, h, h1)
|
require.Equal(t, h, h1)
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEncode(t *testing.T) {
|
func TestEncode(t *testing.T) {
|
||||||
@ -175,16 +177,14 @@ func TestDecodeError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDecode1(t *testing.T) {
|
func TestDecode1(t *testing.T) {
|
||||||
t.Skip("doesn't really test anything, it just prints stuff...")
|
|
||||||
b := mustDecodeHex("0x02f8758401df5e7680832c8411832c8411830767f89452963ef50e27e06d72d59fcb4f3c2a687be3cfef880de0b6b3a764000080c080a094b11866f453ad85a980e0e8a2fc98cbaeb4409618c7734a7e12ae2f66fd405da042dbfb1b37af102023830ceeee0e703ffba0b8b3afeb8fe59f405eca9ed61072")
|
b := mustDecodeHex("0x02f8758401df5e7680832c8411832c8411830767f89452963ef50e27e06d72d59fcb4f3c2a687be3cfef880de0b6b3a764000080c080a094b11866f453ad85a980e0e8a2fc98cbaeb4409618c7734a7e12ae2f66fd405da042dbfb1b37af102023830ceeee0e703ffba0b8b3afeb8fe59f405eca9ed61072")
|
||||||
decoded, err := ParseEthTxArgs(b)
|
decoded, err := ParseEthTxArgs(b)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
orig, err := decoded.OriginalRlpMsg()
|
|
||||||
fmt.Println(hex.EncodeToString(orig))
|
|
||||||
|
|
||||||
// correct f4 addr: f410fkkld55ioe7qg24wvt7fu6pbknb56ht7pt4zamxa
|
sender, err := decoded.Sender()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
fmt.Println(decoded.Sender())
|
addr, err := address.NewFromString("f410fkkld55ioe7qg24wvt7fu6pbknb56ht7pt4zamxa")
|
||||||
|
require.NoError(t, err)
|
||||||
fmt.Printf("%+v\n", decoded)
|
require.Equal(t, sender, addr)
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
@ -18,6 +18,10 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type RobustAddresser interface {
|
||||||
|
LookupRobustAddress(ctx context.Context, idAddr address.Address, ts *types.TipSet) (address.Address, error)
|
||||||
|
}
|
||||||
|
|
||||||
const indexed uint8 = 0x01
|
const indexed uint8 = 0x01
|
||||||
|
|
||||||
type EventFilter struct {
|
type EventFilter struct {
|
||||||
@ -25,7 +29,7 @@ type EventFilter struct {
|
|||||||
minHeight abi.ChainEpoch // minimum epoch to apply filter or -1 if no minimum
|
minHeight abi.ChainEpoch // minimum epoch to apply filter or -1 if no minimum
|
||||||
maxHeight abi.ChainEpoch // maximum epoch to apply filter or -1 if no maximum
|
maxHeight abi.ChainEpoch // maximum epoch to apply filter or -1 if no maximum
|
||||||
tipsetCid cid.Cid
|
tipsetCid cid.Cid
|
||||||
addresses []address.Address // list of actor ids that originated the event
|
addresses []address.Address // list of f4 actor addresses that are extpected to emit the event
|
||||||
keys map[string][][]byte // map of key names to a list of alternate values that may match
|
keys map[string][][]byte // map of key names to a list of alternate values that may match
|
||||||
maxResults int // maximum number of results to collect, 0 is unlimited
|
maxResults int // maximum number of results to collect, 0 is unlimited
|
||||||
|
|
||||||
@ -39,6 +43,7 @@ var _ Filter = (*EventFilter)(nil)
|
|||||||
|
|
||||||
type CollectedEvent struct {
|
type CollectedEvent struct {
|
||||||
Event *types.Event
|
Event *types.Event
|
||||||
|
EmitterAddr address.Address // f4 address of emitter
|
||||||
EventIdx int // index of the event within the list of emitted events
|
EventIdx int // index of the event within the list of emitted events
|
||||||
Reverted bool
|
Reverted bool
|
||||||
Height abi.ChainEpoch
|
Height abi.ChainEpoch
|
||||||
@ -64,18 +69,32 @@ func (f *EventFilter) ClearSubChannel() {
|
|||||||
f.ch = nil
|
f.ch = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *EventFilter) CollectEvents(ctx context.Context, te *TipSetEvents, revert bool) error {
|
func (f *EventFilter) CollectEvents(ctx context.Context, te *TipSetEvents, revert bool, resolver func(ctx context.Context, emitter abi.ActorID, ts *types.TipSet) (address.Address, bool)) error {
|
||||||
if !f.matchTipset(te) {
|
if !f.matchTipset(te) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cache of lookups between actor id and f4 address
|
||||||
|
addressLookups := make(map[abi.ActorID]address.Address)
|
||||||
|
|
||||||
ems, err := te.messages(ctx)
|
ems, err := te.messages(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("load executed messages: %w", err)
|
return xerrors.Errorf("load executed messages: %w", err)
|
||||||
}
|
}
|
||||||
for msgIdx, em := range ems {
|
for msgIdx, em := range ems {
|
||||||
for evIdx, ev := range em.Events() {
|
for evIdx, ev := range em.Events() {
|
||||||
addr, _ := address.NewIDAddress(uint64(ev.Emitter))
|
// lookup address corresponding to the actor id
|
||||||
|
addr, found := addressLookups[ev.Emitter]
|
||||||
|
if !found {
|
||||||
|
var ok bool
|
||||||
|
addr, ok = resolver(ctx, ev.Emitter, te.rctTs)
|
||||||
|
if !ok {
|
||||||
|
// not an address we will be able to match against
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addressLookups[ev.Emitter] = addr
|
||||||
|
}
|
||||||
|
|
||||||
if !f.matchAddress(addr) {
|
if !f.matchAddress(addr) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -86,6 +105,7 @@ func (f *EventFilter) CollectEvents(ctx context.Context, te *TipSetEvents, rever
|
|||||||
// event matches filter, so record it
|
// event matches filter, so record it
|
||||||
cev := &CollectedEvent{
|
cev := &CollectedEvent{
|
||||||
Event: ev,
|
Event: ev,
|
||||||
|
EmitterAddr: addr,
|
||||||
EventIdx: evIdx,
|
EventIdx: evIdx,
|
||||||
Reverted: revert,
|
Reverted: revert,
|
||||||
Height: te.msgTs.Height(),
|
Height: te.msgTs.Height(),
|
||||||
@ -153,8 +173,9 @@ func (f *EventFilter) matchAddress(o address.Address) bool {
|
|||||||
if len(f.addresses) == 0 {
|
if len(f.addresses) == 0 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assume short lists of addresses
|
// Assume short lists of addresses
|
||||||
// TODO: binary search for longer lists
|
// TODO: binary search for longer lists or restrict list length
|
||||||
for _, a := range f.addresses {
|
for _, a := range f.addresses {
|
||||||
if a == o {
|
if a == o {
|
||||||
return true
|
return true
|
||||||
@ -259,6 +280,7 @@ func (e *executedMessage) Events() []*types.Event {
|
|||||||
|
|
||||||
type EventFilterManager struct {
|
type EventFilterManager struct {
|
||||||
ChainStore *cstore.ChainStore
|
ChainStore *cstore.ChainStore
|
||||||
|
AddressResolver func(ctx context.Context, emitter abi.ActorID, ts *types.TipSet) (address.Address, bool)
|
||||||
MaxFilterResults int
|
MaxFilterResults int
|
||||||
|
|
||||||
mu sync.Mutex // guards mutations to filters
|
mu sync.Mutex // guards mutations to filters
|
||||||
@ -280,7 +302,7 @@ func (m *EventFilterManager) Apply(ctx context.Context, from, to *types.TipSet)
|
|||||||
|
|
||||||
// TODO: could run this loop in parallel with errgroup if there are many filters
|
// TODO: could run this loop in parallel with errgroup if there are many filters
|
||||||
for _, f := range m.filters {
|
for _, f := range m.filters {
|
||||||
if err := f.CollectEvents(ctx, tse, false); err != nil {
|
if err := f.CollectEvents(ctx, tse, false, m.AddressResolver); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -303,7 +325,7 @@ func (m *EventFilterManager) Revert(ctx context.Context, from, to *types.TipSet)
|
|||||||
|
|
||||||
// TODO: could run this loop in parallel with errgroup if there are many filters
|
// TODO: could run this loop in parallel with errgroup if there are many filters
|
||||||
for _, f := range m.filters {
|
for _, f := range m.filters {
|
||||||
if err := f.CollectEvents(ctx, tse, true); err != nil {
|
if err := f.CollectEvents(ctx, tse, true, m.AddressResolver); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
builtintypes "github.com/filecoin-project/go-state-types/builtin"
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
"github.com/filecoin-project/go-state-types/exitcode"
|
"github.com/filecoin-project/go-state-types/exitcode"
|
||||||
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
|
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||||
@ -23,11 +24,18 @@ import (
|
|||||||
|
|
||||||
func TestEventFilterCollectEvents(t *testing.T) {
|
func TestEventFilterCollectEvents(t *testing.T) {
|
||||||
rng := pseudo.New(pseudo.NewSource(299792458))
|
rng := pseudo.New(pseudo.NewSource(299792458))
|
||||||
a1 := randomActorAddr(t, rng)
|
a1 := randomF4Addr(t, rng)
|
||||||
a2 := randomActorAddr(t, rng)
|
a2 := randomF4Addr(t, rng)
|
||||||
|
|
||||||
|
a1ID := abi.ActorID(1)
|
||||||
|
a2ID := abi.ActorID(2)
|
||||||
|
|
||||||
|
addrMap := addressMap{}
|
||||||
|
addrMap.add(a1ID, a1)
|
||||||
|
addrMap.add(a2ID, a2)
|
||||||
|
|
||||||
ev1 := fakeEvent(
|
ev1 := fakeEvent(
|
||||||
a1,
|
a1ID,
|
||||||
[]kv{
|
[]kv{
|
||||||
{k: "type", v: []byte("approval")},
|
{k: "type", v: []byte("approval")},
|
||||||
{k: "signer", v: []byte("addr1")},
|
{k: "signer", v: []byte("addr1")},
|
||||||
@ -40,7 +48,7 @@ func TestEventFilterCollectEvents(t *testing.T) {
|
|||||||
st := newStore()
|
st := newStore()
|
||||||
events := []*types.Event{ev1}
|
events := []*types.Event{ev1}
|
||||||
em := executedMessage{
|
em := executedMessage{
|
||||||
msg: fakeMessage(randomActorAddr(t, rng), randomActorAddr(t, rng)),
|
msg: fakeMessage(randomF4Addr(t, rng), randomF4Addr(t, rng)),
|
||||||
rct: fakeReceipt(t, rng, st, events),
|
rct: fakeReceipt(t, rng, st, events),
|
||||||
evs: events,
|
evs: events,
|
||||||
}
|
}
|
||||||
@ -53,6 +61,7 @@ func TestEventFilterCollectEvents(t *testing.T) {
|
|||||||
oneCollectedEvent := []*CollectedEvent{
|
oneCollectedEvent := []*CollectedEvent{
|
||||||
{
|
{
|
||||||
Event: ev1,
|
Event: ev1,
|
||||||
|
EmitterAddr: a1,
|
||||||
EventIdx: 0,
|
EventIdx: 0,
|
||||||
Reverted: false,
|
Reverted: false,
|
||||||
Height: 14000,
|
Height: 14000,
|
||||||
@ -254,7 +263,7 @@ func TestEventFilterCollectEvents(t *testing.T) {
|
|||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
tc := tc // appease lint
|
tc := tc // appease lint
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
if err := tc.filter.CollectEvents(context.Background(), tc.te, false); err != nil {
|
if err := tc.filter.CollectEvents(context.Background(), tc.te, false, addrMap.ResolveAddress); err != nil {
|
||||||
require.NoError(t, err, "collect events")
|
require.NoError(t, err, "collect events")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,7 +278,7 @@ type kv struct {
|
|||||||
v []byte
|
v []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func fakeEvent(emitter address.Address, indexed []kv, unindexed []kv) *types.Event {
|
func fakeEvent(emitter abi.ActorID, indexed []kv, unindexed []kv) *types.Event {
|
||||||
ev := &types.Event{
|
ev := &types.Event{
|
||||||
Emitter: emitter,
|
Emitter: emitter,
|
||||||
}
|
}
|
||||||
@ -293,9 +302,9 @@ func fakeEvent(emitter address.Address, indexed []kv, unindexed []kv) *types.Eve
|
|||||||
return ev
|
return ev
|
||||||
}
|
}
|
||||||
|
|
||||||
func randomActorAddr(tb testing.TB, rng *pseudo.Rand) address.Address {
|
func randomF4Addr(tb testing.TB, rng *pseudo.Rand) address.Address {
|
||||||
tb.Helper()
|
tb.Helper()
|
||||||
addr, err := address.NewActorAddress(randomBytes(32, rng))
|
addr, err := address.NewDelegatedAddress(builtintypes.EthereumAddressManagerActorID, randomBytes(32, rng))
|
||||||
require.NoError(tb, err)
|
require.NoError(tb, err)
|
||||||
|
|
||||||
return addr
|
return addr
|
||||||
@ -409,3 +418,14 @@ func buildTipSetEvents(tb testing.TB, rng *pseudo.Rand, h abi.ChainEpoch, em exe
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type addressMap map[abi.ActorID]address.Address
|
||||||
|
|
||||||
|
func (a addressMap) add(actorID abi.ActorID, addr address.Address) {
|
||||||
|
a[actorID] = addr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a addressMap) ResolveAddress(ctx context.Context, emitter abi.ActorID, ts *types.TipSet) (address.Address, bool) {
|
||||||
|
ra, ok := a[emitter]
|
||||||
|
return ra, ok
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@ package stmgr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
@ -27,6 +28,8 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var ErrMetadataNotFound = errors.New("actor metadata not found")
|
||||||
|
|
||||||
func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, method abi.MethodNum, ts *types.TipSet) (cbg.CBORUnmarshaler, error) {
|
func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, method abi.MethodNum, ts *types.TipSet) (cbg.CBORUnmarshaler, error) {
|
||||||
act, err := sm.LoadActor(ctx, to, ts)
|
act, err := sm.LoadActor(ctx, to, ts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -35,7 +38,7 @@ func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, me
|
|||||||
|
|
||||||
m, found := sm.tsExec.NewActorRegistry().Methods[act.Code][method]
|
m, found := sm.tsExec.NewActorRegistry().Methods[act.Code][method]
|
||||||
if !found {
|
if !found {
|
||||||
return nil, fmt.Errorf("unknown method %d for actor %s", method, act.Code)
|
return nil, fmt.Errorf("unknown method %d for actor %s: %w", method, act.Code, ErrMetadataNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
return reflect.New(m.Ret.Elem()).Interface().(cbg.CBORUnmarshaler), nil
|
return reflect.New(m.Ret.Elem()).Interface().(cbg.CBORUnmarshaler), nil
|
||||||
@ -44,7 +47,7 @@ func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, me
|
|||||||
func GetParamType(ar *vm.ActorRegistry, actCode cid.Cid, method abi.MethodNum) (cbg.CBORUnmarshaler, error) {
|
func GetParamType(ar *vm.ActorRegistry, actCode cid.Cid, method abi.MethodNum) (cbg.CBORUnmarshaler, error) {
|
||||||
m, found := ar.Methods[actCode][method]
|
m, found := ar.Methods[actCode][method]
|
||||||
if !found {
|
if !found {
|
||||||
return nil, fmt.Errorf("unknown method %d for actor %s", method, actCode)
|
return nil, fmt.Errorf("unknown method %d for actor %s: %w", method, actCode, ErrMetadataNotFound)
|
||||||
}
|
}
|
||||||
return reflect.New(m.Params.Elem()).Interface().(cbg.CBORUnmarshaler), nil
|
return reflect.New(m.Params.Elem()).Interface().(cbg.CBORUnmarshaler), nil
|
||||||
}
|
}
|
||||||
|
@ -2353,6 +2353,7 @@ Inputs:
|
|||||||
Response:
|
Response:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
"hash": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||||
"parentHash": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
"parentHash": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||||
"sha3Uncles": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
"sha3Uncles": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||||
"miner": "0x0707070707070707070707070707070707070707",
|
"miner": "0x0707070707070707070707070707070707070707",
|
||||||
@ -2360,6 +2361,7 @@ Response:
|
|||||||
"transactionsRoot": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
"transactionsRoot": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||||
"receiptsRoot": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
"receiptsRoot": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||||
"difficulty": "0x5",
|
"difficulty": "0x5",
|
||||||
|
"totalDifficulty": "0x5",
|
||||||
"number": "0x5",
|
"number": "0x5",
|
||||||
"gasLimit": "0x5",
|
"gasLimit": "0x5",
|
||||||
"gasUsed": "0x5",
|
"gasUsed": "0x5",
|
||||||
@ -2394,6 +2396,7 @@ Inputs:
|
|||||||
Response:
|
Response:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
"hash": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||||
"parentHash": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
"parentHash": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||||
"sha3Uncles": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
"sha3Uncles": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||||
"miner": "0x0707070707070707070707070707070707070707",
|
"miner": "0x0707070707070707070707070707070707070707",
|
||||||
@ -2401,6 +2404,7 @@ Response:
|
|||||||
"transactionsRoot": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
"transactionsRoot": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||||
"receiptsRoot": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
"receiptsRoot": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||||
"difficulty": "0x5",
|
"difficulty": "0x5",
|
||||||
|
"totalDifficulty": "0x5",
|
||||||
"number": "0x5",
|
"number": "0x5",
|
||||||
"gasLimit": "0x5",
|
"gasLimit": "0x5",
|
||||||
"gasUsed": "0x5",
|
"gasUsed": "0x5",
|
||||||
@ -2576,7 +2580,6 @@ Response:
|
|||||||
"type": "0x5",
|
"type": "0x5",
|
||||||
"input": "0x07",
|
"input": "0x07",
|
||||||
"gas": "0x5",
|
"gas": "0x5",
|
||||||
"gasLimit": "0x5",
|
|
||||||
"maxFeePerGas": "0x0",
|
"maxFeePerGas": "0x0",
|
||||||
"maxPriorityFeePerGas": "0x0",
|
"maxPriorityFeePerGas": "0x0",
|
||||||
"v": "0x07",
|
"v": "0x07",
|
||||||
@ -2613,7 +2616,6 @@ Response:
|
|||||||
"type": "0x5",
|
"type": "0x5",
|
||||||
"input": "0x07",
|
"input": "0x07",
|
||||||
"gas": "0x5",
|
"gas": "0x5",
|
||||||
"gasLimit": "0x5",
|
|
||||||
"maxFeePerGas": "0x0",
|
"maxFeePerGas": "0x0",
|
||||||
"maxPriorityFeePerGas": "0x0",
|
"maxPriorityFeePerGas": "0x0",
|
||||||
"v": "0x07",
|
"v": "0x07",
|
||||||
@ -2649,7 +2651,6 @@ Response:
|
|||||||
"type": "0x5",
|
"type": "0x5",
|
||||||
"input": "0x07",
|
"input": "0x07",
|
||||||
"gas": "0x5",
|
"gas": "0x5",
|
||||||
"gasLimit": "0x5",
|
|
||||||
"maxFeePerGas": "0x0",
|
"maxFeePerGas": "0x0",
|
||||||
"maxPriorityFeePerGas": "0x0",
|
"maxPriorityFeePerGas": "0x0",
|
||||||
"v": "0x07",
|
"v": "0x07",
|
||||||
|
1
itests/contracts/SimpleCoin.bin
Normal file
1
itests/contracts/SimpleCoin.bin
Normal file
@ -0,0 +1 @@
|
|||||||
|
608060405234801561001057600080fd5b506127106000803273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061051c806100656000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80637bd703e81461004657806390b98a1114610076578063f8b2cb4f146100a6575b600080fd5b610060600480360381019061005b919061030a565b6100d6565b60405161006d9190610350565b60405180910390f35b610090600480360381019061008b9190610397565b6100f4565b60405161009d91906103f2565b60405180910390f35b6100c060048036038101906100bb919061030a565b61025f565b6040516100cd9190610350565b60405180910390f35b600060026100e38361025f565b6100ed919061043c565b9050919050565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156101455760009050610259565b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254610193919061047e565b92505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546101e891906104b2565b925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161024c9190610350565b60405180910390a3600190505b92915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102d7826102ac565b9050919050565b6102e7816102cc565b81146102f257600080fd5b50565b600081359050610304816102de565b92915050565b6000602082840312156103205761031f6102a7565b5b600061032e848285016102f5565b91505092915050565b6000819050919050565b61034a81610337565b82525050565b60006020820190506103656000830184610341565b92915050565b61037481610337565b811461037f57600080fd5b50565b6000813590506103918161036b565b92915050565b600080604083850312156103ae576103ad6102a7565b5b60006103bc858286016102f5565b92505060206103cd85828601610382565b9150509250929050565b60008115159050919050565b6103ec816103d7565b82525050565b600060208201905061040760008301846103e3565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061044782610337565b915061045283610337565b925082820261046081610337565b915082820484148315176104775761047661040d565b5b5092915050565b600061048982610337565b915061049483610337565b92508282039050818111156104ac576104ab61040d565b5b92915050565b60006104bd82610337565b91506104c883610337565b92508282019050808211156104e0576104df61040d565b5b9291505056fea26469706673582212205ede41ff9072784ccc19ac18de0781558d305a8139361fa85dc51a8614e47d8c64736f6c63430008110033
|
31
itests/contracts/SimpleCoin.sol
Normal file
31
itests/contracts/SimpleCoin.sol
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity >=0.4.2;
|
||||||
|
|
||||||
|
contract SimpleCoin {
|
||||||
|
mapping(address => uint256) balances;
|
||||||
|
|
||||||
|
event Transfer(address indexed _from, address indexed _to, uint256 _value);
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
balances[tx.origin] = 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendCoin(address receiver, uint256 amount)
|
||||||
|
public
|
||||||
|
returns (bool sufficient)
|
||||||
|
{
|
||||||
|
if (balances[msg.sender] < amount) return false;
|
||||||
|
balances[msg.sender] -= amount;
|
||||||
|
balances[receiver] += amount;
|
||||||
|
emit Transfer(msg.sender, receiver, amount);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBalanceInEth(address addr) public view returns (uint256) {
|
||||||
|
return getBalance(addr) * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBalance(address addr) public view returns (uint256) {
|
||||||
|
return balances[addr];
|
||||||
|
}
|
||||||
|
}
|
171
itests/fevm_test.go
Normal file
171
itests/fevm_test.go
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
package itests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
|
|
||||||
|
"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/v10/eam"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/filecoin-project/lotus/itests/kit"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestFEVMBasic does a basic fevm contract installation and invocation
|
||||||
|
func TestFEVMBasic(t *testing.T) {
|
||||||
|
// TODO the contract installation and invocation can be lifted into utility methods
|
||||||
|
// He who writes the second test, shall do that.
|
||||||
|
kit.QuietMiningLogs()
|
||||||
|
|
||||||
|
blockTime := 100 * time.Millisecond
|
||||||
|
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
|
||||||
|
ens.InterconnectAll().BeginMining(blockTime)
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// install contract
|
||||||
|
contractHex, err := os.ReadFile("contracts/SimpleCoin.bin")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
contract, err := hex.DecodeString(string(contractHex))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
fromAddr, err := client.WalletDefaultAddress(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
nonce, err := client.MpoolGetNonce(ctx, fromAddr)
|
||||||
|
if err != nil {
|
||||||
|
nonce = 0 // assume a zero nonce on error (e.g. sender doesn't exist).
|
||||||
|
}
|
||||||
|
|
||||||
|
var salt [32]byte
|
||||||
|
binary.BigEndian.PutUint64(salt[:], nonce)
|
||||||
|
|
||||||
|
method := builtintypes.MethodsEAM.Create2
|
||||||
|
params, err := actors.SerializeParams(&eam.Create2Params{
|
||||||
|
Initcode: contract,
|
||||||
|
Salt: salt,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
msg := &types.Message{
|
||||||
|
To: builtintypes.EthereumAddressManagerActorAddr,
|
||||||
|
From: fromAddr,
|
||||||
|
Value: big.Zero(),
|
||||||
|
Method: method,
|
||||||
|
Params: params,
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("sending create message")
|
||||||
|
smsg, err := client.MpoolPushMessage(ctx, msg, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
t.Log("waiting for message to execute")
|
||||||
|
wait, err := client.StateWaitMsg(ctx, smsg.Cid(), 0, 0, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.True(t, wait.Receipt.ExitCode.IsSuccess(), "contract installation failed")
|
||||||
|
|
||||||
|
var result eam.CreateReturn
|
||||||
|
r := bytes.NewReader(wait.Receipt.Return)
|
||||||
|
err = result.UnmarshalCBOR(r)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
idAddr, err := address.NewIDAddress(result.ActorID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
t.Logf("actor ID address is %s", idAddr)
|
||||||
|
|
||||||
|
// invoke the contract with owner
|
||||||
|
{
|
||||||
|
entryPoint, err := hex.DecodeString("f8b2cb4f")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
inputData, err := hex.DecodeString("000000000000000000000000ff00000000000000000000000000000000000064")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
params := append(entryPoint, inputData...)
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
err = cbg.WriteByteArray(&buffer, params)
|
||||||
|
require.NoError(t, err)
|
||||||
|
params = buffer.Bytes()
|
||||||
|
|
||||||
|
msg := &types.Message{
|
||||||
|
To: idAddr,
|
||||||
|
From: fromAddr,
|
||||||
|
Value: big.Zero(),
|
||||||
|
Method: abi.MethodNum(2),
|
||||||
|
Params: params,
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("sending invoke message")
|
||||||
|
smsg, err := client.MpoolPushMessage(ctx, msg, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
t.Log("waiting for message to execute")
|
||||||
|
wait, err := client.StateWaitMsg(ctx, smsg.Cid(), 0, 0, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.True(t, wait.Receipt.ExitCode.IsSuccess(), "contract execution failed")
|
||||||
|
|
||||||
|
result, err := cbg.ReadByteArray(bytes.NewBuffer(wait.Receipt.Return), uint64(len(wait.Receipt.Return)))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000002710")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, result, expectedResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
// invoke the contract with non owner
|
||||||
|
{
|
||||||
|
entryPoint, err := hex.DecodeString("f8b2cb4f")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
inputData, err := hex.DecodeString("000000000000000000000000ff00000000000000000000000000000000000065")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
params := append(entryPoint, inputData...)
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
err = cbg.WriteByteArray(&buffer, params)
|
||||||
|
require.NoError(t, err)
|
||||||
|
params = buffer.Bytes()
|
||||||
|
|
||||||
|
msg := &types.Message{
|
||||||
|
To: idAddr,
|
||||||
|
From: fromAddr,
|
||||||
|
Value: big.Zero(),
|
||||||
|
Method: abi.MethodNum(2),
|
||||||
|
Params: params,
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("sending invoke message")
|
||||||
|
smsg, err := client.MpoolPushMessage(ctx, msg, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
t.Log("waiting for message to execute")
|
||||||
|
wait, err := client.StateWaitMsg(ctx, smsg.Cid(), 0, 0, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.True(t, wait.Receipt.ExitCode.IsSuccess(), "contract execution failed")
|
||||||
|
|
||||||
|
result, err := cbg.ReadByteArray(bytes.NewBuffer(wait.Receipt.Return), uint64(len(wait.Receipt.Return)))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, result, expectedResult)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -244,7 +244,7 @@ func ConfigFullNode(c interface{}) Option {
|
|||||||
|
|
||||||
// Actor event filtering support
|
// Actor event filtering support
|
||||||
Override(new(events.EventAPI), From(new(modules.EventAPI))),
|
Override(new(events.EventAPI), From(new(modules.EventAPI))),
|
||||||
Override(new(full.EthEventAPI), modules.EthEvent(cfg.ActorEvent)),
|
Override(new(full.EthEventAPI), modules.EthEventAPI(cfg.ActorEvent)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ func (a *EthModule) EthGetBlockByHash(ctx context.Context, blkHash api.EthHash,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return api.EthBlock{}, xerrors.Errorf("error loading tipset %s: %w", ts, err)
|
return api.EthBlock{}, xerrors.Errorf("error loading tipset %s: %w", ts, err)
|
||||||
}
|
}
|
||||||
return a.ethBlockFromFilecoinTipSet(ctx, ts, fullTxInfo)
|
return a.newEthBlockFromFilecoinTipSet(ctx, ts, fullTxInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *EthModule) EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (api.EthBlock, error) {
|
func (a *EthModule) EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (api.EthBlock, error) {
|
||||||
@ -183,7 +183,7 @@ func (a *EthModule) EthGetBlockByNumber(ctx context.Context, blkNum string, full
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return api.EthBlock{}, xerrors.Errorf("error loading tipset %s: %w", ts, err)
|
return api.EthBlock{}, xerrors.Errorf("error loading tipset %s: %w", ts, err)
|
||||||
}
|
}
|
||||||
return a.ethBlockFromFilecoinTipSet(ctx, ts, fullTxInfo)
|
return a.newEthBlockFromFilecoinTipSet(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) {
|
||||||
@ -199,7 +199,7 @@ func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash *api.Eth
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
tx, err := a.ethTxFromFilecoinMessageLookup(ctx, msgLookup)
|
tx, err := a.newEthTxFromFilecoinMessageLookup(ctx, msgLookup)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@ -226,7 +226,7 @@ func (a *EthModule) EthGetTransactionReceipt(ctx context.Context, txHash api.Eth
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
tx, err := a.ethTxFromFilecoinMessageLookup(ctx, msgLookup)
|
tx, err := a.newEthTxFromFilecoinMessageLookup(ctx, msgLookup)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@ -445,7 +445,7 @@ func (a *EthModule) EthFeeHistory(ctx context.Context, blkCount api.EthUint64, n
|
|||||||
for ts.Height() >= abi.ChainEpoch(oldestBlkHeight) {
|
for ts.Height() >= abi.ChainEpoch(oldestBlkHeight) {
|
||||||
// Unfortunately we need to rebuild the full message view so we can
|
// Unfortunately we need to rebuild the full message view so we can
|
||||||
// totalize gas used in the tipset.
|
// totalize gas used in the tipset.
|
||||||
block, err := a.ethBlockFromFilecoinTipSet(ctx, ts, false)
|
block, err := a.newEthBlockFromFilecoinTipSet(ctx, ts, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return api.EthFeeHistory{}, fmt.Errorf("cannot create eth block: %v", err)
|
return api.EthFeeHistory{}, fmt.Errorf("cannot create eth block: %v", err)
|
||||||
}
|
}
|
||||||
@ -534,7 +534,7 @@ func (a *EthModule) EthSendRawTransaction(ctx context.Context, rawTx api.EthByte
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return api.EmptyEthHash, err
|
return api.EmptyEthHash, err
|
||||||
}
|
}
|
||||||
return api.EthHashFromCid(cid)
|
return api.NewEthHashFromCid(cid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *EthModule) ethCallToFilecoinMessage(ctx context.Context, tx api.EthCall) (*types.Message, error) {
|
func (a *EthModule) ethCallToFilecoinMessage(ctx context.Context, tx api.EthCall) (*types.Message, error) {
|
||||||
@ -666,7 +666,7 @@ func (a *EthModule) EthCall(ctx context.Context, tx api.EthCall, blkParam string
|
|||||||
return api.EthBytes{}, nil
|
return api.EthBytes{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *EthModule) ethBlockFromFilecoinTipSet(ctx context.Context, ts *types.TipSet, fullTxInfo bool) (api.EthBlock, error) {
|
func (a *EthModule) newEthBlockFromFilecoinTipSet(ctx context.Context, ts *types.TipSet, fullTxInfo bool) (api.EthBlock, error) {
|
||||||
parent, err := a.Chain.LoadTipSet(ctx, ts.Parents())
|
parent, err := a.Chain.LoadTipSet(ctx, ts.Parents())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return api.EthBlock{}, err
|
return api.EthBlock{}, err
|
||||||
@ -675,7 +675,16 @@ func (a *EthModule) ethBlockFromFilecoinTipSet(ctx context.Context, ts *types.Ti
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return api.EthBlock{}, err
|
return api.EthBlock{}, err
|
||||||
}
|
}
|
||||||
parentBlkHash, err := api.EthHashFromCid(parentKeyCid)
|
parentBlkHash, err := api.NewEthHashFromCid(parentKeyCid)
|
||||||
|
if err != nil {
|
||||||
|
return api.EthBlock{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
blkCid, err := ts.Key().Cid()
|
||||||
|
if err != nil {
|
||||||
|
return api.EthBlock{}, err
|
||||||
|
}
|
||||||
|
blkHash, err := api.NewEthHashFromCid(blkCid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return api.EthBlock{}, err
|
return api.EthBlock{}, err
|
||||||
}
|
}
|
||||||
@ -698,13 +707,13 @@ func (a *EthModule) ethBlockFromFilecoinTipSet(ctx context.Context, ts *types.Ti
|
|||||||
gasUsed += msgLookup.Receipt.GasUsed
|
gasUsed += msgLookup.Receipt.GasUsed
|
||||||
|
|
||||||
if fullTxInfo {
|
if fullTxInfo {
|
||||||
tx, err := a.ethTxFromFilecoinMessageLookup(ctx, msgLookup)
|
tx, err := a.newEthTxFromFilecoinMessageLookup(ctx, msgLookup)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return api.EthBlock{}, nil
|
return api.EthBlock{}, nil
|
||||||
}
|
}
|
||||||
block.Transactions = append(block.Transactions, tx)
|
block.Transactions = append(block.Transactions, tx)
|
||||||
} else {
|
} else {
|
||||||
hash, err := api.EthHashFromCid(msg.Cid())
|
hash, err := api.NewEthHashFromCid(msg.Cid())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return api.EthBlock{}, err
|
return api.EthBlock{}, err
|
||||||
}
|
}
|
||||||
@ -713,6 +722,7 @@ func (a *EthModule) ethBlockFromFilecoinTipSet(ctx context.Context, ts *types.Ti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
block.Hash = blkHash
|
||||||
block.Number = api.EthUint64(ts.Height())
|
block.Number = api.EthUint64(ts.Height())
|
||||||
block.ParentHash = parentBlkHash
|
block.ParentHash = parentBlkHash
|
||||||
block.Timestamp = api.EthUint64(ts.Blocks()[0].Timestamp)
|
block.Timestamp = api.EthUint64(ts.Blocks()[0].Timestamp)
|
||||||
@ -765,12 +775,12 @@ func (a *EthModule) lookupEthAddress(ctx context.Context, addr address.Address)
|
|||||||
return api.EthAddressFromFilecoinAddress(idAddr)
|
return api.EthAddressFromFilecoinAddress(idAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *EthModule) ethTxFromFilecoinMessageLookup(ctx context.Context, msgLookup *api.MsgLookup) (api.EthTx, error) {
|
func (a *EthModule) newEthTxFromFilecoinMessageLookup(ctx context.Context, msgLookup *api.MsgLookup) (api.EthTx, error) {
|
||||||
if msgLookup == nil {
|
if msgLookup == nil {
|
||||||
return api.EthTx{}, fmt.Errorf("msg does not exist")
|
return api.EthTx{}, fmt.Errorf("msg does not exist")
|
||||||
}
|
}
|
||||||
cid := msgLookup.Message
|
cid := msgLookup.Message
|
||||||
txHash, err := api.EthHashFromCid(cid)
|
txHash, err := api.NewEthHashFromCid(cid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return api.EthTx{}, err
|
return api.EthTx{}, err
|
||||||
}
|
}
|
||||||
@ -791,7 +801,7 @@ func (a *EthModule) ethTxFromFilecoinMessageLookup(ctx context.Context, msgLooku
|
|||||||
return api.EthTx{}, err
|
return api.EthTx{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
blkHash, err := api.EthHashFromCid(parentTsCid)
|
blkHash, err := api.NewEthHashFromCid(parentTsCid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return api.EthTx{}, err
|
return api.EthTx{}, err
|
||||||
}
|
}
|
||||||
@ -976,6 +986,8 @@ func (e *EthEvent) EthNewFilter(ctx context.Context, filter *api.EthFilterSpec)
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert all addresses to filecoin f4 addresses
|
||||||
for _, ea := range filter.Address {
|
for _, ea := range filter.Address {
|
||||||
a, err := ea.ToFilecoinAddress()
|
a, err := ea.ToFilecoinAddress()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1244,8 +1256,7 @@ func ethFilterResultFromEvents(evs []*filter.CollectedEvent) (*api.EthFilterResu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addr, _ := address.NewIDAddress(uint64(ev.Event.Emitter))
|
log.Address, err = api.EthAddressFromFilecoinAddress(ev.EmitterAddr)
|
||||||
log.Address, err = api.EthAddressFromFilecoinAddress(addr)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
@ -617,15 +618,23 @@ func (m *StateModule) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence
|
|||||||
|
|
||||||
t, err := stmgr.GetReturnType(ctx, m.StateManager, vmsg.To, vmsg.Method, ts)
|
t, err := stmgr.GetReturnType(ctx, m.StateManager, vmsg.To, vmsg.Method, ts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, stmgr.ErrMetadataNotFound) {
|
||||||
|
// This is not nececessary an error -- EVM methods (and in the future native actors) may
|
||||||
|
// return just bytes, and in the not so distant future we'll have native wasm actors
|
||||||
|
// that are by definition not in the registry.
|
||||||
|
// So in this case, log a debug message and retun the raw bytes.
|
||||||
|
log.Debugf("failed to get return type: %s", err)
|
||||||
|
returndec = recpt.Return
|
||||||
|
} else {
|
||||||
return nil, xerrors.Errorf("failed to get return type: %w", err)
|
return nil, xerrors.Errorf("failed to get return type: %w", err)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
if err := t.UnmarshalCBOR(bytes.NewReader(recpt.Return)); err != nil {
|
if err := t.UnmarshalCBOR(bytes.NewReader(recpt.Return)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
returndec = t
|
returndec = t
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &api.MsgLookup{
|
return &api.MsgLookup{
|
||||||
Message: found,
|
Message: found,
|
||||||
|
@ -4,14 +4,19 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/multiformats/go-varint"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
builtintypes "github.com/filecoin-project/go-state-types/builtin"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/events"
|
"github.com/filecoin-project/lotus/chain/events"
|
||||||
"github.com/filecoin-project/lotus/chain/events/filter"
|
"github.com/filecoin-project/lotus/chain/events/filter"
|
||||||
"github.com/filecoin-project/lotus/chain/messagepool"
|
"github.com/filecoin-project/lotus/chain/messagepool"
|
||||||
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/node/config"
|
"github.com/filecoin-project/lotus/node/config"
|
||||||
"github.com/filecoin-project/lotus/node/impl/full"
|
"github.com/filecoin-project/lotus/node/impl/full"
|
||||||
"github.com/filecoin-project/lotus/node/modules/helpers"
|
"github.com/filecoin-project/lotus/node/modules/helpers"
|
||||||
@ -26,8 +31,8 @@ type EventAPI struct {
|
|||||||
|
|
||||||
var _ events.EventAPI = &EventAPI{}
|
var _ events.EventAPI = &EventAPI{}
|
||||||
|
|
||||||
func EthEvent(cfg config.ActorEventConfig) func(helpers.MetricsCtx, fx.Lifecycle, *store.ChainStore, EventAPI, *messagepool.MessagePool) (*full.EthEvent, error) {
|
func EthEventAPI(cfg config.ActorEventConfig) func(helpers.MetricsCtx, fx.Lifecycle, *store.ChainStore, *stmgr.StateManager, EventAPI, *messagepool.MessagePool) (*full.EthEvent, error) {
|
||||||
return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, cs *store.ChainStore, evapi EventAPI, mp *messagepool.MessagePool) (*full.EthEvent, error) {
|
return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, cs *store.ChainStore, sm *stmgr.StateManager, evapi EventAPI, mp *messagepool.MessagePool) (*full.EthEvent, error) {
|
||||||
ee := &full.EthEvent{
|
ee := &full.EthEvent{
|
||||||
Chain: cs,
|
Chain: cs,
|
||||||
MaxFilterHeightRange: abi.ChainEpoch(cfg.MaxFilterHeightRange),
|
MaxFilterHeightRange: abi.ChainEpoch(cfg.MaxFilterHeightRange),
|
||||||
@ -51,6 +56,27 @@ func EthEvent(cfg config.ActorEventConfig) func(helpers.MetricsCtx, fx.Lifecycle
|
|||||||
if cfg.EnableRealTimeFilterAPI {
|
if cfg.EnableRealTimeFilterAPI {
|
||||||
ee.EventFilterManager = &filter.EventFilterManager{
|
ee.EventFilterManager = &filter.EventFilterManager{
|
||||||
ChainStore: cs,
|
ChainStore: cs,
|
||||||
|
AddressResolver: func(ctx context.Context, emitter abi.ActorID, ts *types.TipSet) (address.Address, bool) {
|
||||||
|
// we only want to match using f4 addresses
|
||||||
|
idAddr, err := address.NewIDAddress(uint64(emitter))
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, false
|
||||||
|
}
|
||||||
|
addr, err := sm.LookupRobustAddress(ctx, idAddr, ts)
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, false
|
||||||
|
}
|
||||||
|
// if robust address is not f4 then we won't match against it so bail early
|
||||||
|
if addr.Protocol() != address.Delegated {
|
||||||
|
return address.Undef, false
|
||||||
|
}
|
||||||
|
// we have an f4 address, make sure it's assigned by the EAM
|
||||||
|
if namespace, _, err := varint.FromUvarint(addr.Payload()); err != nil || namespace != builtintypes.EthereumAddressManagerActorID {
|
||||||
|
return address.Undef, false
|
||||||
|
}
|
||||||
|
return addr, true
|
||||||
|
},
|
||||||
|
|
||||||
MaxFilterResults: cfg.MaxFilterResults,
|
MaxFilterResults: cfg.MaxFilterResults,
|
||||||
}
|
}
|
||||||
ee.TipSetFilterManager = &filter.TipSetFilterManager{
|
ee.TipSetFilterManager = &filter.TipSetFilterManager{
|
||||||
|
Loading…
Reference in New Issue
Block a user