From d9e933c7f3094f2fb3075c54ece5aef2f4a6db54 Mon Sep 17 00:00:00 2001 From: Lutty Date: Sat, 19 Feb 2022 17:28:26 +0800 Subject: [PATCH] support rosetta tracer --- core/evm.go | 14 ++++++++------ core/staking_verifier_test.go | 8 ++++++++ core/state/state_object.go | 9 +++++++++ core/state_transition.go | 10 +++++----- core/vm/contracts_write.go | 13 +++++++++---- core/vm/evm.go | 14 +++++++++----- hmy/tracers/rosetta_block_tracer.go | 14 ++++++++++++++ node/node_syncing.go | 2 +- rosetta/services/block.go | 14 +++++++------- 9 files changed, 70 insertions(+), 28 deletions(-) diff --git a/core/evm.go b/core/evm.go index 1707c9ccd..befb56007 100644 --- a/core/evm.go +++ b/core/evm.go @@ -47,6 +47,8 @@ type ChainContext interface { // ReadDelegationsByDelegator returns the validators list of a delegator ReadDelegationsByDelegator(common.Address) (stakingTypes.DelegationIndexes, error) + ReadDelegationsByDelegatorAt(delegator common.Address, blockNum *big.Int) (m stakingTypes.DelegationIndexes, err error) + // ReadValidatorSnapshot returns the snapshot of validator at the beginning of current epoch. ReadValidatorSnapshot(common.Address) (*stakingTypes.ValidatorSnapshot, error) @@ -104,7 +106,7 @@ func NewEVMContext(msg Message, header *block.Header, chain ChainContext, author // the function can then be called through the EVM context func CreateValidatorFn(ref *block.Header, chain ChainContext) vm.CreateValidatorFunc { // moved from state_transition.go to here, with some modifications - return func(db vm.StateDB, createValidator *stakingTypes.CreateValidator) error { + return func(db vm.StateDB, rosettaTracer vm.RosettaTracer, createValidator *stakingTypes.CreateValidator) error { wrapper, err := VerifyAndCreateValidatorFromMsg( db, chain, ref.Epoch(), ref.Number(), createValidator, ) @@ -122,7 +124,7 @@ func CreateValidatorFn(ref *block.Header, chain ChainContext) vm.CreateValidator func EditValidatorFn(ref *block.Header, chain ChainContext) vm.EditValidatorFunc { // moved from state_transition.go to here, with some modifications - return func(db vm.StateDB, editValidator *stakingTypes.EditValidator) error { + return func(db vm.StateDB, rosettaTracer vm.RosettaTracer, editValidator *stakingTypes.EditValidator) error { wrapper, err := VerifyAndEditValidatorFromMsg( db, chain, ref.Epoch(), ref.Number(), editValidator, ) @@ -135,8 +137,8 @@ func EditValidatorFn(ref *block.Header, chain ChainContext) vm.EditValidatorFunc func DelegateFn(ref *block.Header, chain ChainContext) vm.DelegateFunc { // moved from state_transition.go to here, with some modifications - return func(db vm.StateDB, delegate *stakingTypes.Delegate) error { - delegations, err := chain.ReadDelegationsByDelegator(delegate.DelegatorAddress) + return func(db vm.StateDB, rosettaTracer vm.RosettaTracer, delegate *stakingTypes.Delegate) error { + delegations, err := chain.ReadDelegationsByDelegatorAt(delegate.DelegatorAddress, big.NewInt(0).Sub(ref.Number(), big.NewInt(1))) if err != nil { return err } @@ -188,7 +190,7 @@ func DelegateFn(ref *block.Header, chain ChainContext) vm.DelegateFunc { func UndelegateFn(ref *block.Header, chain ChainContext) vm.UndelegateFunc { // moved from state_transition.go to here, with some modifications - return func(db vm.StateDB, undelegate *stakingTypes.Undelegate) error { + return func(db vm.StateDB, rosettaTracer vm.RosettaTracer, undelegate *stakingTypes.Undelegate) error { wrapper, err := VerifyAndUndelegateFromMsg(db, ref.Epoch(), undelegate) if err != nil { return err @@ -198,7 +200,7 @@ func UndelegateFn(ref *block.Header, chain ChainContext) vm.UndelegateFunc { } func CollectRewardsFn(ref *block.Header, chain ChainContext) vm.CollectRewardsFunc { - return func(db vm.StateDB, collectRewards *stakingTypes.CollectRewards) error { + return func(db vm.StateDB, rosettaTracer vm.RosettaTracer, collectRewards *stakingTypes.CollectRewards) error { if chain == nil { return errors.New("[CollectRewards] No chain context provided") } diff --git a/core/staking_verifier_test.go b/core/staking_verifier_test.go index b356f37fe..f829a0050 100644 --- a/core/staking_verifier_test.go +++ b/core/staking_verifier_test.go @@ -1739,6 +1739,10 @@ func (chain *fakeChainContext) ReadDelegationsByDelegator(common.Address) (staki return nil, nil } +func (chain *fakeChainContext) ReadDelegationsByDelegatorAt(delegator common.Address, blockNum *big.Int) (staking.DelegationIndexes, error) { + return nil, nil +} + func (chain *fakeChainContext) ShardID() uint32 { return shard.BeaconChainShardID } @@ -1779,6 +1783,10 @@ func (chain *fakeErrChainContext) ReadDelegationsByDelegator(common.Address) (st return nil, nil } +func (chain *fakeErrChainContext) ReadDelegationsByDelegatorAt(delegator common.Address, blockNum *big.Int) (staking.DelegationIndexes, error) { + return nil, nil +} + func (chain *fakeErrChainContext) ShardID() uint32 { return 900 // arbitrary number different from BeaconChainShardID } diff --git a/core/state/state_object.go b/core/state/state_object.go index 0d4fd7a80..4bf6a321b 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -341,6 +341,9 @@ func (s *Object) CommitTrie(db Database) error { // AddBalance removes amount from c's balance. // It is used to add funds to the destination account of a transfer. func (s *Object) AddBalance(amount *big.Int) { + if s.address.String() == "0x9aFba568f59854539D17B9120B6E4d31b9e8a3eF" { + fmt.Printf("AddBalance: %s => %s\n", s.address.String(), amount.String()) + } // EIP158: We must check emptiness for the objects such that the account // clearing (0,0,0 objects) can take effect. if amount.Sign() == 0 { @@ -356,6 +359,9 @@ func (s *Object) AddBalance(amount *big.Int) { // SubBalance removes amount from c's balance. // It is used to remove funds from the origin account of a transfer. func (s *Object) SubBalance(amount *big.Int) { + if s.address.String() == "0x9aFba568f59854539D17B9120B6E4d31b9e8a3eF" { + fmt.Printf("SubBalance: %s\n", amount.String()) + } if amount.Sign() == 0 { return } @@ -364,6 +370,9 @@ func (s *Object) SubBalance(amount *big.Int) { // SetBalance ... func (s *Object) SetBalance(amount *big.Int) { + if s.address.String() == "0x9aFba568f59854539D17B9120B6E4d31b9e8a3eF" { + fmt.Printf("SetBalance: %s\n", amount.String()) + } s.db.journal.append(balanceChange{ account: &s.address, prev: new(big.Int).Set(s.data.Balance), diff --git a/core/state_transition.go b/core/state_transition.go index a566f435a..c2b66164d 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -328,7 +328,7 @@ func (st *StateTransition) StakingTransitionDb() (usedGas uint64, err error) { if msg.From() != stkMsg.ValidatorAddress { return 0, errInvalidSigner } - err = st.evm.CreateValidator(st.evm.StateDB, stkMsg) + err = st.evm.CreateValidator(st.evm.StateDB, nil, stkMsg) case types.StakeEditVal: stkMsg := &stakingTypes.EditValidator{} if err = rlp.DecodeBytes(msg.Data(), stkMsg); err != nil { @@ -339,7 +339,7 @@ func (st *StateTransition) StakingTransitionDb() (usedGas uint64, err error) { if msg.From() != stkMsg.ValidatorAddress { return 0, errInvalidSigner } - err = st.evm.EditValidator(st.evm.StateDB, stkMsg) + err = st.evm.EditValidator(st.evm.StateDB, nil, stkMsg) case types.Delegate: stkMsg := &stakingTypes.Delegate{} if err = rlp.DecodeBytes(msg.Data(), stkMsg); err != nil { @@ -349,7 +349,7 @@ func (st *StateTransition) StakingTransitionDb() (usedGas uint64, err error) { if msg.From() != stkMsg.DelegatorAddress { return 0, errInvalidSigner } - err = st.evm.Delegate(st.evm.StateDB, stkMsg) + err = st.evm.Delegate(st.evm.StateDB, nil, stkMsg) case types.Undelegate: stkMsg := &stakingTypes.Undelegate{} if err = rlp.DecodeBytes(msg.Data(), stkMsg); err != nil { @@ -359,7 +359,7 @@ func (st *StateTransition) StakingTransitionDb() (usedGas uint64, err error) { if msg.From() != stkMsg.DelegatorAddress { return 0, errInvalidSigner } - err = st.evm.Undelegate(st.evm.StateDB, stkMsg) + err = st.evm.Undelegate(st.evm.StateDB, nil, stkMsg) case types.CollectRewards: stkMsg := &stakingTypes.CollectRewards{} if err = rlp.DecodeBytes(msg.Data(), stkMsg); err != nil { @@ -369,7 +369,7 @@ func (st *StateTransition) StakingTransitionDb() (usedGas uint64, err error) { if msg.From() != stkMsg.DelegatorAddress { return 0, errInvalidSigner } - err = st.evm.CollectRewards(st.evm.StateDB, stkMsg) + err = st.evm.CollectRewards(st.evm.StateDB, nil, stkMsg) default: return 0, stakingTypes.ErrInvalidStakingKind } diff --git a/core/vm/contracts_write.go b/core/vm/contracts_write.go index 4266625f6..7c506ceb8 100644 --- a/core/vm/contracts_write.go +++ b/core/vm/contracts_write.go @@ -2,7 +2,6 @@ package vm import ( "errors" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/rlp" "github.com/harmony-one/harmony/shard" @@ -112,8 +111,14 @@ func (c *stakingPrecompile) RunWriteCapable( if err != nil { return nil, err } + + var rosettaBlockTracer RosettaTracer + if tmpTracker, ok := evm.vmConfig.Tracer.(RosettaTracer); ok { + rosettaBlockTracer = tmpTracker + } + if delegate, ok := stakeMsg.(*stakingTypes.Delegate); ok { - if err := evm.Delegate(evm.StateDB, delegate); err != nil { + if err := evm.Delegate(evm.StateDB, rosettaBlockTracer, delegate); err != nil { return nil, err } else { evm.StakeMsgs = append(evm.StakeMsgs, delegate) @@ -121,10 +126,10 @@ func (c *stakingPrecompile) RunWriteCapable( } } if undelegate, ok := stakeMsg.(*stakingTypes.Undelegate); ok { - return nil, evm.Undelegate(evm.StateDB, undelegate) + return nil, evm.Undelegate(evm.StateDB, rosettaBlockTracer, undelegate) } if collectRewards, ok := stakeMsg.(*stakingTypes.CollectRewards); ok { - return nil, evm.CollectRewards(evm.StateDB, collectRewards) + return nil, evm.CollectRewards(evm.StateDB, rosettaBlockTracer, collectRewards) } // Migrate is not supported in precompile and will be done in a batch hard fork //if migrationMsg, ok := stakeMsg.(*stakingTypes.MigrationMsg); ok { diff --git a/core/vm/evm.go b/core/vm/evm.go index 3889c54f9..02e0b8fea 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -32,6 +32,10 @@ import ( // deployed contract addresses (relevant after the account abstraction). var emptyCodeHash = crypto.Keccak256Hash(nil) +type RosettaTracer interface { + AddRosettaLog(op OpCode, from, to common.Address, val *big.Int) +} + type ( // CanTransferFunc is the signature of a transfer guard function CanTransferFunc func(StateDB, common.Address, *big.Int) bool @@ -46,11 +50,11 @@ type ( // and is used by the precompile VRF contract. GetVRFFunc func(uint64) common.Hash // Below functions are used by staking precompile, and state transition - CreateValidatorFunc func(db StateDB, stakeMsg *stakingTypes.CreateValidator) error - EditValidatorFunc func(db StateDB, stakeMsg *stakingTypes.EditValidator) error - DelegateFunc func(db StateDB, stakeMsg *stakingTypes.Delegate) error - UndelegateFunc func(db StateDB, stakeMsg *stakingTypes.Undelegate) error - CollectRewardsFunc func(db StateDB, stakeMsg *stakingTypes.CollectRewards) error + CreateValidatorFunc func(db StateDB, rosettaTracer RosettaTracer, stakeMsg *stakingTypes.CreateValidator) error + EditValidatorFunc func(db StateDB, rosettaTracer RosettaTracer, stakeMsg *stakingTypes.EditValidator) error + DelegateFunc func(db StateDB, rosettaTracer RosettaTracer, stakeMsg *stakingTypes.Delegate) error + UndelegateFunc func(db StateDB, rosettaTracer RosettaTracer, stakeMsg *stakingTypes.Undelegate) error + CollectRewardsFunc func(db StateDB, rosettaTracer RosettaTracer, stakeMsg *stakingTypes.CollectRewards) error // Used for migrating delegations via the staking precompile //MigrateDelegationsFunc func(db StateDB, migrationMsg *stakingTypes.MigrationMsg) ([]interface{}, error) CalculateMigrationGasFunc func(db StateDB, migrationMsg *stakingTypes.MigrationMsg, homestead bool, istanbul bool) (uint64, error) diff --git a/hmy/tracers/rosetta_block_tracer.go b/hmy/tracers/rosetta_block_tracer.go index 51497b533..88de210e8 100644 --- a/hmy/tracers/rosetta_block_tracer.go +++ b/hmy/tracers/rosetta_block_tracer.go @@ -34,6 +34,8 @@ type RosettaLogItem struct { type RosettaBlockTracer struct { *ParityBlockTracer + + logs []*RosettaLogItem } func (rbt *RosettaBlockTracer) formatAction(depth []int, parentErr error, ac *action) *RosettaLogItem { @@ -53,6 +55,18 @@ func (rbt *RosettaBlockTracer) formatAction(depth []int, parentErr error, ac *ac } } +func (rbt *RosettaBlockTracer) AddRosettaLog(op vm.OpCode, from, to common.Address, val *big.Int) { + rbt.logs = append(rbt.logs, &RosettaLogItem{ + IsSuccess: true, + Reverted: false, + OP: op, + Depth: make([]int, 0), + From: from, + To: to, + Value: val, + }) +} + func (rbt *RosettaBlockTracer) GetResult() ([]*RosettaLogItem, error) { root := &rbt.action diff --git a/node/node_syncing.go b/node/node_syncing.go index 87820904f..93c97ef0c 100644 --- a/node/node_syncing.go +++ b/node/node_syncing.go @@ -361,7 +361,7 @@ func (node *Node) supportSyncing() { utils.Logger().Debug().Msg("[SYNC] initialized state sync") } - go node.DoSyncing(node.Blockchain(), node.Worker, joinConsensus) + //go node.DoSyncing(node.Blockchain(), node.Worker, joinConsensus) } // InitSyncingServer starts downloader server. diff --git a/rosetta/services/block.go b/rosetta/services/block.go index 436cf4b43..91f8afdec 100644 --- a/rosetta/services/block.go +++ b/rosetta/services/block.go @@ -291,10 +291,10 @@ func init() { func (s *BlockAPI) getTransactionTrace( ctx context.Context, blk *hmytypes.Block, txInfo *transactionInfo, ) ([]*tracers.RosettaLogItem, *types.Error) { - cacheKey := blk.Hash().String() + txInfo.tx.Hash().String() - if value, ok := s.txTraceCache.Get(cacheKey); ok { - return value.([]*tracers.RosettaLogItem), nil - } + //cacheKey := blk.Hash().String() + txInfo.tx.Hash().String() + //if value, ok := s.txTraceCache.Get(cacheKey); ok { + // return value.([]*tracers.RosettaLogItem), nil + //} lock := &sync.Mutex{} if ok, _ := ttLock.ContainsOrAdd(blk.Hash().String(), lock); ok { @@ -310,9 +310,9 @@ func (s *BlockAPI) getTransactionTrace( defer lock.Unlock() } - if value, ok := s.txTraceCache.Get(cacheKey); ok { - return value.([]*tracers.RosettaLogItem), nil - } + //if value, ok := s.txTraceCache.Get(cacheKey); ok { + // return value.([]*tracers.RosettaLogItem), nil + //} var blockError *types.Error var foundResult []*tracers.RosettaLogItem