12 log "github.com/sirupsen/logrus"
14 "github.com/vapor/account"
15 "github.com/vapor/asset"
16 "github.com/vapor/blockchain/pseudohsm"
17 "github.com/vapor/consensus"
18 dbm "github.com/vapor/database/leveldb"
19 "github.com/vapor/protocol/bc"
20 "github.com/vapor/protocol/bc/types"
21 "github.com/vapor/protocol/validation"
22 "github.com/vapor/protocol/vm"
26 log.SetLevel(log.ErrorLevel)
29 type TxTestConfig struct {
30 Keys []*keyInfo `json:"keys"`
31 Accounts []*accountInfo `json:"accounts"`
32 Transactions []*ttTransaction `json:"transactions"`
35 func (cfg *TxTestConfig) Run() error {
36 dirPath, err := ioutil.TempDir(".", "pseudo_hsm")
40 defer os.RemoveAll(dirPath)
41 hsm, err := pseudohsm.New(dirPath)
46 chainDB := dbm.NewDB("chain_db", "leveldb", "chain_db")
47 defer os.RemoveAll("chain_db")
48 chain, _, _, _ := MockChain(chainDB)
49 txTestDB := dbm.NewDB("tx_test_db", "leveldb", "tx_test_db")
50 defer os.RemoveAll("tx_test_db")
51 accountManager := account.NewManager(txTestDB, chain)
52 assets := asset.NewRegistry(txTestDB, chain)
54 generator := NewTxGenerator(accountManager, assets, hsm)
55 for _, key := range cfg.Keys {
56 if err := generator.createKey(key.Name, key.Password); err != nil {
61 for _, acc := range cfg.Accounts {
62 if err := generator.createAccount(acc.Name, acc.Keys, acc.Quorum); err != nil {
68 BlockHeader: &bc.BlockHeader{
73 for _, t := range cfg.Transactions {
74 tx, err := t.create(generator)
79 tx.TxData.Version = t.Version
80 tx.Tx = types.MapTx(&tx.TxData)
81 status, err := validation.ValidateTx(tx.Tx, block)
83 if result != t.Valid {
84 return fmt.Errorf("tx %s validate failed, expected: %t, have: %t", t.Describe, t.Valid, result)
91 if err != nil && status.GasValid {
94 if gasOnlyTx != t.GasOnly {
95 return fmt.Errorf("gas only tx %s validate failed", t.Describe)
97 if result && t.TxFee != status.BTMValue {
98 return fmt.Errorf("gas used dismatch, expected: %d, have: %d", t.TxFee, status.BTMValue)
104 type ttTransaction struct {
106 Describe string `json:"describe"`
107 Version uint64 `json:"version"`
108 Valid bool `json:"valid"`
109 GasOnly bool `json:"gas_only"`
110 TxFee uint64 `json:"tx_fee"`
113 // UnmarshalJSON unmarshal transaction with default version 1
114 func (t *ttTransaction) UnmarshalJSON(data []byte) error {
115 type typeAlias ttTransaction
120 err := json.Unmarshal(data, tx)
124 *t = ttTransaction(*tx)
128 func (t *ttTransaction) create(g *TxGenerator) (*types.Tx, error) {
130 for _, input := range t.Inputs {
132 case "spend_account":
133 utxo, err := g.mockUtxo(input.AccountAlias, input.AssetAlias, input.Amount)
137 if err := g.AddTxInputFromUtxo(utxo, input.AccountAlias); err != nil {
141 _, err := g.createAsset(input.AccountAlias, input.AssetAlias)
145 if err := g.AddIssuanceInput(input.AssetAlias, input.Amount); err != nil {
151 for _, output := range t.Outputs {
154 if err := g.AddTxOutput(output.AccountAlias, output.AssetAlias, output.Amount); err != nil {
158 if err := g.AddRetirement(output.AssetAlias, output.Amount); err != nil {
163 return g.Sign(t.Passwords)
166 func TestTx(t *testing.T) {
167 walk(t, txTestDir, func(t *testing.T, name string, test *TxTestConfig) {
168 if err := test.Run(); err != nil {
174 func TestCoinbaseMature(t *testing.T) {
175 db := dbm.NewDB("test_coinbase_mature_db", "leveldb", "test_coinbase_mature_db")
176 defer os.RemoveAll("test_coinbase_mature_db")
177 chain, _, _, _ := MockChain(db)
179 defaultCtrlProg := []byte{byte(vm.OP_TRUE)}
180 if err := AppendBlocks(chain, 1); err != nil {
184 height := chain.BestBlockHeight()
185 block, err := chain.GetBlockByHeight(height)
190 tx, err := CreateTxFromTx(block.Transactions[0], 0, 1000000000, defaultCtrlProg)
195 txs := []*types.Tx{tx}
196 matureHeight := chain.BestBlockHeight() + consensus.CoinbasePendingBlockNumber
197 currentHeight := chain.BestBlockHeight()
198 for h := currentHeight + 1; h < matureHeight; h++ {
199 block, err := NewBlock(chain, txs, defaultCtrlProg)
203 if _, err := chain.ProcessBlock(block); err == nil {
204 t.Fatal("spent immature coinbase output success")
206 block, err = NewBlock(chain, nil, defaultCtrlProg)
210 if _, err := chain.ProcessBlock(block); err != nil {
215 block, err = NewBlock(chain, txs, defaultCtrlProg)
219 if _, err := chain.ProcessBlock(block); err != nil {
220 t.Fatalf("spent mature coinbase output failed: %s", err)
224 func TestCoinbaseTx(t *testing.T) {
225 db := dbm.NewDB("test_coinbase_tx_db", "leveldb", "test_coinbase_tx_db")
226 defer os.RemoveAll("test_coinbase_tx_db")
227 chain, _, _, _ := MockChain(db)
229 defaultCtrlProg := []byte{byte(vm.OP_TRUE)}
230 if err := AppendBlocks(chain, 1); err != nil {
234 block, err := chain.GetBlockByHeight(chain.BestBlockHeight())
239 tx, err := CreateTxFromTx(block.Transactions[0], 0, 1000000000, defaultCtrlProg)
244 block, err = NewBlock(chain, []*types.Tx{tx}, defaultCtrlProg)
249 txFees := []uint64{100000, 5000000000000}
250 for _, txFee := range txFees {
251 coinbaseTx, err := CreateCoinbaseTx(defaultCtrlProg, block.Height, txFee)
256 if err := ReplaceCoinbase(block, coinbaseTx); err != nil {
260 if _, err := chain.ProcessBlock(block); err == nil {
261 t.Fatalf("invalid coinbase tx validate success")