rpc: store decimals by contract ID instead of hash

And we should also cache contract scripthash to fill Asset field.
This commit is contained in:
Anna Shaleva 2020-07-29 15:09:59 +03:00
parent 0dd1730632
commit 167bd7d9df

View file

@ -514,19 +514,15 @@ func (s *Server) getNEP5Balances(ps request.Params) (interface{}, *response.Erro
Balances: []result.NEP5Balance{},
}
if as != nil {
cache := make(map[util.Uint160]int64)
cache := make(map[int32]decimals)
for id, bal := range as.Trackers {
h, err := s.chain.GetContractScriptHash(id)
dec, err := s.getDecimals(id, cache)
if err != nil {
continue
}
dec, err := s.getDecimals(h, cache)
if err != nil {
continue
}
amount := amountToString(&bal.Balance, dec)
amount := amountToString(&bal.Balance, dec.Value)
bs.Balances = append(bs.Balances, result.NEP5Balance{
Asset: h,
Asset: dec.Hash,
Amount: amount,
LastUpdated: bal.LastUpdatedBlock,
})
@ -547,24 +543,20 @@ func (s *Server) getNEP5Transfers(ps request.Params) (interface{}, *response.Err
Sent: []result.NEP5Transfer{},
}
lg := s.chain.GetNEP5TransferLog(u)
cache := make(map[util.Uint160]int64)
cache := make(map[int32]decimals)
err = lg.ForEach(func(tr *state.NEP5Transfer) error {
h, err := s.chain.GetContractScriptHash(tr.Asset)
d, err := s.getDecimals(tr.Asset, cache)
if err != nil {
return nil
}
transfer := result.NEP5Transfer{
Timestamp: tr.Timestamp,
Asset: h,
Asset: d.Hash,
Index: tr.Block,
TxHash: tr.Tx,
}
d, err := s.getDecimals(h, cache)
if err != nil {
return nil
}
if tr.Amount.Sign() > 0 { // token was received
transfer.Amount = amountToString(&tr.Amount, d)
transfer.Amount = amountToString(&tr.Amount, d.Value)
if !tr.From.Equals(util.Uint160{}) {
transfer.Address = address.Uint160ToString(tr.From)
}
@ -572,7 +564,7 @@ func (s *Server) getNEP5Transfers(ps request.Params) (interface{}, *response.Err
return nil
}
transfer.Amount = amountToString(new(big.Int).Neg(&tr.Amount), d)
transfer.Amount = amountToString(new(big.Int).Neg(&tr.Amount), d.Value)
if !tr.To.Equals(util.Uint160{}) {
transfer.Address = address.Uint160ToString(tr.To)
}
@ -598,10 +590,20 @@ func amountToString(amount *big.Int, decimals int64) string {
return fmt.Sprintf(fs, q, r)
}
func (s *Server) getDecimals(h util.Uint160, cache map[util.Uint160]int64) (int64, error) {
if d, ok := cache[h]; ok {
// decimals represents decimals value for the contract with the specified scripthash.
type decimals struct {
Hash util.Uint160
Value int64
}
func (s *Server) getDecimals(contractID int32, cache map[int32]decimals) (decimals, error) {
if d, ok := cache[contractID]; ok {
return d, nil
}
h, err := s.chain.GetContractScriptHash(contractID)
if err != nil {
return decimals{}, err
}
script, err := request.CreateFunctionInvocationScript(h, request.Params{
{
Type: request.StringT,
@ -613,26 +615,26 @@ func (s *Server) getDecimals(h util.Uint160, cache map[util.Uint160]int64) (int6
},
})
if err != nil {
return 0, fmt.Errorf("can't create script: %v", err)
return decimals{}, fmt.Errorf("can't create script: %v", err)
}
res := s.runScriptInVM(script, nil)
if res == nil || res.State != "HALT" || len(res.Stack) == 0 {
return 0, errors.New("execution error : no result")
return decimals{}, errors.New("execution error : no result")
}
var d int64
d := decimals{Hash: h}
switch item := res.Stack[len(res.Stack)-1]; item.Type {
case smartcontract.IntegerType:
d = item.Value.(int64)
d.Value = item.Value.(int64)
case smartcontract.ByteArrayType:
d = bigint.FromBytes(item.Value.([]byte)).Int64()
d.Value = bigint.FromBytes(item.Value.([]byte)).Int64()
default:
return 0, errors.New("invalid result: not an integer")
return d, errors.New("invalid result: not an integer")
}
if d < 0 {
return 0, errors.New("incorrect result: negative result")
if d.Value < 0 {
return d, errors.New("incorrect result: negative result")
}
cache[h] = d
cache[contractID] = d
return d, nil
}