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