OSDN Git Service

ugly transaction test (#1692)
authormuscle_boy <shenao.78@163.com>
Mon, 15 Apr 2019 10:16:22 +0000 (18:16 +0800)
committerPaladz <yzhu101@uottawa.ca>
Mon, 15 Apr 2019 10:16:22 +0000 (18:16 +0800)
* ugly transaction test

* fix bug

* fix bug

protocol/validation/test/tx_ugly_test.go [new file with mode: 0644]
protocol/validation/tx_scene_test.go

diff --git a/protocol/validation/test/tx_ugly_test.go b/protocol/validation/test/tx_ugly_test.go
new file mode 100644 (file)
index 0000000..51cb54e
--- /dev/null
@@ -0,0 +1,1008 @@
+package test
+
+import (
+       "encoding/hex"
+       "math"
+       "testing"
+
+       "github.com/bytom/account"
+       "github.com/bytom/blockchain/signers"
+       "github.com/bytom/consensus"
+       "github.com/bytom/crypto/ed25519/chainkd"
+       "github.com/bytom/protocol/bc"
+       "github.com/bytom/protocol/bc/types"
+       "github.com/bytom/protocol/validation"
+       "github.com/bytom/protocol/vm/vmutil"
+       "github.com/bytom/testutil"
+)
+
+func TestValidateUglyTx(t *testing.T) {
+       singleSignInst := &signingInst{
+               rootPrvKeys: []string{
+                       "38d2c44314c401b3ea7c23c54e12c36a527aee46a7f26b82443a46bf40583e439dea25de09b0018b35a741d8cd9f6ec06bc11db49762617485f5309ab72a12d4",
+               },
+               quorum:           1,
+               keyIndex:         1,
+               ctrlProgramIndex: 1,
+               change:           false,
+       }
+       multiSignInst := &signingInst{
+               rootPrvKeys: []string{
+                       "a080aca2d9d7948d005c92d0729c618e56fb5551a52dfa04dc4caaf3c8b8a94c89a9795f5bbfd2b885ce7a9d3e3efa5386436c3681b21f9263a0b0a544346b48",
+                       "105295324626e33bb7d8e8a57c6a0aa495346d7fc342a4891ece00424494cf48f75cefa0f8c61674a12238cfa711b4bc26cb22f38b6e2206c691b83943a58312",
+                       "c02bb73d1aee56f8935fb7704f71f668eb37ec223baf5723b38a186669b465427d1bdbc2c4397c1259d12b6229aaf6154aaccdeb8addce3a780a1cbc1025ad25",
+                       "a0c2225685e4c4439f12c264d1573db063ddbc929d4b8a3e1641e8abb4df504a56b1200b9925138d79febe6e1156fcfaf0d1878f25cbccc5db4c8fea55bde198",
+                       "20d06d4fd261ab554e01104f019392f89566acace727e6bb6de4544aa3a6b248480232155332e6e5de10a62e4a9a4c1d9e3b7f9cb4fd196142ef1d080b8bbaec",
+               },
+               quorum:           3,
+               keyIndex:         1,
+               ctrlProgramIndex: 1,
+               change:           false,
+       }
+       cases := []struct {
+               category string
+               desc     string
+               insts    []*signingInst
+               txData   types.TxData
+               gasValid bool
+               err      bool
+       }{
+               {
+                       category: "fee insufficient",
+                       desc:     "sum of btm output greater than btm input",
+                       insts:    []*signingInst{singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, nil),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 10000000001, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "fee insufficient",
+                       desc:     "sum of btm output equals to input btm",
+                       insts:    []*signingInst{singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, nil),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 10000000001, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "fee insufficient",
+                       desc:     "sum of btm input greater than btm output, but still insufficient",
+                       insts:    []*signingInst{singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000001, 0, nil),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "fee insufficient",
+                       desc:     "no btm input",
+                       insts:    []*signingInst{singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 0, nil),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: true,
+               },
+               {
+                       category: "input output unbalance",
+                       desc:     "only has btm input, no output",
+                       insts:    []*signingInst{singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000001, 0, nil),
+                               },
+                               Outputs: []*types.TxOutput{},
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "input output unbalance",
+                       desc:     "issuance asset, no corresponding output",
+                       insts:    []*signingInst{singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, nil),
+                                       types.NewIssuanceInput( // assetID: 97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f
+                                               testutil.MustDecodeHexString("fd0aec4229deb281"),
+                                               10000000000,
+                                               nil,
+                                               nil,
+                                               testutil.MustDecodeHexString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"),
+                                       ),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "input output unbalance",
+                       desc:     "issuance asset A, output asset B",
+                       insts:    []*signingInst{singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, nil),
+                                       types.NewIssuanceInput( // assetID: 97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f
+                                               testutil.MustDecodeHexString("fd0aec4229deb281"),
+                                               10000000000,
+                                               nil,
+                                               nil,
+                                               testutil.MustDecodeHexString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"),
+                                       ),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                                       types.NewTxOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707e"), 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "input output unbalance",
+                       desc:     "sum of output asset A greater than issuance asset A",
+                       insts:    []*signingInst{singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, nil),
+                                       types.NewIssuanceInput( // assetID: 97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f
+                                               testutil.MustDecodeHexString("fd0aec4229deb281"),
+                                               10000000000,
+                                               nil,
+                                               nil,
+                                               testutil.MustDecodeHexString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"),
+                                       ),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                                       types.NewTxOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 20000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "input output unbalance",
+                       desc:     "sum of output asset A less than issuance asset A",
+                       insts:    []*signingInst{singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, nil),
+                                       types.NewIssuanceInput( // assetID: 97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f
+                                               testutil.MustDecodeHexString("fd0aec4229deb281"),
+                                               10000000000,
+                                               nil,
+                                               nil,
+                                               testutil.MustDecodeHexString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"),
+                                       ),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                                       types.NewTxOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 5000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "input output unbalance",
+                       desc:     "sum of retire asset A greater than issuance asset A",
+                       insts:    []*signingInst{singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, nil),
+                                       types.NewIssuanceInput( // assetID: 97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f
+                                               testutil.MustDecodeHexString("fd0aec4229deb281"),
+                                               10000000000,
+                                               nil,
+                                               nil,
+                                               testutil.MustDecodeHexString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"),
+                                       ),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                                       types.NewTxOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 20000000000, testutil.MustDecodeHexString("6a")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "input output unbalance",
+                       desc:     "sum of retire asset A less than issuance asset A",
+                       insts:    []*signingInst{singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, nil),
+                                       types.NewIssuanceInput( // assetID: 97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f
+                                               testutil.MustDecodeHexString("fd0aec4229deb281"),
+                                               10000000000,
+                                               nil,
+                                               nil,
+                                               testutil.MustDecodeHexString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"),
+                                       ),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                                       types.NewTxOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 5000000000, testutil.MustDecodeHexString("6a")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "input output unbalance",
+                       desc:     "spend asset A, no corresponding output",
+                       insts:    []*signingInst{singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, nil),
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
+                                               testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, nil),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "input output unbalance",
+                       desc:     "spend asset A, output asset B",
+                       insts:    []*signingInst{singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, nil),
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
+                                               testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, nil),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                                       types.NewTxOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707e"), 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "input output unbalance",
+                       desc:     "sum of output asset A greater than spend asset A",
+                       insts:    []*signingInst{singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, nil),
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
+                                               testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, nil),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                                       types.NewTxOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 20000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "input output unbalance",
+                       desc:     "sum of output asset A less than spend asset A",
+                       insts:    []*signingInst{singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, nil),
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
+                                               testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, nil),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                                       types.NewTxOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 5000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "input output unbalance",
+                       desc:     "sum of retire asset A greater than spend asset A",
+                       insts:    []*signingInst{singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, nil),
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
+                                               testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, nil),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                                       types.NewTxOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 20000000000, testutil.MustDecodeHexString("6a")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "input output unbalance",
+                       desc:     "sum of retire asset A less than spend asset A",
+                       insts:    []*signingInst{singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, nil),
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
+                                               testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, nil),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                                       types.NewTxOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 5000000000, testutil.MustDecodeHexString("6a")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "input output unbalance",
+                       desc:     "use retired utxo",
+                       insts:    []*signingInst{singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, testutil.MustDecodeHexString("6a")),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "input output unbalance",
+                       desc:     "input utxo is zero",
+                       insts:    []*signingInst{singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 0, 0, nil),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 0, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "input output unbalance",
+                       desc:     "no btm input",
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs:  []*types.TxInput{},
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 10, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "overflow",
+                       desc:     "spend btm input overflow",
+                       insts:    []*signingInst{singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, math.MaxUint64, 0, nil),
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
+                                               *consensus.BTMAssetID, 10000000000, 1, nil),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "overflow",
+                       desc:     "spend non btm input overflow",
+                       insts:    []*signingInst{singleSignInst, singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), math.MaxInt64, 0, nil),
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
+                                               testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 100, 0, nil),
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
+                                               *consensus.BTMAssetID, 10000000000, 1, nil),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                                       types.NewTxOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 100, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "overflow",
+                       desc:     "issuance non btm input overflow",
+                       insts:    []*signingInst{singleSignInst, singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
+                                               *consensus.BTMAssetID, 10000000000, 1, nil),
+                                       types.NewIssuanceInput( // assetID: 97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f
+                                               testutil.MustDecodeHexString("fd0aec4229deb281"),
+                                               math.MaxInt64,
+                                               nil,
+                                               [][]byte{
+                                                       testutil.MustDecodeHexString("e8f301f7bd3b1e4ca853b15559b3a253a4f5f9c7efba233ab0f6896bec23adc6a816c350e08f6b8ac5bc23eb5720173f9190805328af581f34a7fe561358d100"),
+                                               },
+                                               testutil.MustDecodeHexString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"),
+                                       ),
+                                       types.NewIssuanceInput( // assetID: 97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f
+                                               testutil.MustDecodeHexString("fd0aec4229deb281"),
+                                               10000000000,
+                                               nil,
+                                               nil,
+                                               testutil.MustDecodeHexString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"),
+                                       ),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                                       types.NewTxOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "overflow",
+                       desc:     "sum of spend and issuance non btm input overflow",
+                       insts:    []*signingInst{singleSignInst, singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
+                                               *consensus.BTMAssetID, 10000000000, 1, nil),
+                                       types.NewIssuanceInput( // assetID: 97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f
+                                               testutil.MustDecodeHexString("fd0aec4229deb281"),
+                                               math.MaxInt64,
+                                               nil,
+                                               nil,
+                                               testutil.MustDecodeHexString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"),
+                                       ),
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
+                                               testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 100, 0, nil),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                                       types.NewTxOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 100, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "overflow",
+                       desc:     "spend btm output overflow",
+                       insts:    []*signingInst{singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, nil),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, math.MaxUint64, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "overflow",
+                       desc:     "retire btm output overflow",
+                       insts:    []*signingInst{singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, nil),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, math.MaxUint64, testutil.MustDecodeHexString("6a")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "overflow",
+                       desc:     "non btm output overflow",
+                       insts:    []*signingInst{singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, nil),
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
+                                               testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, nil),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                                       types.NewTxOutput(*consensus.BTMAssetID, math.MaxUint64, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "overflow",
+                       desc:     "retire non btm output overflow",
+                       insts:    []*signingInst{singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, nil),
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
+                                               testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, nil),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                                       types.NewTxOutput(*consensus.BTMAssetID, math.MaxUint64, testutil.MustDecodeHexString("6a")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "overflow",
+                       desc:     "output with over range amount but sum in equal",
+                       insts:    []*signingInst{singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 100000000, 0, nil),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 18446744073609551616, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                                       types.NewTxOutput(*consensus.BTMAssetID, 18446744073609551616, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                                       types.NewTxOutput(*consensus.BTMAssetID, 290000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "verify signature fail",
+                       desc:     "btm single sign",
+                       insts:    []*signingInst{singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, testutil.MustDecodeHexString("00140876db6ca8f4542a836f0edd42b87d095d081182")), // wrong control program
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "verify signature fail",
+                       desc:     "btm multi sign",
+                       insts:    []*signingInst{multiSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, testutil.MustDecodeHexString("00200824e931fb806bd77fdcd291aad3bd0a4493443a4120062bd659e64a3e0bac66")), // wrong control program
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: false,
+               },
+               {
+                       category: "verify signature fail",
+                       desc:     "spend non btm single sign",
+                       insts:    []*signingInst{singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, nil),
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
+                                               testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, testutil.MustDecodeHexString("00140876db6ca8f4542a836f0edd42b87d095d081182")), // wrong control program
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                                       types.NewTxOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: true,
+               },
+               {
+                       category: "verify signature fail",
+                       desc:     "spend non btm multi sign",
+                       insts:    []*signingInst{singleSignInst, multiSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, nil),
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
+                                               testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, testutil.MustDecodeHexString("00140876db6ca8f4542a836f0edd42b87d095d081182")), // wrong control program
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                                       types.NewTxOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: true,
+               },
+               {
+                       category: "verify signature fail",
+                       desc:     "issuance non btm single sign",
+                       insts:    []*signingInst{singleSignInst, multiSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, nil),
+                                       types.NewIssuanceInput(
+                                               testutil.MustDecodeHexString("fd0aec4229deb281"),
+                                               10000000000,
+                                               // wrong issuance program
+                                               testutil.MustDecodeHexString("ae20c38173d800e62f63bd08cfaa9bc905e4a34a61ad841d7ad6c70ead0fb48196995151ad"),
+                                               nil,
+                                               nil,
+                                       ),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                                       types.NewTxOutput(testutil.MustDecodeAsset("bf5f8da2334590ee095148ccdcf4d806b26a47a6d9e9e857ef6c2de79aee4f14"), 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: true,
+               },
+               {
+                       category: "verify signature fail",
+                       desc:     "issuance non btm multi sign",
+                       insts:    []*signingInst{singleSignInst, multiSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, nil),
+                                       types.NewIssuanceInput(
+                                               testutil.MustDecodeHexString("fd0aec4229deb281"),
+                                               10000000000,
+                                               // wrong issuance program
+                                               testutil.MustDecodeHexString("ae20ce8639c5dc70cb2b12f89a057670602eb013fc54a10ce22bd4691c62cf546b7b2081bdd879bcbce7f58e1731841c6b3deac242efa00e75124fe559fa531c0c5bb820b40b6eec74288ee4bae67191f135512454b52640cfd7be95dc84be0f02281dce20247b6e6f9230a987ef61c66820268e7b766d28c1ce7aa2c550b34e294167f340205096211460415888768a48b121013711aa711634bb9ff7341a7bd072c31525875355ad"),
+                                               nil,
+                                               testutil.MustDecodeHexString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"),
+                                       ),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                                       types.NewTxOutput(testutil.MustDecodeAsset("776f0a421e9176a03061d388aff4ab3b1bcd32e53a090d593a466706c69e3d3f"), 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: true,
+               },
+               {
+                       category: "double spend",
+                       desc:     "btm asset double spend",
+                       insts:    []*signingInst{singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, testutil.MustDecodeHexString("001420a1af4fc11399e6cd7253abf1bbd4d0af17daad")),
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, testutil.MustDecodeHexString("001420a1af4fc11399e6cd7253abf1bbd4d0af17daad")),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 19000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: true,
+               },
+               {
+                       category: "double spend",
+                       desc:     "non btm asset double spend",
+                       insts:    []*signingInst{singleSignInst, singleSignInst, singleSignInst},
+                       txData: types.TxData{
+                               Version: 1,
+                               Inputs: []*types.TxInput{
+                                       types.NewSpendInput(nil,
+                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
+                                               *consensus.BTMAssetID, 10000000000, 0, nil),
+                                       types.NewSpendInput(
+                                               nil,
+                                               bc.Hash{V0: 3485387979411255237, V1: 15603105575416882039, V2: 5974145557334619041, V3: 16513948410238218452},
+                                               testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 0, testutil.MustDecodeHexString("001420a1af4fc11399e6cd7253abf1bbd4d0af17daad")),
+                                       types.NewSpendInput(
+                                               nil,
+                                               bc.Hash{V0: 3485387979411255237, V1: 15603105575416882039, V2: 5974145557334619041, V3: 16513948410238218452},
+                                               testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 0, testutil.MustDecodeHexString("001420a1af4fc11399e6cd7253abf1bbd4d0af17daad")),
+                               },
+                               Outputs: []*types.TxOutput{
+                                       types.NewTxOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                                       types.NewTxOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 20000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                               },
+                       },
+                       err:      true,
+                       gasValid: true,
+               },
+       }
+
+       for i, c := range cases {
+               mockCtrlProgram(c.txData, c.insts)
+
+               c.txData.SerializedSize = 1
+
+               tx := types.NewTx(c.txData)
+               mockSignTx(tx, c.insts)
+               bcTx := types.MapTx(&c.txData)
+
+               gasStatus, err := validation.ValidateTx(bcTx, &bc.Block{
+                       BlockHeader:  &bc.BlockHeader{Height: 1},
+                       Transactions: []*bc.Tx{bcTx},
+               })
+               if !c.err && err != nil {
+                       t.Errorf("case #%d (%s) expect no error, got error %s", i, c.desc, err)
+               }
+
+               if c.err && err == nil {
+                       t.Errorf("case #%d (%s) expect error, got no error", i, c.desc)
+               }
+
+               if c.gasValid != gasStatus.GasValid {
+                       t.Errorf("case #%d (%s) got GasValid %t, want %t", i, c.desc, gasStatus.GasValid, c.gasValid)
+               }
+       }
+}
+
+type signingInst struct {
+       rootPrvKeys      []string
+       quorum           int
+       keyIndex         uint64
+       ctrlProgramIndex uint64
+       change           bool
+}
+
+func mockCtrlProgram(txData types.TxData, insts []*signingInst) {
+       for i, input := range txData.Inputs {
+               _, xPubs := mustGetRootKeys(insts[i].rootPrvKeys)
+
+               switch inp := input.TypedInput.(type) {
+               case *types.SpendInput:
+                       if inp.ControlProgram != nil {
+                               continue
+                       }
+                       acc := &account.Account{Signer: &signers.Signer{KeyIndex: insts[i].keyIndex, DeriveRule: signers.BIP0044, XPubs: xPubs, Quorum: insts[i].quorum}}
+                       program, err := account.CreateCtrlProgram(acc, insts[i].ctrlProgramIndex, insts[i].change)
+                       if err != nil {
+                               panic(err)
+                       }
+                       inp.ControlProgram = program.ControlProgram
+               case *types.IssuanceInput:
+                       if inp.IssuanceProgram != nil {
+                               continue
+                       }
+                       assetSigner, err := signers.Create("asset", xPubs, insts[i].quorum, insts[i].keyIndex, signers.BIP0032)
+                       if err != nil {
+                               panic(err)
+                       }
+
+                       path := signers.GetBip0032Path(assetSigner, signers.AssetKeySpace)
+                       derivedXPubs := chainkd.DeriveXPubs(assetSigner.XPubs, path)
+                       derivedPKs := chainkd.XPubKeys(derivedXPubs)
+
+                       issuanceProg, err := vmutil.P2SPMultiSigProgramWithHeight(derivedPKs, insts[i].quorum, 0)
+                       if err != nil {
+                               panic(err)
+                       }
+
+                       inp.IssuanceProgram = issuanceProg
+               }
+       }
+}
+
+func mockSignTx(tx *types.Tx, insts []*signingInst) {
+       for i, input := range tx.TxData.Inputs {
+               if input.Arguments() != nil {
+                       continue
+               }
+               var arguments [][]byte
+               inst := insts[i]
+               switch inp := input.TypedInput.(type) {
+               case *types.SpendInput:
+                       path, err := signers.Path(&signers.Signer{KeyIndex: inst.keyIndex, DeriveRule: signers.BIP0044}, signers.AccountKeySpace, inst.change, inst.ctrlProgramIndex)
+                       if err != nil {
+                               panic(err)
+                       }
+
+                       xPrvs, xPubs := mustGetRootKeys(inst.rootPrvKeys)
+                       for _, xPrv := range xPrvs {
+                               childPrv := xPrv.Derive(path)
+                               sigHashBytes := tx.SigHash(uint32(i)).Byte32()
+                               arguments = append(arguments, childPrv.Sign(sigHashBytes[:]))
+                       }
+
+                       if len(xPrvs) == 1 {
+                               childPrv := xPrvs[0].Derive(path)
+                               derivePK := childPrv.XPub()
+                               arguments = append(arguments, derivePK.PublicKey())
+                       } else {
+                               derivedXPubs := chainkd.DeriveXPubs(xPubs, path)
+                               derivedPKs := chainkd.XPubKeys(derivedXPubs)
+                               script, err := vmutil.P2SPMultiSigProgram(derivedPKs, inst.quorum)
+                               if err != nil {
+                                       panic(err)
+                               }
+
+                               arguments = append(arguments, script)
+                       }
+                       inp.Arguments = arguments
+               case *types.IssuanceInput:
+                       path := signers.GetBip0032Path(&signers.Signer{KeyIndex: inst.keyIndex, DeriveRule: signers.BIP0032}, signers.AssetKeySpace)
+                       xPrvs, _ := mustGetRootKeys(inst.rootPrvKeys)
+                       for _, xPrv := range xPrvs {
+                               childPrv := xPrv.Derive(path)
+                               sigHashBytes := tx.SigHash(uint32(i)).Byte32()
+                               arguments = append(arguments, childPrv.Sign(sigHashBytes[:]))
+                       }
+                       inp.Arguments = arguments
+               }
+       }
+}
+
+func mustGetRootKeys(prvs []string) ([]chainkd.XPrv, []chainkd.XPub) {
+       xPubs := make([]chainkd.XPub, len(prvs))
+       xPrvs := make([]chainkd.XPrv, len(prvs))
+       for i, xPrv := range prvs {
+               xPrvBytes, err := hex.DecodeString(xPrv)
+               if err != nil {
+                       panic(err)
+               }
+
+               if len(xPrvBytes) != 64 {
+                       panic("the size of xPrv must 64")
+               }
+
+               var dest [64]byte
+               copy(dest[:], xPrv)
+               xPrvs[i] = chainkd.XPrv(dest)
+               xPubs[i] = xPrvs[i].XPub()
+       }
+       return xPrvs, xPubs
+}
index 72ff964..6f97c81 100644 (file)
@@ -2,23 +2,15 @@ package validation
 
 import (
        "encoding/hex"
-       "math"
        "testing"
 
        "github.com/bytom/consensus"
        "github.com/bytom/protocol/bc"
        "github.com/bytom/protocol/bc/types"
        "github.com/bytom/protocol/vm"
-       "github.com/bytom/protocol/vm/vmutil"
 )
 
 func TestValidateTx(t *testing.T) {
-       cp, _ := vmutil.DefaultCoinbaseProgram()
-       prog, err := vm.Assemble("ADD 5 NUMEQUAL")
-       if err != nil {
-               t.Fatal(err)
-       }
-
        cases := []struct {
                desc     string
                txData   *types.TxData
@@ -26,145 +18,6 @@ func TestValidateTx(t *testing.T) {
                err      error
        }{
                {
-                       desc: "transaction has no output",
-                       txData: &types.TxData{
-                               Version:        1,
-                               SerializedSize: 1,
-                               Inputs: []*types.TxInput{
-                                       types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp),
-                               },
-                       },
-                       gasValid: false,
-                       err:      ErrEmptyResults,
-               },
-               {
-                       desc: "sum of the output btm asset greater than input btm asset",
-                       txData: &types.TxData{
-                               Version:        1,
-                               SerializedSize: 1,
-                               Inputs: []*types.TxInput{
-                                       types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp),
-                               },
-                               Outputs: []*types.TxOutput{
-                                       types.NewTxOutput(*consensus.BTMAssetID, 100000001, cp),
-                               },
-                       },
-                       gasValid: false,
-                       err:      ErrGasCalculate,
-               },
-               {
-                       desc: "sum of the input btm asset is overflow",
-                       txData: &types.TxData{
-                               Version:        1,
-                               SerializedSize: 1,
-                               Inputs: []*types.TxInput{
-                                       types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, math.MaxInt64, 0, cp),
-                                       types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 1, 0, cp),
-                               },
-                               Outputs: []*types.TxOutput{
-                                       types.NewTxOutput(*consensus.BTMAssetID, 100000000, cp),
-                               },
-                       },
-                       gasValid: false,
-                       err:      ErrOverflow,
-               },
-               {
-                       desc: "issuance input has no corresponding output",
-                       txData: &types.TxData{
-                               Version:        1,
-                               SerializedSize: 1,
-                               Inputs: []*types.TxInput{
-                                       types.NewIssuanceInput([]byte{3}, 10, []byte{1}, [][]byte{[]byte{2}, []byte{3}}, []byte{2}),
-                                       types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp),
-                               },
-                               Outputs: []*types.TxOutput{
-                                       types.NewTxOutput(*consensus.BTMAssetID, 50000000, cp),
-                               },
-                       },
-                       gasValid: false,
-                       err:      ErrUnbalanced,
-               },
-               {
-                       desc: "issuance asset A, but output asset B",
-                       txData: &types.TxData{
-                               Version:        1,
-                               SerializedSize: 1,
-                               Inputs: []*types.TxInput{
-                                       types.NewIssuanceInput([]byte{3}, 10, prog, [][]byte{[]byte{2}, []byte{3}}, []byte{2}),
-                                       types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp),
-                               },
-                               Outputs: []*types.TxOutput{
-                                       types.NewTxOutput(bc.AssetID{V0: 0, V1: 1, V2: 2, V3: 3}, 10, cp),
-                                       types.NewTxOutput(*consensus.BTMAssetID, 50000000, cp),
-                               },
-                       },
-                       gasValid: false,
-                       err:      ErrNoSource,
-               },
-               {
-                       desc: "issuance transaction has no gas input",
-                       txData: &types.TxData{
-                               Version:        1,
-                               SerializedSize: 1,
-                               Inputs: []*types.TxInput{
-                                       types.NewIssuanceInput([]byte{3}, 10, prog, [][]byte{[]byte{2}, []byte{3}}, []byte{2}),
-                               },
-                               Outputs: []*types.TxOutput{
-                                       types.NewTxOutput(bc.AssetID{V0: 2596100136807737023, V1: 13466434218884500603, V2: 916280593609723488, V3: 439048993277404648}, 10, cp),
-                               },
-                       },
-                       gasValid: true, // TODO It's a bug, need hard fork solution
-                       err:      vm.ErrRunLimitExceeded,
-               },
-               {
-                       desc: "input using the same utxo",
-                       txData: &types.TxData{
-                               Version:        1,
-                               SerializedSize: 1,
-                               Inputs: []*types.TxInput{
-                                       types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp),
-                                       types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp),
-                               },
-                               Outputs: []*types.TxOutput{
-                                       types.NewTxOutput(*consensus.BTMAssetID, 180000000, cp),
-                               },
-                       },
-                       gasValid: true,
-                       err:      ErrMismatchedPosition,
-               },
-               {
-                       desc: "output with over range amount but sum in equal",
-                       txData: &types.TxData{
-                               Version:        1,
-                               SerializedSize: 1,
-                               Inputs: []*types.TxInput{
-                                       types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp),
-                               },
-                               Outputs: []*types.TxOutput{
-                                       types.NewTxOutput(*consensus.BTMAssetID, 18446744073609551616, cp),
-                                       types.NewTxOutput(*consensus.BTMAssetID, 18446744073609551616, cp),
-                                       types.NewTxOutput(*consensus.BTMAssetID, 290000000, cp),
-                               },
-                       },
-                       gasValid: false,
-                       err:      ErrOverflow,
-               },
-               {
-                       desc: "sum of output greater than sum of input (txtest#1015)",
-                       txData: &types.TxData{
-                               Version:        1,
-                               SerializedSize: 1,
-                               Inputs: []*types.TxInput{
-                                       types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 10, 0, cp),
-                               },
-                               Outputs: []*types.TxOutput{
-                                       types.NewTxOutput(*consensus.BTMAssetID, 20, cp),
-                               },
-                       },
-                       gasValid: false,
-                       err:      ErrGasCalculate,
-               },
-               {
                        desc: "single utxo, single sign, non asset, btm stanard transaction",
                        txData: &types.TxData{
                                Version:        1,