mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-12-12 01:10:36 +00:00
Merge pull request #1760 from nspcc-dev/rpc-compatibility-fixes-and-docs
[2.x] RPC compatibility (and other) fixes and docs
This commit is contained in:
commit
3f50f90dc5
17 changed files with 293 additions and 101 deletions
73
docs/rpc.md
73
docs/rpc.md
|
@ -46,11 +46,15 @@ which would yield the response:
|
||||||
| `getclaimable` |
|
| `getclaimable` |
|
||||||
| `getconnectioncount` |
|
| `getconnectioncount` |
|
||||||
| `getcontractstate` |
|
| `getcontractstate` |
|
||||||
|
| `getminimumnetworkfee` |
|
||||||
| `getnep5balances` |
|
| `getnep5balances` |
|
||||||
| `getnep5transfers` |
|
| `getnep5transfers` |
|
||||||
| `getpeers` |
|
| `getpeers` |
|
||||||
|
| `getproof` |
|
||||||
| `getrawmempool` |
|
| `getrawmempool` |
|
||||||
| `getrawtransaction` |
|
| `getrawtransaction` |
|
||||||
|
| `getstateheight` |
|
||||||
|
| `getstateroot` |
|
||||||
| `getstorage` |
|
| `getstorage` |
|
||||||
| `gettransactionheight` |
|
| `gettransactionheight` |
|
||||||
| `gettxout` |
|
| `gettxout` |
|
||||||
|
@ -65,9 +69,78 @@ which would yield the response:
|
||||||
| `sendrawtransaction` |
|
| `sendrawtransaction` |
|
||||||
| `submitblock` |
|
| `submitblock` |
|
||||||
| `validateaddress` |
|
| `validateaddress` |
|
||||||
|
| `verifyproof` |
|
||||||
|
|
||||||
#### Implementation notices
|
#### Implementation notices
|
||||||
|
|
||||||
|
##### `getaccountstate`
|
||||||
|
|
||||||
|
The order of assets in `balances` section may differ from the one returned by
|
||||||
|
C# implementation. Assets can still be identified by their hashes so it
|
||||||
|
shouldn't be an issue.
|
||||||
|
|
||||||
|
##### `getapplicationlog`
|
||||||
|
|
||||||
|
Error handling for incorrect stack items differs with C# implementation. C#
|
||||||
|
implementation substitutes `stack` and `state` arrays with "error: recursive
|
||||||
|
reference" string if there are any invalid items. NeoGo never does this, for
|
||||||
|
bad `state` items it uses byte array susbstitute with message "bad
|
||||||
|
notification: ..." (may vary depending on the problem), for incorrect `stack`
|
||||||
|
items it just omits them (still returning valid ones).
|
||||||
|
|
||||||
|
##### `getassetstate`
|
||||||
|
|
||||||
|
It returns "NEO" for NEO and "NEOGas" for GAS in the `name` field instead of
|
||||||
|
language-aware JSON structures.
|
||||||
|
|
||||||
|
##### `getblock` and `getrawtransaction`
|
||||||
|
|
||||||
|
In their verbose outputs neo-go can omit some fields with default values for
|
||||||
|
transactions, this includes:
|
||||||
|
* zero "nonce" for Miner transactions (usually nonce is not zero)
|
||||||
|
* zero "gas" for Invocation transactions (most of the time it is zero).
|
||||||
|
|
||||||
|
##### `getclaimable`
|
||||||
|
|
||||||
|
`claimable` array ordering differs, neo-go orders entries there by the
|
||||||
|
`end_height` field, while C# implementation orders by `txid`.
|
||||||
|
|
||||||
|
##### `getcontractstate`
|
||||||
|
|
||||||
|
C# implementation doesn't return `Payable` flag in its output, neo-go has
|
||||||
|
`is_payable` field in `properties` for that.
|
||||||
|
|
||||||
|
##### `getnep5transfers`
|
||||||
|
|
||||||
|
`received` and `sent` entries are sorted differently, C# node uses
|
||||||
|
chronological order and neo-go uses reverse chronological order (which is
|
||||||
|
important for paging support, see Extensions section down below).
|
||||||
|
|
||||||
|
##### `getrawmempool`
|
||||||
|
|
||||||
|
neo-go doesn't support boolean parameter to `getrawmempool` for unverified
|
||||||
|
transactions request because neo-go actually never stores unverified
|
||||||
|
transactions in the mempool.
|
||||||
|
|
||||||
|
##### `getunclaimed`
|
||||||
|
|
||||||
|
Numeric results are wrapped into strings in neo-go (the same way fees are
|
||||||
|
encoded) to prevent floating point rounding errors.
|
||||||
|
|
||||||
|
##### `getunspents`
|
||||||
|
|
||||||
|
neo-go uses standard "0xhash" syntax for `txid` and `asset_hash` fields
|
||||||
|
whereas C# module doesn't add "0x" prefix. The order of `balance` or `unspent`
|
||||||
|
entries can differ. neo-go returns all UTXO assets while C# module only tracks
|
||||||
|
and returns NEO and GAS.
|
||||||
|
|
||||||
|
##### `getutxotransfers`
|
||||||
|
|
||||||
|
`transactions` are sorted differently, C# node uses chronological order and
|
||||||
|
neo-go uses reverse chronological order (which is important for paging
|
||||||
|
support, see Extensions section down below).
|
||||||
|
|
||||||
|
|
||||||
##### `invokefunction` and `invoke`
|
##### `invokefunction` and `invoke`
|
||||||
|
|
||||||
neo-go's implementation of `invokefunction` and `invoke` does not return `tx`
|
neo-go's implementation of `invokefunction` and `invoke` does not return `tx`
|
||||||
|
|
|
@ -3,6 +3,7 @@ package core
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"math/big"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
@ -31,7 +32,7 @@ import (
|
||||||
// Tuning parameters.
|
// Tuning parameters.
|
||||||
const (
|
const (
|
||||||
headerBatchCount = 2000
|
headerBatchCount = 2000
|
||||||
version = "0.0.9"
|
version = "0.0.10"
|
||||||
|
|
||||||
// This one comes from C# code and it's different from the constant used
|
// This one comes from C# code and it's different from the constant used
|
||||||
// when creating an asset with Neo.Asset.Create interop call. It looks
|
// when creating an asset with Neo.Asset.Create interop call. It looks
|
||||||
|
@ -551,9 +552,9 @@ func (bc *Blockchain) processHeader(h *block.Header, batch storage.Batch, header
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// bc.GetHeaderHash(int(endHeight)) returns sum of all system fees for blocks up to h.
|
// GetSystemFeeAmount returns sum of all system fees for blocks up to h.
|
||||||
// and 0 if no such block exists.
|
// and 0 if no such block exists.
|
||||||
func (bc *Blockchain) getSystemFeeAmount(h util.Uint256) uint32 {
|
func (bc *Blockchain) GetSystemFeeAmount(h util.Uint256) uint32 {
|
||||||
_, sf, _ := bc.dao.GetBlock(h)
|
_, sf, _ := bc.dao.GetBlock(h)
|
||||||
return sf
|
return sf
|
||||||
}
|
}
|
||||||
|
@ -582,7 +583,7 @@ func (bc *Blockchain) GetStateRoot(height uint32) (*state.MPTRootState, error) {
|
||||||
func (bc *Blockchain) storeBlock(block *block.Block) error {
|
func (bc *Blockchain) storeBlock(block *block.Block) error {
|
||||||
cache := dao.NewCached(bc.dao)
|
cache := dao.NewCached(bc.dao)
|
||||||
appExecResults := make([]*state.AppExecResult, 0, len(block.Transactions))
|
appExecResults := make([]*state.AppExecResult, 0, len(block.Transactions))
|
||||||
fee := bc.getSystemFeeAmount(block.PrevHash)
|
fee := bc.GetSystemFeeAmount(block.PrevHash)
|
||||||
for _, tx := range block.Transactions {
|
for _, tx := range block.Transactions {
|
||||||
fee += uint32(bc.SystemFee(tx).IntegralValue())
|
fee += uint32(bc.SystemFee(tx).IntegralValue())
|
||||||
}
|
}
|
||||||
|
@ -688,6 +689,7 @@ func (bc *Blockchain) storeBlock(block *block.Block) error {
|
||||||
Precision: t.Precision,
|
Precision: t.Precision,
|
||||||
Owner: t.Owner,
|
Owner: t.Owner,
|
||||||
Admin: t.Admin,
|
Admin: t.Admin,
|
||||||
|
Issuer: t.Admin,
|
||||||
Expiration: bc.BlockHeight() + registeredAssetLifetime,
|
Expiration: bc.BlockHeight() + registeredAssetLifetime,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -943,16 +945,23 @@ func (bc *Blockchain) processNEP5Transfer(cache *dao.Cached, transfer *state.NEP
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
bs := balances.Trackers[transfer.Asset]
|
bs := balances.Trackers[transfer.Asset]
|
||||||
bs.Balance -= transfer.Amount
|
if bs.Balance == nil {
|
||||||
bs.LastUpdatedBlock = transfer.Block
|
return
|
||||||
balances.Trackers[transfer.Asset] = bs
|
}
|
||||||
|
bs.Balance.Sub(bs.Balance, transfer.Amount)
|
||||||
|
if bs.Balance.Sign() > 0 {
|
||||||
|
bs.LastUpdatedBlock = transfer.Block
|
||||||
|
balances.Trackers[transfer.Asset] = bs
|
||||||
|
} else {
|
||||||
|
delete(balances.Trackers, transfer.Asset)
|
||||||
|
}
|
||||||
|
|
||||||
transfer.Amount = -transfer.Amount
|
transfer.Amount.Neg(transfer.Amount)
|
||||||
isBig, err := cache.AppendNEP5Transfer(transfer.From, balances.NextTransferBatch, transfer)
|
isBig, err := cache.AppendNEP5Transfer(transfer.From, balances.NextTransferBatch, transfer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
transfer.Amount = -transfer.Amount
|
transfer.Amount.Neg(transfer.Amount)
|
||||||
if isBig {
|
if isBig {
|
||||||
balances.NextTransferBatch++
|
balances.NextTransferBatch++
|
||||||
}
|
}
|
||||||
|
@ -966,7 +975,10 @@ func (bc *Blockchain) processNEP5Transfer(cache *dao.Cached, transfer *state.NEP
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
bs := balances.Trackers[transfer.Asset]
|
bs := balances.Trackers[transfer.Asset]
|
||||||
bs.Balance += transfer.Amount
|
if bs.Balance == nil {
|
||||||
|
bs.Balance = new(big.Int)
|
||||||
|
}
|
||||||
|
bs.Balance.Add(bs.Balance, transfer.Amount)
|
||||||
bs.LastUpdatedBlock = transfer.Block
|
bs.LastUpdatedBlock = transfer.Block
|
||||||
balances.Trackers[transfer.Asset] = bs
|
balances.Trackers[transfer.Asset] = bs
|
||||||
|
|
||||||
|
@ -1502,9 +1514,9 @@ func (bc *Blockchain) CalculateClaimable(value util.Fixed8, startHeight, endHeig
|
||||||
startHeight++
|
startHeight++
|
||||||
}
|
}
|
||||||
h := bc.GetHeaderHash(int(startHeight - 1))
|
h := bc.GetHeaderHash(int(startHeight - 1))
|
||||||
feeStart := bc.getSystemFeeAmount(h)
|
feeStart := bc.GetSystemFeeAmount(h)
|
||||||
h = bc.GetHeaderHash(int(endHeight - 1))
|
h = bc.GetHeaderHash(int(endHeight - 1))
|
||||||
feeEnd := bc.getSystemFeeAmount(h)
|
feeEnd := bc.GetSystemFeeAmount(h)
|
||||||
|
|
||||||
sysFeeTotal := util.Fixed8(feeEnd - feeStart)
|
sysFeeTotal := util.Fixed8(feeEnd - feeStart)
|
||||||
ratio := value / 100000000
|
ratio := value / 100000000
|
||||||
|
@ -1576,11 +1588,44 @@ func (bc *Blockchain) NetworkFee(t *transaction.Transaction) util.Fixed8 {
|
||||||
|
|
||||||
// SystemFee returns system fee.
|
// SystemFee returns system fee.
|
||||||
func (bc *Blockchain) SystemFee(t *transaction.Transaction) util.Fixed8 {
|
func (bc *Blockchain) SystemFee(t *transaction.Transaction) util.Fixed8 {
|
||||||
if t.Type == transaction.InvocationType {
|
switch t.Type {
|
||||||
|
case transaction.InvocationType:
|
||||||
inv := t.Data.(*transaction.InvocationTX)
|
inv := t.Data.(*transaction.InvocationTX)
|
||||||
if inv.Version >= 1 {
|
return inv.Gas
|
||||||
return inv.Gas
|
case transaction.IssueType:
|
||||||
|
if t.Version >= 1 {
|
||||||
|
return util.Fixed8(0)
|
||||||
}
|
}
|
||||||
|
var iszero = true
|
||||||
|
for i := range t.Outputs {
|
||||||
|
asset := t.Outputs[i].AssetID
|
||||||
|
if asset != UtilityTokenID() && asset != GoverningTokenID() {
|
||||||
|
iszero = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if iszero {
|
||||||
|
return util.Fixed8(0)
|
||||||
|
}
|
||||||
|
case transaction.RegisterType:
|
||||||
|
reg := t.Data.(*transaction.RegisterTX)
|
||||||
|
if reg.AssetType == transaction.GoverningToken || reg.AssetType == transaction.UtilityToken {
|
||||||
|
return util.Fixed8(0)
|
||||||
|
}
|
||||||
|
case transaction.StateType:
|
||||||
|
res := util.Fixed8(0)
|
||||||
|
st := t.Data.(*transaction.StateTX)
|
||||||
|
for _, desc := range st.Descriptors {
|
||||||
|
if desc.Type == transaction.Validator && desc.Field == "Registered" {
|
||||||
|
for i := range desc.Value {
|
||||||
|
if desc.Value[i] != 0 {
|
||||||
|
res += util.Fixed8FromInt64(1000)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
return bc.GetConfig().SystemFee.TryGetValue(t.Type)
|
return bc.GetConfig().SystemFee.TryGetValue(t.Type)
|
||||||
}
|
}
|
||||||
|
@ -2232,23 +2277,14 @@ func (bc *Blockchain) GetEnrollments() ([]*state.Validator, error) {
|
||||||
for _, validator := range validators {
|
for _, validator := range validators {
|
||||||
if validator.Registered {
|
if validator.Registered {
|
||||||
result = append(result, validator)
|
result = append(result, validator)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
for _, sbValidator := range uniqueSBValidators {
|
||||||
for _, sBValidator := range uniqueSBValidators {
|
if validator.PublicKey.Equal(sbValidator) {
|
||||||
isAdded := false
|
result = append(result, validator)
|
||||||
for _, v := range result {
|
|
||||||
if v.PublicKey == sBValidator {
|
|
||||||
isAdded = true
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !isAdded {
|
|
||||||
result = append(result, &state.Validator{
|
|
||||||
PublicKey: sBValidator,
|
|
||||||
Registered: false,
|
|
||||||
Votes: 0,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ type Blockchainer interface {
|
||||||
GetStateRoot(height uint32) (*state.MPTRootState, error)
|
GetStateRoot(height uint32) (*state.MPTRootState, error)
|
||||||
GetStorageItem(scripthash util.Uint160, key []byte) *state.StorageItem
|
GetStorageItem(scripthash util.Uint160, key []byte) *state.StorageItem
|
||||||
GetStorageItems(hash util.Uint160) (map[string]*state.StorageItem, error)
|
GetStorageItems(hash util.Uint160) (map[string]*state.StorageItem, error)
|
||||||
|
GetSystemFeeAmount(h util.Uint256) uint32
|
||||||
GetTestVM(tx *transaction.Transaction) *vm.VM
|
GetTestVM(tx *transaction.Transaction) *vm.VM
|
||||||
GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error)
|
GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error)
|
||||||
GetUnspentCoinState(util.Uint256) *state.UnspentCoin
|
GetUnspentCoinState(util.Uint256) *state.UnspentCoin
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
// NEP5Tracker contains info about a single account in a NEP5 contract.
|
// NEP5Tracker contains info about a single account in a NEP5 contract.
|
||||||
type NEP5Tracker struct {
|
type NEP5Tracker struct {
|
||||||
// Balance is the current balance of the account.
|
// 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
|
// LastUpdatedBlock is a number of block when last `transfer` to or from the
|
||||||
// account occured.
|
// account occured.
|
||||||
LastUpdatedBlock uint32
|
LastUpdatedBlock uint32
|
||||||
|
@ -25,7 +25,7 @@ type TransferLog struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NEP5TransferSize is a size of a marshaled NEP5Transfer struct in bytes.
|
// NEP5TransferSize is a size of a marshaled NEP5Transfer struct in bytes.
|
||||||
const NEP5TransferSize = util.Uint160Size*3 + 8 + 4 + 4 + util.Uint256Size + 4
|
const NEP5TransferSize = util.Uint160Size*3 + amountSize + 4 + 4 + util.Uint256Size + 4
|
||||||
|
|
||||||
// NEP5Transfer represents a single NEP5 Transfer event.
|
// NEP5Transfer represents a single NEP5 Transfer event.
|
||||||
type NEP5Transfer struct {
|
type NEP5Transfer struct {
|
||||||
|
@ -37,7 +37,7 @@ type NEP5Transfer struct {
|
||||||
To util.Uint160
|
To util.Uint160
|
||||||
// Amount is the amount of tokens transferred.
|
// Amount is the amount of tokens transferred.
|
||||||
// It is negative when tokens are sent and positive if they are received.
|
// 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 is a number of block when the event occured.
|
||||||
Block uint32
|
Block uint32
|
||||||
// Timestamp is the timestamp of the block where transfer occured.
|
// Timestamp is the timestamp of the block where transfer occured.
|
||||||
|
@ -48,6 +48,8 @@ type NEP5Transfer struct {
|
||||||
Index uint32
|
Index uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const amountSize = 32
|
||||||
|
|
||||||
// NEP5Balances is a map of the NEP5 contract hashes
|
// NEP5Balances is a map of the NEP5 contract hashes
|
||||||
// to the corresponding structures.
|
// to the corresponding structures.
|
||||||
type NEP5Balances struct {
|
type NEP5Balances struct {
|
||||||
|
@ -143,13 +145,13 @@ func (lg *TransferLog) Size() int {
|
||||||
|
|
||||||
// EncodeBinary implements io.Serializable interface.
|
// EncodeBinary implements io.Serializable interface.
|
||||||
func (t *NEP5Tracker) EncodeBinary(w *io.BinWriter) {
|
func (t *NEP5Tracker) EncodeBinary(w *io.BinWriter) {
|
||||||
w.WriteU64LE(uint64(t.Balance))
|
w.WriteVarBytes(emit.IntToBytes(t.Balance))
|
||||||
w.WriteU32LE(t.LastUpdatedBlock)
|
w.WriteU32LE(t.LastUpdatedBlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeBinary implements io.Serializable interface.
|
// DecodeBinary implements io.Serializable interface.
|
||||||
func (t *NEP5Tracker) DecodeBinary(r *io.BinReader) {
|
func (t *NEP5Tracker) DecodeBinary(r *io.BinReader) {
|
||||||
t.Balance = int64(r.ReadU64LE())
|
t.Balance = emit.BytesToInt(r.ReadVarBytes(amountSize))
|
||||||
t.LastUpdatedBlock = r.ReadU32LE()
|
t.LastUpdatedBlock = r.ReadU32LE()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,7 +196,7 @@ func NEP5TransferFromNotification(ne NotificationEvent, txHash util.Uint256, hei
|
||||||
Asset: ne.ScriptHash,
|
Asset: ne.ScriptHash,
|
||||||
From: fromAddr,
|
From: fromAddr,
|
||||||
To: toAddr,
|
To: toAddr,
|
||||||
Amount: amount.Int64(),
|
Amount: amount,
|
||||||
Block: height,
|
Block: height,
|
||||||
Timestamp: time,
|
Timestamp: time,
|
||||||
Tx: txHash,
|
Tx: txHash,
|
||||||
|
@ -212,7 +214,19 @@ func (t *NEP5Transfer) EncodeBinary(w *io.BinWriter) {
|
||||||
w.WriteBytes(t.To[:])
|
w.WriteBytes(t.To[:])
|
||||||
w.WriteU32LE(t.Block)
|
w.WriteU32LE(t.Block)
|
||||||
w.WriteU32LE(t.Timestamp)
|
w.WriteU32LE(t.Timestamp)
|
||||||
w.WriteU64LE(uint64(t.Amount))
|
am := emit.IntToBytes(t.Amount)
|
||||||
|
if len(am) > amountSize {
|
||||||
|
panic("bad integer length")
|
||||||
|
}
|
||||||
|
fillerLen := amountSize - len(am)
|
||||||
|
w.WriteBytes(am)
|
||||||
|
var filler byte
|
||||||
|
if t.Amount.Sign() < 0 {
|
||||||
|
filler = 0xff
|
||||||
|
}
|
||||||
|
for i := 0; i < fillerLen; i++ {
|
||||||
|
w.WriteB(filler)
|
||||||
|
}
|
||||||
w.WriteU32LE(t.Index)
|
w.WriteU32LE(t.Index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,6 +238,8 @@ func (t *NEP5Transfer) DecodeBinary(r *io.BinReader) {
|
||||||
r.ReadBytes(t.To[:])
|
r.ReadBytes(t.To[:])
|
||||||
t.Block = r.ReadU32LE()
|
t.Block = r.ReadU32LE()
|
||||||
t.Timestamp = r.ReadU32LE()
|
t.Timestamp = r.ReadU32LE()
|
||||||
t.Amount = int64(r.ReadU64LE())
|
amount := make([]byte, amountSize)
|
||||||
|
r.ReadBytes(amount)
|
||||||
|
t.Amount = emit.BytesToInt(amount)
|
||||||
t.Index = r.ReadU32LE()
|
t.Index = r.ReadU32LE()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package state
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -41,7 +42,7 @@ func TestNEP5TransferLog_Append(t *testing.T) {
|
||||||
|
|
||||||
func TestNEP5Tracker_EncodeBinary(t *testing.T) {
|
func TestNEP5Tracker_EncodeBinary(t *testing.T) {
|
||||||
expected := &NEP5Tracker{
|
expected := &NEP5Tracker{
|
||||||
Balance: int64(rand.Uint64()),
|
Balance: big.NewInt(int64(rand.Uint64())),
|
||||||
LastUpdatedBlock: rand.Uint32(),
|
LastUpdatedBlock: rand.Uint32(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +54,7 @@ func TestNEP5Transfer_DecodeBinary(t *testing.T) {
|
||||||
Asset: util.Uint160{1, 2, 3},
|
Asset: util.Uint160{1, 2, 3},
|
||||||
From: util.Uint160{5, 6, 7},
|
From: util.Uint160{5, 6, 7},
|
||||||
To: util.Uint160{8, 9, 10},
|
To: util.Uint160{8, 9, 10},
|
||||||
Amount: 42,
|
Amount: big.NewInt(42),
|
||||||
Block: 12345,
|
Block: 12345,
|
||||||
Timestamp: 54321,
|
Timestamp: 54321,
|
||||||
Tx: util.Uint256{8, 5, 3},
|
Tx: util.Uint256{8, 5, 3},
|
||||||
|
@ -70,7 +71,7 @@ func TestNEP5TransferSize(t *testing.T) {
|
||||||
|
|
||||||
func randomTransfer(r *rand.Rand) *NEP5Transfer {
|
func randomTransfer(r *rand.Rand) *NEP5Transfer {
|
||||||
return &NEP5Transfer{
|
return &NEP5Transfer{
|
||||||
Amount: int64(r.Uint64()),
|
Amount: big.NewInt(int64(r.Uint64())),
|
||||||
Block: r.Uint32(),
|
Block: r.Uint32(),
|
||||||
Asset: random.Uint160(),
|
Asset: random.Uint160(),
|
||||||
From: random.Uint160(),
|
From: random.Uint160(),
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
package transaction
|
package transaction
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
// AssetType represents a NEO asset type.
|
// AssetType represents a NEO asset type.
|
||||||
type AssetType uint8
|
type AssetType uint8
|
||||||
|
|
||||||
|
@ -14,3 +19,68 @@ const (
|
||||||
Invoice AssetType = DutyFlag | 0x18
|
Invoice AssetType = DutyFlag | 0x18
|
||||||
Token AssetType = CreditFlag | 0x20
|
Token AssetType = CreditFlag | 0x20
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// String implements Stringer interface.
|
||||||
|
func (a AssetType) String() string {
|
||||||
|
switch a {
|
||||||
|
case CreditFlag:
|
||||||
|
return "CreditFlag"
|
||||||
|
case DutyFlag:
|
||||||
|
return "DutyFlag"
|
||||||
|
case GoverningToken:
|
||||||
|
return "GoverningToken"
|
||||||
|
case UtilityToken:
|
||||||
|
return "UtilityToken"
|
||||||
|
case Currency:
|
||||||
|
return "Currency"
|
||||||
|
case Share:
|
||||||
|
return "Share"
|
||||||
|
case Invoice:
|
||||||
|
return "Invoice"
|
||||||
|
case Token:
|
||||||
|
return "Token"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("Unknonwn (%d)", a)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements the json marshaller interface.
|
||||||
|
func (a AssetType) MarshalJSON() ([]byte, error) {
|
||||||
|
return []byte(`"` + a.String() + `"`), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||||
|
func (a *AssetType) UnmarshalJSON(data []byte) error {
|
||||||
|
l := len(data)
|
||||||
|
if l < 2 || data[0] != '"' || data[l-1] != '"' {
|
||||||
|
return errors.New("wrong format")
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
*a, err = AssetTypeFromString(string(data[1 : l-1]))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssetTypeFromString converts string into AssetType.
|
||||||
|
func AssetTypeFromString(s string) (AssetType, error) {
|
||||||
|
switch s {
|
||||||
|
case "CreditFlag":
|
||||||
|
return CreditFlag, nil
|
||||||
|
case "DutyFlag":
|
||||||
|
return DutyFlag, nil
|
||||||
|
case "GoverningToken":
|
||||||
|
return GoverningToken, nil
|
||||||
|
case "UtilityToken":
|
||||||
|
return UtilityToken, nil
|
||||||
|
case "Currency":
|
||||||
|
return Currency, nil
|
||||||
|
case "Share":
|
||||||
|
return Share, nil
|
||||||
|
case "Invoice":
|
||||||
|
return Invoice, nil
|
||||||
|
case "Token":
|
||||||
|
return Token, nil
|
||||||
|
default:
|
||||||
|
return 0, errors.New("bad asset type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -67,18 +67,18 @@ func (tx *PublishTX) EncodeBinary(bw *io.BinWriter) {
|
||||||
// publishedContract is a JSON wrapper for PublishTransaction
|
// publishedContract is a JSON wrapper for PublishTransaction
|
||||||
type publishedContract struct {
|
type publishedContract struct {
|
||||||
Code publishedCode `json:"code"`
|
Code publishedCode `json:"code"`
|
||||||
NeedStorage bool `json:"needstorage,omitempty"`
|
NeedStorage bool `json:"needstorage"`
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name"`
|
||||||
CodeVersion string `json:"version,omitempty"`
|
CodeVersion string `json:"version"`
|
||||||
Author string `json:"author,omitempty"`
|
Author string `json:"author"`
|
||||||
Email string `json:"email,omitempty"`
|
Email string `json:"email"`
|
||||||
Description string `json:"description,omitempty"`
|
Description string `json:"description"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// publishedCode is a JSON wrapper for PublishTransaction Code
|
// publishedCode is a JSON wrapper for PublishTransaction Code
|
||||||
type publishedCode struct {
|
type publishedCode struct {
|
||||||
Hash util.Uint160 `json:"hash,omitempty"`
|
Hash util.Uint160 `json:"hash"`
|
||||||
Script string `json:"script,omitempty"`
|
Script string `json:"script"`
|
||||||
ParamList []smartcontract.ParamType `json:"parameters,omitempty"`
|
ParamList []smartcontract.ParamType `json:"parameters"`
|
||||||
ReturnType smartcontract.ParamType `json:"returntype,omitempty"`
|
ReturnType smartcontract.ParamType `json:"returntype"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,10 +56,10 @@ func (tx *RegisterTX) EncodeBinary(bw *io.BinWriter) {
|
||||||
|
|
||||||
// registeredAsset is a wrapper for RegisterTransaction
|
// registeredAsset is a wrapper for RegisterTransaction
|
||||||
type registeredAsset struct {
|
type registeredAsset struct {
|
||||||
AssetType AssetType `json:"type,omitempty"`
|
AssetType AssetType `json:"type"`
|
||||||
Name json.RawMessage `json:"name,omitempty"`
|
Name json.RawMessage `json:"name"`
|
||||||
Amount util.Fixed8 `json:"amount,omitempty"`
|
Amount util.Fixed8 `json:"amount"`
|
||||||
Precision uint8 `json:"precision,omitempty"`
|
Precision uint8 `json:"precision"`
|
||||||
Owner keys.PublicKey `json:"owner,omitempty"`
|
Owner keys.PublicKey `json:"owner"`
|
||||||
Admin string `json:"admin,omitempty"`
|
Admin string `json:"admin"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,6 +123,9 @@ func (chain testChain) GetStateRoot(height uint32) (*state.MPTRootState, error)
|
||||||
func (chain testChain) GetStorageItem(scripthash util.Uint160, key []byte) *state.StorageItem {
|
func (chain testChain) GetStorageItem(scripthash util.Uint160, key []byte) *state.StorageItem {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
|
func (chain testChain) GetSystemFeeAmount(h util.Uint256) uint32 {
|
||||||
|
panic("TODO")
|
||||||
|
}
|
||||||
func (chain testChain) GetTestVM(tx *transaction.Transaction) *vm.VM {
|
func (chain testChain) GetTestVM(tx *transaction.Transaction) *vm.VM {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,7 +178,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
||||||
invoke: func(c *Client) (interface{}, error) {
|
invoke: func(c *Client) (interface{}, error) {
|
||||||
return c.GetAssetState(util.Uint256{})
|
return c.GetAssetState(util.Uint256{})
|
||||||
},
|
},
|
||||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":"0xc56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b","type":0,"name":"NEO","amount":"100000000","available":"100000000","precision":0,"owner":"00","admin":"Abf2qMs1pzQb8kYk9RuxtUb9jtRKJVuBJt","issuer":"AFmseVrdL9f9oyCzZefL9tG6UbvhPbdYzM","expiration":4000000,"is_frozen":false}}`,
|
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":"0xc56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b","type":"GoverningToken","name":"NEO","amount":"100000000","available":"100000000","precision":0,"owner":"00","admin":"Abf2qMs1pzQb8kYk9RuxtUb9jtRKJVuBJt","issuer":"AFmseVrdL9f9oyCzZefL9tG6UbvhPbdYzM","expiration":4000000,"frozen":false}}`,
|
||||||
result: func(c *Client) interface{} {
|
result: func(c *Client) interface{} {
|
||||||
return &result.AssetState{
|
return &result.AssetState{
|
||||||
ID: core.GoverningTokenID(),
|
ID: core.GoverningTokenID(),
|
||||||
|
@ -517,25 +517,25 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
||||||
invoke: func(c *Client) (interface{}, error) {
|
invoke: func(c *Client) (interface{}, error) {
|
||||||
return c.GetPeers()
|
return c.GetPeers()
|
||||||
},
|
},
|
||||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"unconnected":[{"address":"172.200.0.1","port":"20333"}],"connected":[{"address":"127.0.0.1","port":"20335"}],"bad":[{"address":"172.200.0.254","port":"20332"}]}}`,
|
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"unconnected":[{"address":"172.200.0.1","port":20333}],"connected":[{"address":"127.0.0.1","port":20335}],"bad":[{"address":"172.200.0.254","port":20332}]}}`,
|
||||||
result: func(c *Client) interface{} {
|
result: func(c *Client) interface{} {
|
||||||
return &result.GetPeers{
|
return &result.GetPeers{
|
||||||
Unconnected: result.Peers{
|
Unconnected: result.Peers{
|
||||||
{
|
{
|
||||||
Address: "172.200.0.1",
|
Address: "172.200.0.1",
|
||||||
Port: "20333",
|
Port: 20333,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Connected: result.Peers{
|
Connected: result.Peers{
|
||||||
{
|
{
|
||||||
Address: "127.0.0.1",
|
Address: "127.0.0.1",
|
||||||
Port: "20335",
|
Port: 20335,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Bad: result.Peers{
|
Bad: result.Peers{
|
||||||
{
|
{
|
||||||
Address: "172.200.0.254",
|
Address: "172.200.0.254",
|
||||||
Port: "20332",
|
Port: 20332,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ type AssetState struct {
|
||||||
Admin string `json:"admin"`
|
Admin string `json:"admin"`
|
||||||
Issuer string `json:"issuer"`
|
Issuer string `json:"issuer"`
|
||||||
Expiration uint32 `json:"expiration"`
|
Expiration uint32 `json:"expiration"`
|
||||||
IsFrozen bool `json:"is_frozen"`
|
IsFrozen bool `json:"frozen"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAssetState creates a new Asset wrapper.
|
// NewAssetState creates a new Asset wrapper.
|
||||||
|
|
|
@ -48,7 +48,7 @@ func NewBlock(b *block.Block, chain core.Blockchainer) Block {
|
||||||
Base: &b.Base,
|
Base: &b.Base,
|
||||||
BlockMetadataAndTx: BlockMetadataAndTx{
|
BlockMetadataAndTx: BlockMetadataAndTx{
|
||||||
Size: io.GetVarSize(b),
|
Size: io.GetVarSize(b),
|
||||||
Confirmations: chain.BlockHeight() - b.Index - 1,
|
Confirmations: chain.BlockHeight() - b.Index + 1,
|
||||||
Tx: make([]Tx, 0, len(b.Transactions)),
|
Tx: make([]Tx, 0, len(b.Transactions)),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package result
|
package result
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ type (
|
||||||
// Peer represents the peer.
|
// Peer represents the peer.
|
||||||
Peer struct {
|
Peer struct {
|
||||||
Address string `json:"address"`
|
Address string `json:"address"`
|
||||||
Port string `json:"port"`
|
Port uint16 `json:"port"`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -50,9 +51,10 @@ func (g *GetPeers) AddBad(addrs []string) {
|
||||||
func (p *Peers) addPeers(addrs []string) {
|
func (p *Peers) addPeers(addrs []string) {
|
||||||
for i := range addrs {
|
for i := range addrs {
|
||||||
addressParts := strings.Split(addrs[i], ":")
|
addressParts := strings.Split(addrs[i], ":")
|
||||||
|
port, _ := strconv.Atoi(addressParts[1]) // We know it's a good port number.
|
||||||
peer := Peer{
|
peer := Peer{
|
||||||
Address: addressParts[0],
|
Address: addressParts[0],
|
||||||
Port: addressParts[1],
|
Port: uint16(port),
|
||||||
}
|
}
|
||||||
|
|
||||||
*p = append(*p, peer)
|
*p = append(*p, peer)
|
||||||
|
|
|
@ -20,7 +20,7 @@ func TestGetPeers(t *testing.T) {
|
||||||
require.Equal(t, 1, len(gp.Connected))
|
require.Equal(t, 1, len(gp.Connected))
|
||||||
require.Equal(t, 1, len(gp.Bad))
|
require.Equal(t, 1, len(gp.Bad))
|
||||||
require.Equal(t, "192.168.0.1", gp.Connected[0].Address)
|
require.Equal(t, "192.168.0.1", gp.Connected[0].Address)
|
||||||
require.Equal(t, "10333", gp.Connected[0].Port)
|
require.Equal(t, uint16(10333), gp.Connected[0].Port)
|
||||||
require.Equal(t, "127.0.0.1", gp.Bad[0].Address)
|
require.Equal(t, "127.0.0.1", gp.Bad[0].Address)
|
||||||
require.Equal(t, "20333", gp.Bad[0].Port)
|
require.Equal(t, uint16(20333), gp.Bad[0].Port)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ func NewTxOutput(out *transaction.Output) *TransactionOutput {
|
||||||
|
|
||||||
return &TransactionOutput{
|
return &TransactionOutput{
|
||||||
N: out.Position,
|
N: out.Position,
|
||||||
Asset: "0x" + out.AssetID.String(),
|
Asset: "0x" + out.AssetID.StringLE(),
|
||||||
Value: out.Amount,
|
Value: out.Amount,
|
||||||
Address: addr,
|
Address: addr,
|
||||||
}
|
}
|
||||||
|
|
|
@ -461,7 +461,7 @@ func (s *Server) getBlockHash(reqParams request.Params) (interface{}, *response.
|
||||||
}
|
}
|
||||||
num, err := s.blockHeightFromParam(param)
|
num, err := s.blockHeightFromParam(param)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, response.ErrInvalidParams
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.chain.GetHeaderHash(num), nil
|
return s.chain.GetHeaderHash(num), nil
|
||||||
|
@ -771,7 +771,7 @@ func (s *Server) getNEP5Balances(ps request.Params) (interface{}, *response.Erro
|
||||||
}
|
}
|
||||||
if as != nil {
|
if as != nil {
|
||||||
for h, bal := range as.Trackers {
|
for h, bal := range as.Trackers {
|
||||||
amount := strconv.FormatInt(bal.Balance, 10)
|
amount := bal.Balance.String()
|
||||||
bs.Balances = append(bs.Balances, result.NEP5Balance{
|
bs.Balances = append(bs.Balances, result.NEP5Balance{
|
||||||
Asset: h,
|
Asset: h,
|
||||||
Amount: amount,
|
Amount: amount,
|
||||||
|
@ -824,14 +824,15 @@ func (s *Server) getNEP5Transfers(ps request.Params) (interface{}, *response.Err
|
||||||
|
|
||||||
NotifyIndex: tr.Index,
|
NotifyIndex: tr.Index,
|
||||||
}
|
}
|
||||||
if tr.Amount > 0 { // token was received
|
if tr.Amount.Sign() > 0 { // token was received
|
||||||
transfer.Amount = strconv.FormatInt(tr.Amount, 10)
|
transfer.Amount = tr.Amount.String()
|
||||||
if !tr.From.Equals(util.Uint160{}) {
|
if !tr.From.Equals(util.Uint160{}) {
|
||||||
transfer.Address = address.Uint160ToString(tr.From)
|
transfer.Address = address.Uint160ToString(tr.From)
|
||||||
}
|
}
|
||||||
bs.Received = append(bs.Received, transfer)
|
bs.Received = append(bs.Received, transfer)
|
||||||
} else {
|
} else {
|
||||||
transfer.Amount = strconv.FormatInt(-tr.Amount, 10)
|
tr.Amount.Neg(tr.Amount)
|
||||||
|
transfer.Amount = tr.Amount.String()
|
||||||
if !tr.To.Equals(util.Uint160{}) {
|
if !tr.To.Equals(util.Uint160{}) {
|
||||||
transfer.Address = address.Uint160ToString(tr.To)
|
transfer.Address = address.Uint160ToString(tr.To)
|
||||||
}
|
}
|
||||||
|
@ -888,12 +889,14 @@ func uint160ToString(u util.Uint160) string {
|
||||||
func appendNEP5ToTransferTx(transfer *result.TransferTx, nepTr *state.NEP5Transfer) {
|
func appendNEP5ToTransferTx(transfer *result.TransferTx, nepTr *state.NEP5Transfer) {
|
||||||
var event result.TransferTxEvent
|
var event result.TransferTxEvent
|
||||||
event.Asset = nepTr.Asset.StringLE()
|
event.Asset = nepTr.Asset.StringLE()
|
||||||
if nepTr.Amount > 0 { // token was received
|
if nepTr.Amount.Sign() > 0 { // token was received
|
||||||
event.Value = strconv.FormatInt(nepTr.Amount, 10)
|
event.Value = nepTr.Amount.String()
|
||||||
event.Type = "receive"
|
event.Type = "receive"
|
||||||
event.Address = uint160ToString(nepTr.From)
|
event.Address = uint160ToString(nepTr.From)
|
||||||
} else {
|
} else {
|
||||||
event.Value = strconv.FormatInt(-nepTr.Amount, 10)
|
nepTr.Amount.Neg(nepTr.Amount)
|
||||||
|
event.Value = nepTr.Amount.String()
|
||||||
|
nepTr.Amount.Neg(nepTr.Amount)
|
||||||
event.Type = "send"
|
event.Type = "send"
|
||||||
event.Address = uint160ToString(nepTr.To)
|
event.Address = uint160ToString(nepTr.To)
|
||||||
}
|
}
|
||||||
|
@ -1327,7 +1330,7 @@ func (s *Server) getBlockTransferTx(ps request.Params) (interface{}, *response.E
|
||||||
Asset: nepTr.Asset.StringLE(),
|
Asset: nepTr.Asset.StringLE(),
|
||||||
From: uint160ToString(nepTr.From),
|
From: uint160ToString(nepTr.From),
|
||||||
To: uint160ToString(nepTr.To),
|
To: uint160ToString(nepTr.To),
|
||||||
Value: strconv.FormatInt(nepTr.Amount, 10),
|
Value: nepTr.Amount.String(),
|
||||||
})
|
})
|
||||||
index++
|
index++
|
||||||
}
|
}
|
||||||
|
@ -1356,24 +1359,15 @@ func (s *Server) getBlockSysFee(reqParams request.Params) (interface{}, *respons
|
||||||
}
|
}
|
||||||
|
|
||||||
headerHash := s.chain.GetHeaderHash(num)
|
headerHash := s.chain.GetHeaderHash(num)
|
||||||
block, errBlock := s.chain.GetBlock(headerHash)
|
|
||||||
if errBlock != nil {
|
|
||||||
return 0, response.NewRPCError(errBlock.Error(), "", nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
var blockSysFee util.Fixed8
|
return util.Fixed8FromInt64(int64(s.chain.GetSystemFeeAmount(headerHash))), nil
|
||||||
for _, tx := range block.Transactions {
|
|
||||||
blockSysFee += s.chain.SystemFee(tx)
|
|
||||||
}
|
|
||||||
|
|
||||||
return blockSysFee, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// getBlockHeader returns the corresponding block header information according to the specified script hash.
|
// getBlockHeader returns the corresponding block header information according to the specified script hash.
|
||||||
func (s *Server) getBlockHeader(reqParams request.Params) (interface{}, *response.Error) {
|
func (s *Server) getBlockHeader(reqParams request.Params) (interface{}, *response.Error) {
|
||||||
hash, err := reqParams.ValueWithType(0, request.StringT).GetUint256()
|
hash, respErr := s.getBlockHashFromParam(reqParams.Value(0))
|
||||||
if err != nil {
|
if respErr != nil {
|
||||||
return nil, response.ErrInvalidParams
|
return nil, respErr
|
||||||
}
|
}
|
||||||
|
|
||||||
verbose := reqParams.Value(1).GetBoolean()
|
verbose := reqParams.Value(1).GetBoolean()
|
||||||
|
|
|
@ -548,13 +548,9 @@ var rpcTestCases = map[string][]rpcTestCase{
|
||||||
name: "positive",
|
name: "positive",
|
||||||
params: "[1]",
|
params: "[1]",
|
||||||
result: func(e *executor) interface{} {
|
result: func(e *executor) interface{} {
|
||||||
block, _ := e.chain.GetBlock(e.chain.GetHeaderHash(1))
|
sf := e.chain.GetSystemFeeAmount(e.chain.GetHeaderHash(1))
|
||||||
|
r := util.Fixed8FromInt64(int64(sf))
|
||||||
var expectedBlockSysFee util.Fixed8
|
return &r
|
||||||
for _, tx := range block.Transactions {
|
|
||||||
expectedBlockSysFee += e.chain.SystemFee(tx)
|
|
||||||
}
|
|
||||||
return &expectedBlockSysFee
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -727,12 +723,12 @@ var rpcTestCases = map[string][]rpcTestCase{
|
||||||
},
|
},
|
||||||
check: func(t *testing.T, e *executor, validators interface{}) {
|
check: func(t *testing.T, e *executor, validators interface{}) {
|
||||||
var expected []result.Validator
|
var expected []result.Validator
|
||||||
sBValidators, err := e.chain.GetStandByValidators()
|
enrolls, err := e.chain.GetEnrollments()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
for _, sbValidator := range sBValidators {
|
for _, validator := range enrolls {
|
||||||
expected = append(expected, result.Validator{
|
expected = append(expected, result.Validator{
|
||||||
PublicKey: *sbValidator,
|
PublicKey: *validator.PublicKey,
|
||||||
Votes: 0,
|
Votes: validator.Votes,
|
||||||
Active: true,
|
Active: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1217,7 +1213,7 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
|
||||||
err := json.Unmarshal(res, &txOut)
|
err := json.Unmarshal(res, &txOut)
|
||||||
require.NoErrorf(t, err, "could not parse response: %s", res)
|
require.NoErrorf(t, err, "could not parse response: %s", res)
|
||||||
assert.Equal(t, 1, txOut.N)
|
assert.Equal(t, 1, txOut.N)
|
||||||
assert.Equal(t, "0x9b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc5", txOut.Asset)
|
assert.Equal(t, "0xc56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b", txOut.Asset)
|
||||||
assert.Equal(t, util.Fixed8FromInt64(1000), txOut.Value)
|
assert.Equal(t, util.Fixed8FromInt64(1000), txOut.Value)
|
||||||
assert.Equal(t, "AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU", txOut.Address)
|
assert.Equal(t, "AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU", txOut.Address)
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue