diff --git a/docs/rpc.md b/docs/rpc.md index f12a7abca..1f8763f59 100644 --- a/docs/rpc.md +++ b/docs/rpc.md @@ -114,7 +114,11 @@ balance won't be shown in the list of NEP17 balances returned by the neo-go node (unlike the C# node behavior). However, transfer logs of such token are still available via `getnep17transfers` RPC call. -The behaviour of the `LastUpdatedBlock` tracking matches the C# node's one. +The behaviour of the `LastUpdatedBlock` tracking for archival nodes as far as for +governing token balances matches the C# node's one. For non-archival nodes and +other NEP17-compliant tokens if transfer's `LastUpdatedBlock` is lower than the +latest state synchronization point P the node working against, then +`LastUpdatedBlock` equals P. ### Unsupported methods diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 18fdf786f..1b3a99370 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -1223,12 +1223,25 @@ func (bc *Blockchain) GetNEP17Contracts() []util.Uint160 { } // GetNEP17LastUpdated returns a set of contract ids with the corresponding last updated -// block indexes. +// block indexes. In case of an empty account, latest stored state synchronisation point +// is returned under Math.MinInt32 key. func (bc *Blockchain) GetNEP17LastUpdated(acc util.Uint160) (map[int32]uint32, error) { info, err := bc.dao.GetNEP17TransferInfo(acc) if err != nil { return nil, err } + if bc.config.P2PStateExchangeExtensions && bc.config.RemoveUntraceableBlocks { + if _, ok := info.LastUpdated[bc.contracts.NEO.ID]; !ok { + nBalance, lub := bc.contracts.NEO.BalanceOf(bc.dao, acc) + if nBalance.Sign() != 0 { + info.LastUpdated[bc.contracts.NEO.ID] = lub + } + } + } + stateSyncPoint, err := bc.dao.GetStateSyncPoint() + if err == nil { + info.LastUpdated[math.MinInt32] = stateSyncPoint + } return info.LastUpdated, nil } diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index 3fa82c659..8bd2e26a3 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -679,6 +679,7 @@ func (s *Server) getNEP17Balances(ps request.Params) (interface{}, *response.Err if err != nil { return nil, response.NewRPCError("Failed to get NEP17 last updated block", err.Error(), err) } + stateSyncPoint := lastUpdated[math.MinInt32] bw := io.NewBufBinWriter() for _, h := range s.chain.GetNEP17Contracts() { balance, err := s.getNEP17Balance(h, u, bw) @@ -692,10 +693,18 @@ func (s *Server) getNEP17Balances(ps request.Params) (interface{}, *response.Err if cs == nil { continue } + lub, ok := lastUpdated[cs.ID] + if !ok { + cfg := s.chain.GetConfig() + if !cfg.P2PStateExchangeExtensions && cfg.RemoveUntraceableBlocks { + return nil, response.NewInternalServerError(fmt.Sprintf("failed to get LastUpdatedBlock for balance of %s token", cs.Hash.StringLE()), nil) + } + lub = stateSyncPoint + } bs.Balances = append(bs.Balances, result.NEP17Balance{ Asset: h, Amount: balance.String(), - LastUpdated: lastUpdated[cs.ID], + LastUpdated: lub, }) } return bs, nil