forked from TrueCloudLab/neoneo-go
Merge pull request #718 from nspcc-dev/fix-invocation-tx-checks-and-fee
Fix Invocation TX checks and fee
This commit is contained in:
commit
5c781be08d
9 changed files with 280 additions and 101 deletions
|
@ -457,7 +457,7 @@ func (bc *Blockchain) storeBlock(block *block.Block) error {
|
|||
cache := newCachedDao(bc.dao.store)
|
||||
fee := bc.getSystemFeeAmount(block.PrevHash)
|
||||
for _, tx := range block.Transactions {
|
||||
fee += uint32(bc.SystemFee(tx).Int64Value())
|
||||
fee += uint32(bc.SystemFee(tx).IntegralValue())
|
||||
}
|
||||
if err := cache.StoreAsBlock(block, fee); err != nil {
|
||||
return err
|
||||
|
@ -1211,6 +1211,12 @@ func (bc *Blockchain) NetworkFee(t *transaction.Transaction) util.Fixed8 {
|
|||
|
||||
// SystemFee returns system fee.
|
||||
func (bc *Blockchain) SystemFee(t *transaction.Transaction) util.Fixed8 {
|
||||
if t.Type == transaction.InvocationType {
|
||||
inv := t.Data.(*transaction.InvocationTX)
|
||||
if inv.Version >= 1 {
|
||||
return inv.Gas
|
||||
}
|
||||
}
|
||||
return bc.GetConfig().SystemFee.TryGetValue(t.Type)
|
||||
}
|
||||
|
||||
|
@ -1285,7 +1291,8 @@ func (bc *Blockchain) verifyTx(t *transaction.Transaction, block *block.Block) e
|
|||
}
|
||||
}
|
||||
|
||||
if t.Type == transaction.ClaimType {
|
||||
switch t.Type {
|
||||
case transaction.ClaimType:
|
||||
claim := t.Data.(*transaction.ClaimTX)
|
||||
if transaction.HaveDuplicateInputs(claim.Claims) {
|
||||
return errors.New("duplicate claims")
|
||||
|
@ -1296,6 +1303,11 @@ func (bc *Blockchain) verifyTx(t *transaction.Transaction, block *block.Block) e
|
|||
if err := bc.verifyClaims(t); err != nil {
|
||||
return err
|
||||
}
|
||||
case transaction.InvocationType:
|
||||
inv := t.Data.(*transaction.InvocationTX)
|
||||
if inv.Gas.FractionalValue() != 0 {
|
||||
return errors.New("invocation gas can only be integer")
|
||||
}
|
||||
}
|
||||
|
||||
return bc.verifyTxWitnesses(t, block)
|
||||
|
|
|
@ -93,8 +93,9 @@ func newBlock(cfg config.ProtocolConfiguration, index uint32, prev util.Uint256,
|
|||
func (bc *Blockchain) genBlocks(n int) ([]*block.Block, error) {
|
||||
blocks := make([]*block.Block, n)
|
||||
lastHash := bc.topBlock.Load().(*block.Block).Hash()
|
||||
lastIndex := bc.topBlock.Load().(*block.Block).Index
|
||||
for i := 0; i < n; i++ {
|
||||
blocks[i] = newBlock(bc.config, uint32(i)+1, lastHash, newMinerTX())
|
||||
blocks[i] = newBlock(bc.config, uint32(i)+lastIndex+1, lastHash, newMinerTX())
|
||||
if err := bc.AddBlock(blocks[i]); err != nil {
|
||||
return blocks, err
|
||||
}
|
||||
|
@ -165,21 +166,117 @@ func getInvocationScript(data []byte, priv *keys.PrivateKey) []byte {
|
|||
}
|
||||
|
||||
// This function generates "../rpc/testdata/testblocks.acc" file which contains data
|
||||
// for RPC unit tests.
|
||||
// for RPC unit tests. It also is a nice integration test.
|
||||
// To generate new "../rpc/testdata/testblocks.acc", follow the steps:
|
||||
// 1. Rename the function
|
||||
// 2. Add specific test-case into "neo-go/pkg/core/blockchain_test.go"
|
||||
// 3. Run tests with `$ make test`
|
||||
func _(t *testing.T) {
|
||||
// 1. Set saveChain down below to true
|
||||
// 2. Run tests with `$ make test`
|
||||
func TestCreateBasicChain(t *testing.T) {
|
||||
const saveChain = false
|
||||
const prefix = "../rpc/server/testdata/"
|
||||
// To make enough GAS.
|
||||
const numOfEmptyBlocks = 200
|
||||
|
||||
var neoAmount = util.Fixed8FromInt64(99999000)
|
||||
var neoRemainder = util.Fixed8FromInt64(100000000) - neoAmount
|
||||
bc := newTestChain(t)
|
||||
n := 50
|
||||
_, err := bc.genBlocks(n)
|
||||
|
||||
// Move almost all NEO to one simple account.
|
||||
txMoveNeo := transaction.NewContractTX()
|
||||
h, err := util.Uint256DecodeStringBE("6da730b566db183bfceb863b780cd92dee2b497e5a023c322c1eaca81cf9ad7a")
|
||||
require.NoError(t, err)
|
||||
txMoveNeo.AddInput(&transaction.Input{
|
||||
PrevHash: h,
|
||||
PrevIndex: 0,
|
||||
})
|
||||
|
||||
// multisig address which possess all NEO
|
||||
scriptHash, err := util.Uint160DecodeStringBE("be48d3a3f5d10013ab9ffee489706078714f1ea2")
|
||||
require.NoError(t, err)
|
||||
priv0, err := keys.NewPrivateKeyFromWIF(privNetKeys[0])
|
||||
require.NoError(t, err)
|
||||
txMoveNeo.AddOutput(&transaction.Output{
|
||||
AssetID: GoverningTokenID(),
|
||||
Amount: neoAmount,
|
||||
ScriptHash: priv0.GetScriptHash(),
|
||||
Position: 0,
|
||||
})
|
||||
txMoveNeo.AddOutput(&transaction.Output{
|
||||
AssetID: GoverningTokenID(),
|
||||
Amount: neoRemainder,
|
||||
ScriptHash: scriptHash,
|
||||
Position: 1,
|
||||
})
|
||||
txMoveNeo.Data = new(transaction.ContractTX)
|
||||
|
||||
validators, err := getValidators(bc.config)
|
||||
require.NoError(t, err)
|
||||
rawScript, err := smartcontract.CreateMultiSigRedeemScript(len(bc.config.StandbyValidators)/2+1, validators)
|
||||
require.NoError(t, err)
|
||||
data := txMoveNeo.GetSignedPart()
|
||||
|
||||
var invoc []byte
|
||||
for i := range privNetKeys {
|
||||
priv, err := keys.NewPrivateKeyFromWIF(privNetKeys[i])
|
||||
require.NoError(t, err)
|
||||
invoc = append(invoc, getInvocationScript(data, priv)...)
|
||||
}
|
||||
|
||||
txMoveNeo.Scripts = []transaction.Witness{{
|
||||
InvocationScript: invoc,
|
||||
VerificationScript: rawScript,
|
||||
}}
|
||||
|
||||
b := bc.newBlock(newMinerTX(), txMoveNeo)
|
||||
require.NoError(t, bc.AddBlock(b))
|
||||
t.Logf("txMoveNeo: %s", txMoveNeo.Hash().StringLE())
|
||||
|
||||
// Generate some blocks to be able to claim GAS for them.
|
||||
_, err = bc.genBlocks(numOfEmptyBlocks)
|
||||
require.NoError(t, err)
|
||||
|
||||
tx1 := newMinerTX()
|
||||
acc0, err := wallet.NewAccountFromWIF(priv0.WIF())
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make a NEO roundtrip (send to myself) and claim GAS.
|
||||
txNeoRound := transaction.NewContractTX()
|
||||
txNeoRound.AddInput(&transaction.Input{
|
||||
PrevHash: txMoveNeo.Hash(),
|
||||
PrevIndex: 0,
|
||||
})
|
||||
txNeoRound.AddOutput(&transaction.Output{
|
||||
AssetID: GoverningTokenID(),
|
||||
Amount: neoAmount,
|
||||
ScriptHash: priv0.GetScriptHash(),
|
||||
Position: 0,
|
||||
})
|
||||
txNeoRound.Data = new(transaction.ContractTX)
|
||||
require.NoError(t, acc0.SignTx(txNeoRound))
|
||||
b = bc.newBlock(newMinerTX(), txNeoRound)
|
||||
require.NoError(t, bc.AddBlock(b))
|
||||
t.Logf("txNeoRound: %s", txNeoRound.Hash().StringLE())
|
||||
|
||||
txClaim := &transaction.Transaction{Type: transaction.ClaimType}
|
||||
claim := new(transaction.ClaimTX)
|
||||
claim.Claims = append(claim.Claims, transaction.Input{
|
||||
PrevHash: txMoveNeo.Hash(),
|
||||
PrevIndex: 0,
|
||||
})
|
||||
txClaim.Data = claim
|
||||
neoGas, sysGas, err := bc.CalculateClaimable(neoAmount, 1, bc.BlockHeight())
|
||||
require.NoError(t, err)
|
||||
gasOwned := neoGas + sysGas
|
||||
txClaim.AddOutput(&transaction.Output{
|
||||
AssetID: UtilityTokenID(),
|
||||
Amount: gasOwned,
|
||||
ScriptHash: priv0.GetScriptHash(),
|
||||
Position: 0,
|
||||
})
|
||||
require.NoError(t, acc0.SignTx(txClaim))
|
||||
b = bc.newBlock(newMinerTX(), txClaim)
|
||||
require.NoError(t, bc.AddBlock(b))
|
||||
t.Logf("txClaim: %s", txClaim.Hash().StringLE())
|
||||
|
||||
// Push some contract into the chain.
|
||||
avm, err := ioutil.ReadFile(prefix + "test_contract.avm")
|
||||
require.NoError(t, err)
|
||||
|
||||
|
@ -200,11 +297,25 @@ func _(t *testing.T) {
|
|||
emit.Syscall(script.BinWriter, "Neo.Contract.Create")
|
||||
txScript := script.Bytes()
|
||||
|
||||
tx2 := transaction.NewInvocationTX(txScript, util.Fixed8FromFloat(100))
|
||||
|
||||
block := bc.newBlock(tx1, tx2)
|
||||
require.NoError(t, bc.AddBlock(block))
|
||||
invFee := util.Fixed8FromFloat(100)
|
||||
txDeploy := transaction.NewInvocationTX(txScript, invFee)
|
||||
txDeploy.AddInput(&transaction.Input{
|
||||
PrevHash: txClaim.Hash(),
|
||||
PrevIndex: 0,
|
||||
})
|
||||
txDeploy.AddOutput(&transaction.Output{
|
||||
AssetID: UtilityTokenID(),
|
||||
Amount: gasOwned - invFee,
|
||||
ScriptHash: priv0.GetScriptHash(),
|
||||
Position: 0,
|
||||
})
|
||||
gasOwned -= invFee
|
||||
require.NoError(t, acc0.SignTx(txDeploy))
|
||||
b = bc.newBlock(newMinerTX(), txDeploy)
|
||||
require.NoError(t, bc.AddBlock(b))
|
||||
t.Logf("txDeploy: %s", txDeploy.Hash().StringLE())
|
||||
|
||||
// Now invoke this contract.
|
||||
script = io.NewBufBinWriter()
|
||||
emit.String(script.BinWriter, "testvalue")
|
||||
emit.String(script.BinWriter, "testkey")
|
||||
|
@ -213,94 +324,54 @@ func _(t *testing.T) {
|
|||
emit.String(script.BinWriter, "Put")
|
||||
emit.AppCall(script.BinWriter, hash.Hash160(avm), false)
|
||||
|
||||
tx3 := transaction.NewInvocationTX(script.Bytes(), util.Fixed8FromFloat(100))
|
||||
|
||||
tx4 := transaction.NewContractTX()
|
||||
h, err := util.Uint256DecodeStringBE("6da730b566db183bfceb863b780cd92dee2b497e5a023c322c1eaca81cf9ad7a")
|
||||
require.NoError(t, err)
|
||||
tx4.AddInput(&transaction.Input{
|
||||
PrevHash: h,
|
||||
PrevIndex: 0,
|
||||
})
|
||||
|
||||
// multisig address which possess all NEO
|
||||
scriptHash, err := util.Uint160DecodeStringBE("be48d3a3f5d10013ab9ffee489706078714f1ea2")
|
||||
require.NoError(t, err)
|
||||
priv, err := keys.NewPrivateKeyFromWIF(privNetKeys[0])
|
||||
require.NoError(t, err)
|
||||
tx4.AddOutput(&transaction.Output{
|
||||
AssetID: GoverningTokenID(),
|
||||
Amount: util.Fixed8FromInt64(1000),
|
||||
ScriptHash: priv.GetScriptHash(),
|
||||
Position: 0,
|
||||
})
|
||||
tx4.AddOutput(&transaction.Output{
|
||||
AssetID: GoverningTokenID(),
|
||||
Amount: util.Fixed8FromInt64(99999000),
|
||||
ScriptHash: scriptHash,
|
||||
Position: 1,
|
||||
})
|
||||
tx4.Data = new(transaction.ContractTX)
|
||||
|
||||
validators, err := getValidators(bc.config)
|
||||
require.NoError(t, err)
|
||||
rawScript, err := smartcontract.CreateMultiSigRedeemScript(len(bc.config.StandbyValidators)/2+1, validators)
|
||||
require.NoError(t, err)
|
||||
data := tx4.GetSignedPart()
|
||||
|
||||
var invoc []byte
|
||||
for i := range privNetKeys {
|
||||
priv, err := keys.NewPrivateKeyFromWIF(privNetKeys[i])
|
||||
require.NoError(t, err)
|
||||
invoc = append(invoc, getInvocationScript(data, priv)...)
|
||||
}
|
||||
|
||||
tx4.Scripts = []transaction.Witness{{
|
||||
InvocationScript: invoc,
|
||||
VerificationScript: rawScript,
|
||||
}}
|
||||
|
||||
b := bc.newBlock(newMinerTX(), tx3, tx4)
|
||||
txInv := transaction.NewInvocationTX(script.Bytes(), 0)
|
||||
b = bc.newBlock(newMinerTX(), txInv)
|
||||
require.NoError(t, bc.AddBlock(b))
|
||||
t.Logf("txInv: %s", txInv.Hash().StringLE())
|
||||
|
||||
priv1, err := keys.NewPrivateKeyFromWIF(privNetKeys[1])
|
||||
require.NoError(t, err)
|
||||
tx5 := transaction.NewContractTX()
|
||||
tx5.Data = new(transaction.ContractTX)
|
||||
tx5.AddInput(&transaction.Input{
|
||||
PrevHash: tx4.Hash(),
|
||||
txNeo0to1 := transaction.NewContractTX()
|
||||
txNeo0to1.Data = new(transaction.ContractTX)
|
||||
txNeo0to1.AddInput(&transaction.Input{
|
||||
PrevHash: txNeoRound.Hash(),
|
||||
PrevIndex: 0,
|
||||
})
|
||||
tx5.AddOutput(&transaction.Output{
|
||||
txNeo0to1.AddOutput(&transaction.Output{
|
||||
AssetID: GoverningTokenID(),
|
||||
Amount: util.Fixed8FromInt64(1000),
|
||||
ScriptHash: priv1.GetScriptHash(),
|
||||
})
|
||||
txNeo0to1.AddOutput(&transaction.Output{
|
||||
AssetID: GoverningTokenID(),
|
||||
Amount: neoAmount - util.Fixed8FromInt64(1000),
|
||||
ScriptHash: priv0.GetScriptHash(),
|
||||
})
|
||||
|
||||
acc, err := wallet.NewAccountFromWIF(priv.WIF())
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, acc.SignTx(tx5))
|
||||
b = bc.newBlock(newMinerTX(), tx5)
|
||||
require.NoError(t, acc0.SignTx(txNeo0to1))
|
||||
b = bc.newBlock(newMinerTX(), txNeo0to1)
|
||||
require.NoError(t, bc.AddBlock(b))
|
||||
|
||||
outStream, err := os.Create(prefix + "testblocks.acc")
|
||||
require.NoError(t, err)
|
||||
defer outStream.Close()
|
||||
|
||||
writer := io.NewBinWriterFromIO(outStream)
|
||||
|
||||
count := bc.BlockHeight() + 1
|
||||
writer.WriteU32LE(count - 1)
|
||||
|
||||
for i := 1; i < int(count); i++ {
|
||||
bh := bc.GetHeaderHash(i)
|
||||
b, err := bc.GetBlock(bh)
|
||||
if saveChain {
|
||||
outStream, err := os.Create(prefix + "testblocks.acc")
|
||||
require.NoError(t, err)
|
||||
buf := io.NewBufBinWriter()
|
||||
b.EncodeBinary(buf.BinWriter)
|
||||
bytes := buf.Bytes()
|
||||
writer.WriteU32LE(uint32(len(bytes)))
|
||||
writer.WriteBytes(bytes)
|
||||
require.NoError(t, writer.Err)
|
||||
defer outStream.Close()
|
||||
|
||||
writer := io.NewBinWriterFromIO(outStream)
|
||||
|
||||
count := bc.BlockHeight() + 1
|
||||
writer.WriteU32LE(count - 1)
|
||||
|
||||
for i := 1; i < int(count); i++ {
|
||||
bh := bc.GetHeaderHash(i)
|
||||
b, err := bc.GetBlock(bh)
|
||||
require.NoError(t, err)
|
||||
buf := io.NewBufBinWriter()
|
||||
b.EncodeBinary(buf.BinWriter)
|
||||
bytes := buf.Bytes()
|
||||
writer.WriteU32LE(uint32(len(bytes)))
|
||||
writer.WriteBytes(bytes)
|
||||
require.NoError(t, writer.Err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,8 @@ func TestEncodeDecodeContract(t *testing.T) {
|
|||
|
||||
assert.Equal(t, "eec17cc828d6ede932b57e4eaf79c2591151096a7825435cd67f498f9fa98d88", input.PrevHash.StringLE())
|
||||
assert.Equal(t, 0, int(input.PrevIndex))
|
||||
assert.Equal(t, int64(706), tx.Outputs[0].Amount.Int64Value())
|
||||
assert.Equal(t, int64(706), tx.Outputs[0].Amount.IntegralValue())
|
||||
assert.Equal(t, int32(0), tx.Outputs[0].Amount.FractionalValue())
|
||||
assert.Equal(t, "c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b", tx.Outputs[0].AssetID.StringLE())
|
||||
assert.Equal(t, "a8666b4830229d6a1a9b80f6088059191c122d2b", tx.Outputs[0].ScriptHash.String())
|
||||
assert.Equal(t, "bdf6cc3b9af12a7565bda80933a75ee8cef1bc771d0d58effc08e4c8b436da79", tx.Hash().StringLE())
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
@ -36,8 +38,16 @@ func NewInvocationTX(script []byte, gas util.Fixed8) *Transaction {
|
|||
// DecodeBinary implements Serializable interface.
|
||||
func (tx *InvocationTX) DecodeBinary(br *io.BinReader) {
|
||||
tx.Script = br.ReadVarBytes()
|
||||
if br.Err == nil && len(tx.Script) == 0 {
|
||||
br.Err = errors.New("no script")
|
||||
return
|
||||
}
|
||||
if tx.Version >= 1 {
|
||||
tx.Gas.DecodeBinary(br)
|
||||
if br.Err == nil && tx.Gas.LessThan(0) {
|
||||
br.Err = errors.New("negative gas")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
tx.Gas = util.Fixed8FromInt64(0)
|
||||
}
|
||||
|
|
70
pkg/core/transaction/invocation_test.go
Normal file
70
pkg/core/transaction/invocation_test.go
Normal file
|
@ -0,0 +1,70 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestInvocationZeroScript(t *testing.T) {
|
||||
// Zero-length script.
|
||||
in, err := hex.DecodeString("000000000000000000")
|
||||
require.NoError(t, err)
|
||||
|
||||
inv := &InvocationTX{Version: 1}
|
||||
r := io.NewBinReaderFromBuf(in)
|
||||
|
||||
inv.DecodeBinary(r)
|
||||
assert.Error(t, r.Err)
|
||||
|
||||
// PUSH1 script.
|
||||
in, err = hex.DecodeString("01510000000000000000")
|
||||
require.NoError(t, err)
|
||||
r = io.NewBinReaderFromBuf(in)
|
||||
|
||||
inv.DecodeBinary(r)
|
||||
assert.NoError(t, r.Err)
|
||||
}
|
||||
|
||||
func TestInvocationNegativeGas(t *testing.T) {
|
||||
// Negative GAS
|
||||
in, err := hex.DecodeString("015100000000000000ff")
|
||||
require.NoError(t, err)
|
||||
|
||||
inv := &InvocationTX{Version: 1}
|
||||
r := io.NewBinReaderFromBuf(in)
|
||||
|
||||
inv.DecodeBinary(r)
|
||||
assert.Error(t, r.Err)
|
||||
|
||||
// Positive GAS.
|
||||
in, err = hex.DecodeString("01510100000000000000")
|
||||
require.NoError(t, err)
|
||||
r = io.NewBinReaderFromBuf(in)
|
||||
|
||||
inv.DecodeBinary(r)
|
||||
assert.NoError(t, r.Err)
|
||||
assert.Equal(t, util.Fixed8(1), inv.Gas)
|
||||
}
|
||||
|
||||
func TestInvocationVersionZero(t *testing.T) {
|
||||
in, err := hex.DecodeString("0151")
|
||||
require.NoError(t, err)
|
||||
|
||||
inv := &InvocationTX{Version: 1}
|
||||
r := io.NewBinReaderFromBuf(in)
|
||||
|
||||
inv.DecodeBinary(r)
|
||||
assert.Error(t, r.Err)
|
||||
|
||||
inv = &InvocationTX{Version: 0}
|
||||
r = io.NewBinReaderFromBuf(in)
|
||||
|
||||
inv.DecodeBinary(r)
|
||||
assert.NoError(t, r.Err)
|
||||
assert.Equal(t, util.Fixed8(0), inv.Gas)
|
||||
}
|
|
@ -44,14 +44,15 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
"getapplicationlog": {
|
||||
{
|
||||
name: "positive",
|
||||
params: `["d5cf936296de912aa4d051531bd8d25c7a58fb68fc7f87c8d3e6e85475187c08"]`,
|
||||
params: `["2441c2776cbab65bf81d38a839cf3a85689421631d4ba091be64703f02867315"]`,
|
||||
result: func(e *executor) interface{} { return &result.ApplicationLog{} },
|
||||
check: func(t *testing.T, e *executor, acc interface{}) {
|
||||
res, ok := acc.(*result.ApplicationLog)
|
||||
|
||||
require.True(t, ok)
|
||||
|
||||
expectedTxHash := util.Uint256{0x8, 0x7c, 0x18, 0x75, 0x54, 0xe8, 0xe6, 0xd3, 0xc8, 0x87, 0x7f, 0xfc, 0x68, 0xfb, 0x58, 0x7a, 0x5c, 0xd2, 0xd8, 0x1b, 0x53, 0x51, 0xd0, 0xa4, 0x2a, 0x91, 0xde, 0x96, 0x62, 0x93, 0xcf, 0xd5}
|
||||
expectedTxHash, err := util.Uint256DecodeStringLE("2441c2776cbab65bf81d38a839cf3a85689421631d4ba091be64703f02867315")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, expectedTxHash, res.TxHash)
|
||||
assert.Equal(t, 1, len(res.Executions))
|
||||
assert.Equal(t, "Application", res.Executions[0].Trigger)
|
||||
|
@ -256,13 +257,13 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
"getblock": {
|
||||
{
|
||||
name: "positive",
|
||||
params: "[1, 1]",
|
||||
params: "[2, 1]",
|
||||
result: func(e *executor) interface{} { return &result.Block{} },
|
||||
check: func(t *testing.T, e *executor, blockRes interface{}) {
|
||||
res, ok := blockRes.(*result.Block)
|
||||
require.True(t, ok)
|
||||
|
||||
block, err := e.chain.GetBlock(e.chain.GetHeaderHash(1))
|
||||
block, err := e.chain.GetBlock(e.chain.GetHeaderHash(2))
|
||||
require.NoErrorf(t, err, "could not get block")
|
||||
|
||||
assert.Equal(t, block.Hash(), res.Hash)
|
||||
|
@ -381,13 +382,13 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
result: func(*executor) interface{} {
|
||||
// hash of the issueTx
|
||||
h, _ := util.Uint256DecodeStringBE("6da730b566db183bfceb863b780cd92dee2b497e5a023c322c1eaca81cf9ad7a")
|
||||
amount := util.Fixed8FromInt64(52 * 8) // (endHeight - startHeight) * genAmount[0]
|
||||
amount := util.Fixed8FromInt64(1 * 8) // (endHeight - startHeight) * genAmount[0]
|
||||
return &result.ClaimableInfo{
|
||||
Spents: []result.Claimable{
|
||||
{
|
||||
Tx: h,
|
||||
Value: util.Fixed8FromInt64(100000000),
|
||||
EndHeight: 52,
|
||||
EndHeight: 1,
|
||||
Generated: amount,
|
||||
Unclaimed: amount,
|
||||
},
|
||||
|
|
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
Binary file not shown.
|
@ -46,11 +46,18 @@ func (f Fixed8) FloatValue() float64 {
|
|||
return float64(f) / decimals
|
||||
}
|
||||
|
||||
// Int64Value returns the original value representing Fixed8 as int64.
|
||||
func (f Fixed8) Int64Value() int64 {
|
||||
// IntegralValue returns integer part of the original value representing
|
||||
// Fixed8 as int64.
|
||||
func (f Fixed8) IntegralValue() int64 {
|
||||
return int64(f) / decimals
|
||||
}
|
||||
|
||||
// FractionalValue returns decimal part of the original value. It has the same
|
||||
// sign as f, so that f = f.IntegralValue() + f.FractionalValue().
|
||||
func (f Fixed8) FractionalValue() int32 {
|
||||
return int32(int64(f) % decimals)
|
||||
}
|
||||
|
||||
// Fixed8FromInt64 returns a new Fixed8 type multiplied by decimals.
|
||||
func Fixed8FromInt64(val int64) Fixed8 {
|
||||
return Fixed8(decimals * val)
|
||||
|
|
|
@ -2,6 +2,7 @@ package util
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
|
@ -16,7 +17,8 @@ func TestFixed8FromInt64(t *testing.T) {
|
|||
|
||||
for _, val := range values {
|
||||
assert.Equal(t, Fixed8(val*decimals), Fixed8FromInt64(val))
|
||||
assert.Equal(t, val, Fixed8FromInt64(val).Int64Value())
|
||||
assert.Equal(t, val, Fixed8FromInt64(val).IntegralValue())
|
||||
assert.Equal(t, int32(0), Fixed8FromInt64(val).FractionalValue())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,7 +37,8 @@ func TestFixed8Sub(t *testing.T) {
|
|||
b := Fixed8FromInt64(34)
|
||||
|
||||
c := a.Sub(b)
|
||||
assert.Equal(t, int64(8), c.Int64Value())
|
||||
assert.Equal(t, int64(8), c.IntegralValue())
|
||||
assert.Equal(t, int32(0), c.FractionalValue())
|
||||
}
|
||||
|
||||
func TestFixed8FromFloat(t *testing.T) {
|
||||
|
@ -44,6 +47,10 @@ func TestFixed8FromFloat(t *testing.T) {
|
|||
for _, val := range inputs {
|
||||
assert.Equal(t, Fixed8(val*decimals), Fixed8FromFloat(val))
|
||||
assert.Equal(t, val, Fixed8FromFloat(val).FloatValue())
|
||||
trunc := math.Trunc(val)
|
||||
rem := (val - trunc) * decimals
|
||||
assert.Equal(t, int64(trunc), Fixed8FromFloat(val).IntegralValue())
|
||||
assert.Equal(t, int32(math.Round(rem)), Fixed8FromFloat(val).FractionalValue())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue