github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/test/tx_test.go (about) 1 // +build functional 2 3 package test 4 5 import ( 6 "encoding/json" 7 "fmt" 8 "io/ioutil" 9 "os" 10 "testing" 11 12 log "github.com/sirupsen/logrus" 13 14 "github.com/bytom/bytom/account" 15 "github.com/bytom/bytom/asset" 16 "github.com/bytom/bytom/blockchain/pseudohsm" 17 "github.com/bytom/bytom/consensus" 18 dbm "github.com/bytom/bytom/database/leveldb" 19 "github.com/bytom/bytom/protocol/bc" 20 "github.com/bytom/bytom/protocol/bc/types" 21 "github.com/bytom/bytom/protocol/validation" 22 "github.com/bytom/bytom/protocol/vm" 23 ) 24 25 func init() { 26 log.SetLevel(log.ErrorLevel) 27 } 28 29 type TxTestConfig struct { 30 Keys []*keyInfo `json:"keys"` 31 Accounts []*accountInfo `json:"accounts"` 32 Transactions []*ttTransaction `json:"transactions"` 33 } 34 35 func (cfg *TxTestConfig) Run() error { 36 dirPath, err := ioutil.TempDir(".", "pseudo_hsm") 37 if err != nil { 38 return err 39 } 40 defer os.RemoveAll(dirPath) 41 hsm, err := pseudohsm.New(dirPath) 42 if err != nil { 43 return err 44 } 45 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) 53 54 generator := NewTxGenerator(accountManager, assets, hsm) 55 for _, key := range cfg.Keys { 56 if err := generator.createKey(key.Name, key.Password); err != nil { 57 return err 58 } 59 } 60 61 for _, acc := range cfg.Accounts { 62 if err := generator.createAccount(acc.Name, acc.Keys, acc.Quorum); err != nil { 63 return err 64 } 65 } 66 67 block := &bc.Block{ 68 BlockHeader: &bc.BlockHeader{ 69 Height: 1, 70 Version: 1, 71 }, 72 } 73 for _, t := range cfg.Transactions { 74 tx, err := t.create(generator) 75 if err != nil { 76 return err 77 } 78 79 tx.TxData.Version = t.Version 80 tx.Tx = types.MapTx(&tx.TxData) 81 status, err := validation.ValidateTx(tx.Tx, block) 82 result := err == nil 83 if result != t.Valid { 84 return fmt.Errorf("tx %s validate failed, expected: %t, have: %t", t.Describe, t.Valid, result) 85 } 86 if status == nil { 87 continue 88 } 89 90 if result && t.TxFee != status.BTMValue { 91 return fmt.Errorf("gas used dismatch, expected: %d, have: %d", t.TxFee, status.BTMValue) 92 } 93 } 94 return nil 95 } 96 97 type ttTransaction struct { 98 wtTransaction 99 Describe string `json:"describe"` 100 Version uint64 `json:"version"` 101 Valid bool `json:"valid"` 102 TxFee uint64 `json:"tx_fee"` 103 } 104 105 // UnmarshalJSON unmarshal transaction with default version 1 106 func (t *ttTransaction) UnmarshalJSON(data []byte) error { 107 type typeAlias ttTransaction 108 tx := &typeAlias{ 109 Version: 1, 110 } 111 112 err := json.Unmarshal(data, tx) 113 if err != nil { 114 return err 115 } 116 *t = ttTransaction(*tx) 117 return nil 118 } 119 120 func (t *ttTransaction) create(g *TxGenerator) (*types.Tx, error) { 121 g.Reset() 122 for _, input := range t.Inputs { 123 switch input.Type { 124 case "spend_account": 125 utxo, err := g.mockUtxo(input.AccountAlias, input.AssetAlias, input.Amount) 126 if err != nil { 127 return nil, err 128 } 129 if err := g.AddTxInputFromUtxo(utxo, input.AccountAlias); err != nil { 130 return nil, err 131 } 132 case "issue": 133 _, err := g.createAsset(input.AccountAlias, input.AssetAlias) 134 if err != nil { 135 return nil, err 136 } 137 if err := g.AddIssuanceInput(input.AssetAlias, input.Amount); err != nil { 138 return nil, err 139 } 140 } 141 } 142 143 for _, output := range t.Outputs { 144 switch output.Type { 145 case "output": 146 if err := g.AddTxOutput(output.AccountAlias, output.AssetAlias, output.Amount); err != nil { 147 return nil, err 148 } 149 case "retire": 150 if err := g.AddRetirement(output.AssetAlias, output.Amount); err != nil { 151 return nil, err 152 } 153 } 154 } 155 return g.Sign(t.Passwords) 156 } 157 158 func TestTx(t *testing.T) { 159 walk(t, txTestDir, func(t *testing.T, name string, test *TxTestConfig) { 160 if err := test.Run(); err != nil { 161 t.Fatal(err) 162 } 163 }) 164 } 165 166 func TestCoinbaseMature(t *testing.T) { 167 db := dbm.NewDB("test_coinbase_mature_db", "leveldb", "test_coinbase_mature_db") 168 defer os.RemoveAll("test_coinbase_mature_db") 169 chain, _, _, _ := MockChain(db) 170 171 defaultCtrlProg := []byte{byte(vm.OP_TRUE)} 172 if err := AppendBlocks(chain, 1); err != nil { 173 t.Fatal(err) 174 } 175 176 height := chain.BestBlockHeight() 177 block, err := chain.GetBlockByHeight(height) 178 if err != nil { 179 t.Fatal(err) 180 } 181 182 tx, err := CreateTxFromTx(block.Transactions[0], 0, 1000000000, defaultCtrlProg) 183 if err != nil { 184 t.Fatal(err) 185 } 186 187 txs := []*types.Tx{tx} 188 matureHeight := chain.BestBlockHeight() + consensus.CoinbasePendingBlockNumber 189 currentHeight := chain.BestBlockHeight() 190 for h := currentHeight + 1; h < matureHeight; h++ { 191 block, err := NewBlock(chain, txs, defaultCtrlProg) 192 if err != nil { 193 t.Fatal(err) 194 } 195 if _, err = chain.ProcessBlock(block); err == nil { 196 t.Fatal("spent immature coinbase output success") 197 } 198 block, err = NewBlock(chain, nil, defaultCtrlProg) 199 if err != nil { 200 t.Fatal(err) 201 } 202 if _, err := chain.ProcessBlock(block); err != nil { 203 t.Fatal(err) 204 } 205 } 206 207 block, err = NewBlock(chain, txs, defaultCtrlProg) 208 if err != nil { 209 t.Fatal(err) 210 } 211 if _, err = chain.ProcessBlock(block); err != nil { 212 t.Fatalf("spent mature coinbase output failed: %s", err) 213 } 214 } 215 216 func TestCoinbaseTx(t *testing.T) { 217 db := dbm.NewDB("test_coinbase_tx_db", "leveldb", "test_coinbase_tx_db") 218 defer os.RemoveAll("test_coinbase_tx_db") 219 chain, _, _, _ := MockChain(db) 220 221 defaultCtrlProg := []byte{byte(vm.OP_TRUE)} 222 if err := AppendBlocks(chain, 1); err != nil { 223 t.Fatal(err) 224 } 225 226 block, err := chain.GetBlockByHeight(chain.BestBlockHeight()) 227 if err != nil { 228 t.Fatal(err) 229 } 230 231 tx, err := CreateTxFromTx(block.Transactions[0], 0, 1000000000, defaultCtrlProg) 232 if err != nil { 233 t.Fatal(err) 234 } 235 236 block, err = NewBlock(chain, []*types.Tx{tx}, defaultCtrlProg) 237 if err != nil { 238 t.Fatal(err) 239 } 240 241 txFees := []uint64{100000, 5000000000000} 242 for _, txFee := range txFees { 243 coinbaseTx, err := CreateCoinbaseTx(defaultCtrlProg, block.Height, txFee) 244 if err != nil { 245 t.Fatal(err) 246 } 247 248 if err := ReplaceCoinbase(block, coinbaseTx); err != nil { 249 t.Fatal(err) 250 } 251 252 if _, err = chain.ProcessBlock(block); err == nil { 253 t.Fatalf("invalid coinbase tx validate success") 254 } 255 } 256 }