forked from TrueCloudLab/neoneo-go
core: fix SystemFee calculation for Invocation TXes
They have it specified right in the transaction. Unfortunately, this little change rendered invalid our RPC test chain, but I think it became even better after it, especially given that chain generation is a nice test by itself, so it should be running as a regular test.
This commit is contained in:
parent
ae6edf0601
commit
81d89cd502
4 changed files with 172 additions and 94 deletions
|
@ -1209,6 +1209,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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
Loading…
Reference in a new issue