mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-26 19:42:23 +00:00
Merge pull request #1165 from nspcc-dev/neo3/state/nep5transfer
core: store NEP5 transfers and balances as big.Int
This commit is contained in:
commit
1fa2d4bc6a
15 changed files with 113 additions and 80 deletions
|
@ -694,7 +694,7 @@ func (bc *Blockchain) handleNotification(note *state.NotificationEvent, d *dao.C
|
|||
}
|
||||
amount = bigint.FromBytes(bs)
|
||||
}
|
||||
bc.processNEP5Transfer(d, h, b, note.ScriptHash, from, to, amount.Int64())
|
||||
bc.processNEP5Transfer(d, h, b, note.ScriptHash, from, to, amount)
|
||||
}
|
||||
|
||||
func parseUint160(addr []byte) util.Uint160 {
|
||||
|
@ -704,7 +704,7 @@ func parseUint160(addr []byte) util.Uint160 {
|
|||
return util.Uint160{}
|
||||
}
|
||||
|
||||
func (bc *Blockchain) processNEP5Transfer(cache *dao.Cached, h util.Uint256, b *block.Block, sc util.Uint160, from, to []byte, amount int64) {
|
||||
func (bc *Blockchain) processNEP5Transfer(cache *dao.Cached, h util.Uint256, b *block.Block, sc util.Uint160, from, to []byte, amount *big.Int) {
|
||||
toAddr := parseUint160(to)
|
||||
fromAddr := parseUint160(from)
|
||||
transfer := &state.NEP5Transfer{
|
||||
|
@ -721,11 +721,10 @@ func (bc *Blockchain) processNEP5Transfer(cache *dao.Cached, h util.Uint256, b *
|
|||
return
|
||||
}
|
||||
bs := balances.Trackers[sc]
|
||||
bs.Balance -= amount
|
||||
bs.Balance = *new(big.Int).Sub(&bs.Balance, amount)
|
||||
bs.LastUpdatedBlock = b.Index
|
||||
balances.Trackers[sc] = bs
|
||||
|
||||
transfer.Amount = -amount
|
||||
transfer.Amount = *new(big.Int).Sub(&transfer.Amount, amount)
|
||||
isBig, err := cache.AppendNEP5Transfer(fromAddr, balances.NextTransferBatch, transfer)
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -743,11 +742,11 @@ func (bc *Blockchain) processNEP5Transfer(cache *dao.Cached, h util.Uint256, b *
|
|||
return
|
||||
}
|
||||
bs := balances.Trackers[sc]
|
||||
bs.Balance += amount
|
||||
bs.Balance = *new(big.Int).Add(&bs.Balance, amount)
|
||||
bs.LastUpdatedBlock = b.Index
|
||||
balances.Trackers[sc] = bs
|
||||
|
||||
transfer.Amount = amount
|
||||
transfer.Amount = *amount
|
||||
isBig, err := cache.AppendNEP5Transfer(toAddr, balances.NextTransferBatch, transfer)
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -788,23 +787,24 @@ func (bc *Blockchain) GetNEP5Balances(acc util.Uint160) *state.NEP5Balances {
|
|||
}
|
||||
|
||||
// GetUtilityTokenBalance returns utility token (GAS) balance for the acc.
|
||||
func (bc *Blockchain) GetUtilityTokenBalance(acc util.Uint160) int64 {
|
||||
func (bc *Blockchain) GetUtilityTokenBalance(acc util.Uint160) *big.Int {
|
||||
bs, err := bc.dao.GetNEP5Balances(acc)
|
||||
if err != nil {
|
||||
return 0
|
||||
return big.NewInt(0)
|
||||
}
|
||||
return bs.Trackers[bc.contracts.GAS.Hash].Balance
|
||||
balance := bs.Trackers[bc.contracts.GAS.Hash].Balance
|
||||
return &balance
|
||||
}
|
||||
|
||||
// GetGoverningTokenBalance returns governing token (NEO) balance and the height
|
||||
// of the last balance change for the account.
|
||||
func (bc *Blockchain) GetGoverningTokenBalance(acc util.Uint160) (int64, uint32) {
|
||||
func (bc *Blockchain) GetGoverningTokenBalance(acc util.Uint160) (*big.Int, uint32) {
|
||||
bs, err := bc.dao.GetNEP5Balances(acc)
|
||||
if err != nil {
|
||||
return 0, 0
|
||||
return big.NewInt(0), 0
|
||||
}
|
||||
neo := bs.Trackers[bc.contracts.NEO.Hash]
|
||||
return neo.Balance, neo.LastUpdatedBlock
|
||||
return &neo.Balance, neo.LastUpdatedBlock
|
||||
}
|
||||
|
||||
// LastBatch returns last persisted storage batch.
|
||||
|
@ -1062,7 +1062,7 @@ func (bc *Blockchain) UnsubscribeFromExecutions(ch chan<- *state.AppExecResult)
|
|||
// amount of NEO between specified blocks. The amount of NEO being passed is in
|
||||
// its natural non-divisible form (1 NEO as 1, 2 NEO as 2, no multiplication by
|
||||
// 10⁸ is needed as for Fixed8).
|
||||
func (bc *Blockchain) CalculateClaimable(value int64, startHeight, endHeight uint32) int64 {
|
||||
func (bc *Blockchain) CalculateClaimable(value *big.Int, startHeight, endHeight uint32) *big.Int {
|
||||
var amount int64
|
||||
di := uint32(bc.decrementInterval)
|
||||
|
||||
|
@ -1088,7 +1088,7 @@ func (bc *Blockchain) CalculateClaimable(value int64, startHeight, endHeight uin
|
|||
amount += int64(iend-istart) * int64(bc.generationAmount[ustart])
|
||||
}
|
||||
|
||||
return amount * value
|
||||
return new(big.Int).Mul(big.NewInt(amount), value)
|
||||
}
|
||||
|
||||
// FeePerByte returns transaction network fee per byte.
|
||||
|
@ -1148,7 +1148,7 @@ func (bc *Blockchain) verifyTx(t *transaction.Transaction, block *block.Block) e
|
|||
}
|
||||
balance := bc.GetUtilityTokenBalance(t.Sender)
|
||||
need := t.SystemFee + t.NetworkFee
|
||||
if balance < need {
|
||||
if balance.Cmp(big.NewInt(need)) < 0 {
|
||||
return errors.Errorf("insufficient funds: balance is %v, need: %v", balance, need)
|
||||
}
|
||||
size := io.GetVarSize(t)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -196,23 +197,23 @@ func TestGetClaimable(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
t.Run("first generation period", func(t *testing.T) {
|
||||
amount := bc.CalculateClaimable(1, 0, 2)
|
||||
require.EqualValues(t, 8, amount)
|
||||
amount := bc.CalculateClaimable(big.NewInt(1), 0, 2)
|
||||
require.EqualValues(t, big.NewInt(8), amount)
|
||||
})
|
||||
|
||||
t.Run("a number of full periods", func(t *testing.T) {
|
||||
amount := bc.CalculateClaimable(1, 0, 6)
|
||||
require.EqualValues(t, 4+4+3+3+2+2, amount)
|
||||
amount := bc.CalculateClaimable(big.NewInt(1), 0, 6)
|
||||
require.EqualValues(t, big.NewInt(4+4+3+3+2+2), amount)
|
||||
})
|
||||
|
||||
t.Run("start from the 2-nd block", func(t *testing.T) {
|
||||
amount := bc.CalculateClaimable(1, 1, 7)
|
||||
require.EqualValues(t, 4+3+3+2+2+1, amount)
|
||||
amount := bc.CalculateClaimable(big.NewInt(1), 1, 7)
|
||||
require.EqualValues(t, big.NewInt(4+3+3+2+2+1), amount)
|
||||
})
|
||||
|
||||
t.Run("end height after generation has ended", func(t *testing.T) {
|
||||
amount := bc.CalculateClaimable(1, 1, 10)
|
||||
require.EqualValues(t, 4+3+3+2+2+1+1, amount)
|
||||
amount := bc.CalculateClaimable(big.NewInt(1), 1, 10)
|
||||
require.EqualValues(t, big.NewInt(4+3+3+2+2+1+1), amount)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package blockchainer
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/mempool"
|
||||
|
@ -19,13 +21,13 @@ type Blockchainer interface {
|
|||
AddHeaders(...*block.Header) error
|
||||
AddBlock(*block.Block) error
|
||||
BlockHeight() uint32
|
||||
CalculateClaimable(value int64, startHeight, endHeight uint32) int64
|
||||
CalculateClaimable(value *big.Int, startHeight, endHeight uint32) *big.Int
|
||||
Close()
|
||||
HeaderHeight() uint32
|
||||
GetBlock(hash util.Uint256) (*block.Block, error)
|
||||
GetContractState(hash util.Uint160) *state.Contract
|
||||
GetEnrollments() ([]state.Validator, error)
|
||||
GetGoverningTokenBalance(acc util.Uint160) (int64, uint32)
|
||||
GetGoverningTokenBalance(acc util.Uint160) (*big.Int, uint32)
|
||||
GetHeaderHash(int) util.Uint256
|
||||
GetHeader(hash util.Uint256) (*block.Header, error)
|
||||
CurrentHeaderHash() util.Uint256
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -181,7 +182,7 @@ func TestCreateBasicChain(t *testing.T) {
|
|||
priv0 := testchain.PrivateKeyByID(0)
|
||||
priv0ScriptHash := priv0.GetScriptHash()
|
||||
|
||||
require.Equal(t, int64(0), bc.GetUtilityTokenBalance(priv0ScriptHash))
|
||||
require.Equal(t, big.NewInt(0), bc.GetUtilityTokenBalance(priv0ScriptHash))
|
||||
// Move some NEO to one simple account.
|
||||
txMoveNeo := newNEP5Transfer(neoHash, neoOwner, priv0ScriptHash, neoAmount)
|
||||
txMoveNeo.ValidUntilBlock = validUntilBlock
|
||||
|
@ -211,7 +212,7 @@ func TestCreateBasicChain(t *testing.T) {
|
|||
t.Logf("txMoveNeo: %s", txMoveNeo.Hash().StringLE())
|
||||
t.Logf("txMoveGas: %s", txMoveGas.Hash().StringLE())
|
||||
|
||||
require.True(t, bc.GetUtilityTokenBalance(priv0ScriptHash) >= 1000*native.GASFactor)
|
||||
require.True(t, bc.GetUtilityTokenBalance(priv0ScriptHash).Cmp(big.NewInt(1000*native.GASFactor)) >= 0)
|
||||
// info for getblockheader rpc tests
|
||||
t.Logf("header hash: %s", b.Hash().StringLE())
|
||||
buf := io.NewBufBinWriter()
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
package mempool
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
||||
// Feer is an interface that abstract the implementation of the fee calculation.
|
||||
type Feer interface {
|
||||
FeePerByte() int64
|
||||
GetUtilityTokenBalance(util.Uint160) int64
|
||||
GetUtilityTokenBalance(util.Uint160) *big.Int
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package mempool
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -35,7 +36,7 @@ type items []*item
|
|||
// utilityBalanceAndFees stores sender's balance and overall fees of
|
||||
// sender's transactions which are currently in mempool
|
||||
type utilityBalanceAndFees struct {
|
||||
balance int64
|
||||
balance *big.Int
|
||||
feeSum int64
|
||||
}
|
||||
|
||||
|
@ -124,7 +125,7 @@ func (mp *Pool) checkBalanceAndUpdate(tx *transaction.Transaction, feer Feer) bo
|
|||
mp.fees[tx.Sender] = senderFee
|
||||
}
|
||||
needFee := senderFee.feeSum + tx.SystemFee + tx.NetworkFee
|
||||
if senderFee.balance < needFee {
|
||||
if senderFee.balance.Cmp(big.NewInt(needFee)) < 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package mempool
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
|
@ -16,13 +17,13 @@ type FeerStub struct {
|
|||
feePerByte int64
|
||||
}
|
||||
|
||||
const balance = 10000000
|
||||
var balance = big.NewInt(10000000)
|
||||
|
||||
func (fs *FeerStub) FeePerByte() int64 {
|
||||
return fs.feePerByte
|
||||
}
|
||||
|
||||
func (fs *FeerStub) GetUtilityTokenBalance(uint160 util.Uint160) int64 {
|
||||
func (fs *FeerStub) GetUtilityTokenBalance(uint160 util.Uint160) *big.Int {
|
||||
return balance
|
||||
}
|
||||
|
||||
|
@ -184,7 +185,7 @@ func TestMemPoolFees(t *testing.T) {
|
|||
mp := NewMemPool(10)
|
||||
sender0 := util.Uint160{1, 2, 3}
|
||||
tx0 := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
|
||||
tx0.NetworkFee = balance + 1
|
||||
tx0.NetworkFee = balance.Int64() + 1
|
||||
tx0.Sender = sender0
|
||||
// insufficient funds to add transaction, but balance should be stored
|
||||
require.Equal(t, false, mp.Verify(tx0, &FeerStub{}))
|
||||
|
@ -195,9 +196,10 @@ func TestMemPoolFees(t *testing.T) {
|
|||
feeSum: 0,
|
||||
}, mp.fees[sender0])
|
||||
|
||||
balancePart := new(big.Int).Div(balance, big.NewInt(4))
|
||||
// no problems with adding another transaction with lower fee
|
||||
tx1 := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
|
||||
tx1.NetworkFee = balance * 0.7
|
||||
tx1.NetworkFee = balancePart.Int64()
|
||||
tx1.Sender = sender0
|
||||
require.NoError(t, mp.Add(tx1, &FeerStub{}))
|
||||
require.Equal(t, 1, len(mp.fees))
|
||||
|
@ -208,14 +210,14 @@ func TestMemPoolFees(t *testing.T) {
|
|||
|
||||
// balance shouldn't change after adding one more transaction
|
||||
tx2 := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
|
||||
tx2.NetworkFee = balance * 0.3
|
||||
tx2.NetworkFee = new(big.Int).Sub(balance, balancePart).Int64()
|
||||
tx2.Sender = sender0
|
||||
require.NoError(t, mp.Add(tx2, &FeerStub{}))
|
||||
require.Equal(t, 2, len(mp.verifiedTxes))
|
||||
require.Equal(t, 1, len(mp.fees))
|
||||
require.Equal(t, utilityBalanceAndFees{
|
||||
balance: balance,
|
||||
feeSum: balance,
|
||||
feeSum: balance.Int64(),
|
||||
}, mp.fees[sender0])
|
||||
|
||||
// can't add more transactions as we don't have enough GAS
|
||||
|
@ -227,7 +229,7 @@ func TestMemPoolFees(t *testing.T) {
|
|||
require.Equal(t, 1, len(mp.fees))
|
||||
require.Equal(t, utilityBalanceAndFees{
|
||||
balance: balance,
|
||||
feeSum: balance,
|
||||
feeSum: balance.Int64(),
|
||||
}, mp.fees[sender0])
|
||||
|
||||
// check whether sender's fee updates correctly
|
||||
|
|
|
@ -197,9 +197,9 @@ func (n *NEO) distributeGas(ic *interop.Context, h util.Uint160, acc *state.NEOB
|
|||
if ic.Block == nil || ic.Block.Index == 0 {
|
||||
return nil
|
||||
}
|
||||
gen := ic.Chain.CalculateClaimable(acc.Balance.Int64(), acc.BalanceHeight, ic.Block.Index)
|
||||
gen := ic.Chain.CalculateClaimable(&acc.Balance, acc.BalanceHeight, ic.Block.Index)
|
||||
acc.BalanceHeight = ic.Block.Index
|
||||
n.GAS.mint(ic, h, big.NewInt(gen))
|
||||
n.GAS.mint(ic, h, gen)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -212,8 +212,8 @@ func (n *NEO) unclaimedGas(ic *interop.Context, args []stackitem.Item) stackitem
|
|||
}
|
||||
tr := bs.Trackers[n.Hash]
|
||||
|
||||
gen := ic.Chain.CalculateClaimable(tr.Balance, tr.LastUpdatedBlock, end)
|
||||
return stackitem.NewBigInteger(big.NewInt(gen))
|
||||
gen := ic.Chain.CalculateClaimable(&tr.Balance, tr.LastUpdatedBlock, end)
|
||||
return stackitem.NewBigInteger(gen)
|
||||
}
|
||||
|
||||
func (n *NEO) registerValidator(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
|
|
|
@ -214,7 +214,7 @@ func (c *nep5TokenNative) balanceOf(ic *interop.Context, args []stackitem.Item)
|
|||
panic(err)
|
||||
}
|
||||
balance := bs.Trackers[c.Hash].Balance
|
||||
return stackitem.NewBigInteger(big.NewInt(balance))
|
||||
return stackitem.NewBigInteger(&balance)
|
||||
}
|
||||
|
||||
func (c *nep5TokenNative) mint(ic *interop.Context, h util.Uint160, amount *big.Int) {
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
@ -8,7 +11,7 @@ import (
|
|||
// NEP5Tracker contains info about a single account in a NEP5 contract.
|
||||
type NEP5Tracker struct {
|
||||
// Balance is the current balance of the account.
|
||||
Balance int64
|
||||
Balance big.Int
|
||||
// LastUpdatedBlock is a number of block when last `transfer` to or from the
|
||||
// account occured.
|
||||
LastUpdatedBlock uint32
|
||||
|
@ -17,11 +20,10 @@ type NEP5Tracker struct {
|
|||
// NEP5TransferLog is a log of NEP5 token transfers for the specific command.
|
||||
type NEP5TransferLog struct {
|
||||
Raw []byte
|
||||
// size is the number of NEP5Transfers written into Raw
|
||||
size int
|
||||
}
|
||||
|
||||
// NEP5TransferSize is a size of a marshaled NEP5Transfer struct in bytes.
|
||||
const NEP5TransferSize = util.Uint160Size*3 + 8 + 4 + 8 + util.Uint256Size
|
||||
|
||||
// NEP5Transfer represents a single NEP5 Transfer event.
|
||||
type NEP5Transfer struct {
|
||||
// Asset is a NEP5 contract hash.
|
||||
|
@ -32,7 +34,7 @@ type NEP5Transfer struct {
|
|||
To util.Uint160
|
||||
// Amount is the amount of tokens transferred.
|
||||
// It is negative when tokens are sent and positive if they are received.
|
||||
Amount int64
|
||||
Amount big.Int
|
||||
// Block is a number of block when the event occured.
|
||||
Block uint32
|
||||
// Timestamp is the timestamp of the block where transfer occured.
|
||||
|
@ -89,6 +91,7 @@ func (lg *NEP5TransferLog) Append(tr *NEP5Transfer) error {
|
|||
return w.Err
|
||||
}
|
||||
lg.Raw = append(lg.Raw, w.Bytes()...)
|
||||
lg.size++
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -98,9 +101,10 @@ func (lg *NEP5TransferLog) ForEach(f func(*NEP5Transfer) error) error {
|
|||
return nil
|
||||
}
|
||||
tr := new(NEP5Transfer)
|
||||
for i := 0; i < len(lg.Raw); i += NEP5TransferSize {
|
||||
r := io.NewBinReaderFromBuf(lg.Raw[i : i+NEP5TransferSize])
|
||||
tr.DecodeBinary(r)
|
||||
var bytesRead int
|
||||
for i := 0; i < len(lg.Raw); i += bytesRead {
|
||||
r := io.NewBinReaderFromBuf(lg.Raw[i:])
|
||||
bytesRead = tr.DecodeBinaryReturnCount(r)
|
||||
if r.Err != nil {
|
||||
return r.Err
|
||||
} else if err := f(tr); err != nil {
|
||||
|
@ -112,23 +116,22 @@ func (lg *NEP5TransferLog) ForEach(f func(*NEP5Transfer) error) error {
|
|||
|
||||
// Size returns an amount of transfer written in log.
|
||||
func (lg *NEP5TransferLog) Size() int {
|
||||
return len(lg.Raw) / NEP5TransferSize
|
||||
return lg.size
|
||||
}
|
||||
|
||||
// EncodeBinary implements io.Serializable interface.
|
||||
func (t *NEP5Tracker) EncodeBinary(w *io.BinWriter) {
|
||||
w.WriteU64LE(uint64(t.Balance))
|
||||
w.WriteVarBytes(bigint.ToBytes(&t.Balance))
|
||||
w.WriteU32LE(t.LastUpdatedBlock)
|
||||
}
|
||||
|
||||
// DecodeBinary implements io.Serializable interface.
|
||||
func (t *NEP5Tracker) DecodeBinary(r *io.BinReader) {
|
||||
t.Balance = int64(r.ReadU64LE())
|
||||
t.Balance = *bigint.FromBytes(r.ReadVarBytes())
|
||||
t.LastUpdatedBlock = r.ReadU32LE()
|
||||
}
|
||||
|
||||
// EncodeBinary implements io.Serializable interface.
|
||||
// Note: change NEP5TransferSize constant when changing this function.
|
||||
func (t *NEP5Transfer) EncodeBinary(w *io.BinWriter) {
|
||||
w.WriteBytes(t.Asset[:])
|
||||
w.WriteBytes(t.Tx[:])
|
||||
|
@ -136,16 +139,27 @@ func (t *NEP5Transfer) EncodeBinary(w *io.BinWriter) {
|
|||
w.WriteBytes(t.To[:])
|
||||
w.WriteU32LE(t.Block)
|
||||
w.WriteU64LE(t.Timestamp)
|
||||
w.WriteU64LE(uint64(t.Amount))
|
||||
amountBytes := bigint.ToBytes(&t.Amount)
|
||||
w.WriteU64LE(uint64(len(amountBytes)))
|
||||
w.WriteBytes(amountBytes)
|
||||
}
|
||||
|
||||
// DecodeBinary implements io.Serializable interface.
|
||||
func (t *NEP5Transfer) DecodeBinary(r *io.BinReader) {
|
||||
_ = t.DecodeBinaryReturnCount(r)
|
||||
}
|
||||
|
||||
// DecodeBinaryReturnCount decodes NEP5Transfer and returns the number of bytes read.
|
||||
func (t *NEP5Transfer) DecodeBinaryReturnCount(r *io.BinReader) int {
|
||||
r.ReadBytes(t.Asset[:])
|
||||
r.ReadBytes(t.Tx[:])
|
||||
r.ReadBytes(t.From[:])
|
||||
r.ReadBytes(t.To[:])
|
||||
t.Block = r.ReadU32LE()
|
||||
t.Timestamp = r.ReadU64LE()
|
||||
t.Amount = int64(r.ReadU64LE())
|
||||
amountLen := r.ReadU64LE()
|
||||
amountBytes := make([]byte, amountLen)
|
||||
r.ReadBytes(amountBytes)
|
||||
t.Amount = *bigint.FromBytes(amountBytes)
|
||||
return util.Uint160Size*3 + 8 + 4 + (8 + len(amountBytes)) + +util.Uint256Size
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -40,7 +41,7 @@ func TestNEP5TransferLog_Append(t *testing.T) {
|
|||
|
||||
func TestNEP5Tracker_EncodeBinary(t *testing.T) {
|
||||
expected := &NEP5Tracker{
|
||||
Balance: int64(rand.Uint64()),
|
||||
Balance: *big.NewInt(int64(rand.Uint64())),
|
||||
LastUpdatedBlock: rand.Uint32(),
|
||||
}
|
||||
|
||||
|
@ -52,7 +53,7 @@ func TestNEP5Transfer_DecodeBinary(t *testing.T) {
|
|||
Asset: util.Uint160{1, 2, 3},
|
||||
From: util.Uint160{5, 6, 7},
|
||||
To: util.Uint160{8, 9, 10},
|
||||
Amount: 42,
|
||||
Amount: *big.NewInt(42),
|
||||
Block: 12345,
|
||||
Timestamp: 54321,
|
||||
Tx: util.Uint256{8, 5, 3},
|
||||
|
@ -64,12 +65,18 @@ func TestNEP5Transfer_DecodeBinary(t *testing.T) {
|
|||
func TestNEP5TransferSize(t *testing.T) {
|
||||
tr := randomTransfer(rand.New(rand.NewSource(0)))
|
||||
size := io.GetVarSize(tr)
|
||||
require.EqualValues(t, NEP5TransferSize, size)
|
||||
w := io.NewBufBinWriter()
|
||||
tr.EncodeBinary(w.BinWriter)
|
||||
require.NoError(t, w.Err)
|
||||
r := io.NewBinReaderFromBuf(w.Bytes())
|
||||
actualTr := &NEP5Transfer{}
|
||||
actual := actualTr.DecodeBinaryReturnCount(r)
|
||||
require.EqualValues(t, actual, size)
|
||||
}
|
||||
|
||||
func randomTransfer(r *rand.Rand) *NEP5Transfer {
|
||||
return &NEP5Transfer{
|
||||
Amount: int64(r.Uint64()),
|
||||
Amount: *big.NewInt(int64(r.Uint64())),
|
||||
Block: r.Uint32(),
|
||||
Asset: random.Uint160(),
|
||||
From: random.Uint160(),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package network
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"net"
|
||||
"strconv"
|
||||
|
@ -31,7 +32,7 @@ func (chain testChain) ApplyPolicyToTxSet([]*transaction.Transaction) []*transac
|
|||
func (chain testChain) GetConfig() config.ProtocolConfiguration {
|
||||
panic("TODO")
|
||||
}
|
||||
func (chain testChain) CalculateClaimable(int64, uint32, uint32) int64 {
|
||||
func (chain testChain) CalculateClaimable(*big.Int, uint32, uint32) *big.Int {
|
||||
panic("TODO")
|
||||
}
|
||||
|
||||
|
@ -123,11 +124,11 @@ func (chain testChain) GetMemPool() *mempool.Pool {
|
|||
panic("TODO")
|
||||
}
|
||||
|
||||
func (chain testChain) GetGoverningTokenBalance(acc util.Uint160) (int64, uint32) {
|
||||
func (chain testChain) GetGoverningTokenBalance(acc util.Uint160) (*big.Int, uint32) {
|
||||
panic("TODO")
|
||||
}
|
||||
|
||||
func (chain testChain) GetUtilityTokenBalance(uint160 util.Uint160) int64 {
|
||||
func (chain testChain) GetUtilityTokenBalance(uint160 util.Uint160) *big.Int {
|
||||
panic("TODO")
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
@ -512,7 +513,7 @@ func (s *Server) getNEP5Balances(ps request.Params) (interface{}, *response.Erro
|
|||
if err != nil {
|
||||
continue
|
||||
}
|
||||
amount := amountToString(bal.Balance, dec)
|
||||
amount := amountToString(&bal.Balance, dec)
|
||||
bs.Balances = append(bs.Balances, result.NEP5Balance{
|
||||
Asset: h,
|
||||
Amount: amount,
|
||||
|
@ -547,8 +548,8 @@ func (s *Server) getNEP5Transfers(ps request.Params) (interface{}, *response.Err
|
|||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if tr.Amount > 0 { // token was received
|
||||
transfer.Amount = amountToString(tr.Amount, d)
|
||||
if tr.Amount.Sign() > 0 { // token was received
|
||||
transfer.Amount = amountToString(&tr.Amount, d)
|
||||
if !tr.From.Equals(util.Uint160{}) {
|
||||
transfer.Address = address.Uint160ToString(tr.From)
|
||||
}
|
||||
|
@ -556,7 +557,7 @@ func (s *Server) getNEP5Transfers(ps request.Params) (interface{}, *response.Err
|
|||
return nil
|
||||
}
|
||||
|
||||
transfer.Amount = amountToString(-tr.Amount, d)
|
||||
transfer.Amount = amountToString(new(big.Int).Neg(&tr.Amount), d)
|
||||
if !tr.To.Equals(util.Uint160{}) {
|
||||
transfer.Address = address.Uint160ToString(tr.To)
|
||||
}
|
||||
|
@ -569,15 +570,14 @@ func (s *Server) getNEP5Transfers(ps request.Params) (interface{}, *response.Err
|
|||
return bs, nil
|
||||
}
|
||||
|
||||
func amountToString(amount int64, decimals int64) string {
|
||||
func amountToString(amount *big.Int, decimals int64) string {
|
||||
if decimals == 0 {
|
||||
return strconv.FormatInt(amount, 10)
|
||||
return amount.String()
|
||||
}
|
||||
pow := int64(math.Pow10(int(decimals)))
|
||||
q := amount / pow
|
||||
r := amount % pow
|
||||
if r == 0 {
|
||||
return strconv.FormatInt(q, 10)
|
||||
q, r := new(big.Int).DivMod(amount, big.NewInt(pow), new(big.Int))
|
||||
if r.Sign() == 0 {
|
||||
return q.String()
|
||||
}
|
||||
fs := fmt.Sprintf("%%d.%%0%dd", decimals)
|
||||
return fmt.Sprintf(fs, q, r)
|
||||
|
@ -783,11 +783,11 @@ func (s *Server) getUnclaimedGas(ps request.Params) (interface{}, *response.Erro
|
|||
}
|
||||
|
||||
neo, neoHeight := s.chain.GetGoverningTokenBalance(u)
|
||||
if neo == 0 {
|
||||
if neo.Sign() == 0 {
|
||||
return "0", nil
|
||||
}
|
||||
gas := s.chain.CalculateClaimable(neo, neoHeight, s.chain.BlockHeight()+1) // +1 as in C#, for the next block.
|
||||
return strconv.FormatInt(gas, 10), nil
|
||||
return gas.String(), nil
|
||||
}
|
||||
|
||||
// getValidators returns the current NEO consensus nodes information and voting status.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
|
@ -90,6 +91,6 @@ func (fs *FeerStub) FeePerByte() int64 {
|
|||
return 0
|
||||
}
|
||||
|
||||
func (fs *FeerStub) GetUtilityTokenBalance(acc util.Uint160) int64 {
|
||||
return 1000000 * native.GASFactor
|
||||
func (fs *FeerStub) GetUtilityTokenBalance(acc util.Uint160) *big.Int {
|
||||
return big.NewInt(1000000 * native.GASFactor)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
|
@ -270,7 +271,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
Timestamp: b.Timestamp,
|
||||
Asset: e.chain.UtilityTokenHash(),
|
||||
Address: "", // burn has empty receiver
|
||||
Amount: amountToString(int64(amount), 8),
|
||||
Amount: amountToString(big.NewInt(amount), 8),
|
||||
Index: b.Index,
|
||||
TxHash: b.Hash(),
|
||||
})
|
||||
|
@ -282,7 +283,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
Timestamp: b.Timestamp,
|
||||
Asset: e.chain.UtilityTokenHash(),
|
||||
Address: "", // minted from network fees.
|
||||
Amount: amountToString(int64(netFee), 8),
|
||||
Amount: amountToString(big.NewInt(netFee), 8),
|
||||
Index: b.Index,
|
||||
TxHash: b.Hash(),
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue