1// Copyright (c) 2016 The btcsuite developers 2// Use of this source code is governed by an ISC 3// license that can be found in the LICENSE file. 4 5// This file is ignored during the regular tests due to the following build tag. 6// +build rpctest 7 8package integration 9 10import ( 11 "bytes" 12 "runtime" 13 "strings" 14 "testing" 15 "time" 16 17 "github.com/btcsuite/btcd/blockchain" 18 "github.com/btcsuite/btcd/btcec" 19 "github.com/btcsuite/btcd/chaincfg" 20 "github.com/btcsuite/btcd/chaincfg/chainhash" 21 "github.com/btcsuite/btcd/integration/rpctest" 22 "github.com/btcsuite/btcd/txscript" 23 "github.com/btcsuite/btcd/wire" 24 "github.com/btcsuite/btcutil" 25) 26 27const ( 28 csvKey = "csv" 29) 30 31// makeTestOutput creates an on-chain output paying to a freshly generated 32// p2pkh output with the specified amount. 33func makeTestOutput(r *rpctest.Harness, t *testing.T, 34 amt btcutil.Amount) (*btcec.PrivateKey, *wire.OutPoint, []byte, error) { 35 36 // Create a fresh key, then send some coins to an address spendable by 37 // that key. 38 key, err := btcec.NewPrivateKey(btcec.S256()) 39 if err != nil { 40 return nil, nil, nil, err 41 } 42 43 // Using the key created above, generate a pkScript which it's able to 44 // spend. 45 a, err := btcutil.NewAddressPubKey(key.PubKey().SerializeCompressed(), r.ActiveNet) 46 if err != nil { 47 return nil, nil, nil, err 48 } 49 selfAddrScript, err := txscript.PayToAddrScript(a.AddressPubKeyHash()) 50 if err != nil { 51 return nil, nil, nil, err 52 } 53 output := &wire.TxOut{PkScript: selfAddrScript, Value: 1e8} 54 55 // Next, create and broadcast a transaction paying to the output. 56 fundTx, err := r.CreateTransaction([]*wire.TxOut{output}, 10, true) 57 if err != nil { 58 return nil, nil, nil, err 59 } 60 txHash, err := r.Node.SendRawTransaction(fundTx, true) 61 if err != nil { 62 return nil, nil, nil, err 63 } 64 65 // The transaction created above should be included within the next 66 // generated block. 67 blockHash, err := r.Node.Generate(1) 68 if err != nil { 69 return nil, nil, nil, err 70 } 71 assertTxInBlock(r, t, blockHash[0], txHash) 72 73 // Locate the output index of the coins spendable by the key we 74 // generated above, this is needed in order to create a proper utxo for 75 // this output. 76 var outputIndex uint32 77 if bytes.Equal(fundTx.TxOut[0].PkScript, selfAddrScript) { 78 outputIndex = 0 79 } else { 80 outputIndex = 1 81 } 82 83 utxo := &wire.OutPoint{ 84 Hash: fundTx.TxHash(), 85 Index: outputIndex, 86 } 87 88 return key, utxo, selfAddrScript, nil 89} 90 91// TestBIP0113Activation tests for proper adherence of the BIP 113 rule 92// constraint which requires all transaction finality tests to use the MTP of 93// the last 11 blocks, rather than the timestamp of the block which includes 94// them. 95// 96// Overview: 97// - Pre soft-fork: 98// - Transactions with non-final lock-times from the PoV of MTP should be 99// rejected from the mempool. 100// - Transactions within non-final MTP based lock-times should be accepted 101// in valid blocks. 102// 103// - Post soft-fork: 104// - Transactions with non-final lock-times from the PoV of MTP should be 105// rejected from the mempool and when found within otherwise valid blocks. 106// - Transactions with final lock-times from the PoV of MTP should be 107// accepted to the mempool and mined in future block. 108func TestBIP0113Activation(t *testing.T) { 109 t.Parallel() 110 111 btcdCfg := []string{"--rejectnonstd"} 112 r, err := rpctest.New(&chaincfg.SimNetParams, nil, btcdCfg) 113 if err != nil { 114 t.Fatal("unable to create primary harness: ", err) 115 } 116 if err := r.SetUp(true, 1); err != nil { 117 t.Fatalf("unable to setup test chain: %v", err) 118 } 119 defer r.TearDown() 120 121 // Create a fresh output for usage within the test below. 122 const outputValue = btcutil.SatoshiPerBitcoin 123 outputKey, testOutput, testPkScript, err := makeTestOutput(r, t, 124 outputValue) 125 if err != nil { 126 t.Fatalf("unable to create test output: %v", err) 127 } 128 129 // Fetch a fresh address from the harness, we'll use this address to 130 // send funds back into the Harness. 131 addr, err := r.NewAddress() 132 if err != nil { 133 t.Fatalf("unable to generate address: %v", err) 134 } 135 addrScript, err := txscript.PayToAddrScript(addr) 136 if err != nil { 137 t.Fatalf("unable to generate addr script: %v", err) 138 } 139 140 // Now create a transaction with a lock time which is "final" according 141 // to the latest block, but not according to the current median time 142 // past. 143 tx := wire.NewMsgTx(1) 144 tx.AddTxIn(&wire.TxIn{ 145 PreviousOutPoint: *testOutput, 146 }) 147 tx.AddTxOut(&wire.TxOut{ 148 PkScript: addrScript, 149 Value: outputValue - 1000, 150 }) 151 152 // We set the lock-time of the transaction to just one minute after the 153 // current MTP of the chain. 154 chainInfo, err := r.Node.GetBlockChainInfo() 155 if err != nil { 156 t.Fatalf("unable to query for chain info: %v", err) 157 } 158 tx.LockTime = uint32(chainInfo.MedianTime) + 1 159 160 sigScript, err := txscript.SignatureScript(tx, 0, testPkScript, 161 txscript.SigHashAll, outputKey, true) 162 if err != nil { 163 t.Fatalf("unable to generate sig: %v", err) 164 } 165 tx.TxIn[0].SignatureScript = sigScript 166 167 // This transaction should be rejected from the mempool as using MTP 168 // for transactions finality is now a policy rule. Additionally, the 169 // exact error should be the rejection of a non-final transaction. 170 _, err = r.Node.SendRawTransaction(tx, true) 171 if err == nil { 172 t.Fatalf("transaction accepted, but should be non-final") 173 } else if !strings.Contains(err.Error(), "not finalized") { 174 t.Fatalf("transaction should be rejected due to being "+ 175 "non-final, instead: %v", err) 176 } 177 178 // However, since the block validation consensus rules haven't yet 179 // activated, a block including the transaction should be accepted. 180 txns := []*btcutil.Tx{btcutil.NewTx(tx)} 181 block, err := r.GenerateAndSubmitBlock(txns, -1, time.Time{}) 182 if err != nil { 183 t.Fatalf("unable to submit block: %v", err) 184 } 185 txid := tx.TxHash() 186 assertTxInBlock(r, t, block.Hash(), &txid) 187 188 // At this point, the block height should be 103: we mined 101 blocks 189 // to create a single mature output, then an additional block to create 190 // a new output, and then mined a single block above to include our 191 // transaction. 192 assertChainHeight(r, t, 103) 193 194 // Next, mine enough blocks to ensure that the soft-fork becomes 195 // activated. Assert that the block version of the second-to-last block 196 // in the final range is active. 197 198 // Next, mine ensure blocks to ensure that the soft-fork becomes 199 // active. We're at height 103 and we need 200 blocks to be mined after 200 // the genesis target period, so we mine 196 blocks. This'll put us at 201 // height 299. The getblockchaininfo call checks the state for the 202 // block AFTER the current height. 203 numBlocks := (r.ActiveNet.MinerConfirmationWindow * 2) - 4 204 if _, err := r.Node.Generate(numBlocks); err != nil { 205 t.Fatalf("unable to generate blocks: %v", err) 206 } 207 208 assertChainHeight(r, t, 299) 209 assertSoftForkStatus(r, t, csvKey, blockchain.ThresholdActive) 210 211 // The timeLockDeltas slice represents a series of deviations from the 212 // current MTP which will be used to test border conditions w.r.t 213 // transaction finality. -1 indicates 1 second prior to the MTP, 0 214 // indicates the current MTP, and 1 indicates 1 second after the 215 // current MTP. 216 // 217 // This time, all transactions which are final according to the MTP 218 // *should* be accepted to both the mempool and within a valid block. 219 // While transactions with lock-times *after* the current MTP should be 220 // rejected. 221 timeLockDeltas := []int64{-1, 0, 1} 222 for _, timeLockDelta := range timeLockDeltas { 223 chainInfo, err = r.Node.GetBlockChainInfo() 224 if err != nil { 225 t.Fatalf("unable to query for chain info: %v", err) 226 } 227 medianTimePast := chainInfo.MedianTime 228 229 // Create another test output to be spent shortly below. 230 outputKey, testOutput, testPkScript, err = makeTestOutput(r, t, 231 outputValue) 232 if err != nil { 233 t.Fatalf("unable to create test output: %v", err) 234 } 235 236 // Create a new transaction with a lock-time past the current known 237 // MTP. 238 tx = wire.NewMsgTx(1) 239 tx.AddTxIn(&wire.TxIn{ 240 PreviousOutPoint: *testOutput, 241 }) 242 tx.AddTxOut(&wire.TxOut{ 243 PkScript: addrScript, 244 Value: outputValue - 1000, 245 }) 246 tx.LockTime = uint32(medianTimePast + timeLockDelta) 247 sigScript, err = txscript.SignatureScript(tx, 0, testPkScript, 248 txscript.SigHashAll, outputKey, true) 249 if err != nil { 250 t.Fatalf("unable to generate sig: %v", err) 251 } 252 tx.TxIn[0].SignatureScript = sigScript 253 254 // If the time-lock delta is greater than -1, then the 255 // transaction should be rejected from the mempool and when 256 // included within a block. A time-lock delta of -1 should be 257 // accepted as it has a lock-time of one 258 // second _before_ the current MTP. 259 260 _, err = r.Node.SendRawTransaction(tx, true) 261 if err == nil && timeLockDelta >= 0 { 262 t.Fatal("transaction was accepted into the mempool " + 263 "but should be rejected!") 264 } else if err != nil && !strings.Contains(err.Error(), "not finalized") { 265 t.Fatalf("transaction should be rejected from mempool "+ 266 "due to being non-final, instead: %v", err) 267 } 268 269 txns = []*btcutil.Tx{btcutil.NewTx(tx)} 270 _, err := r.GenerateAndSubmitBlock(txns, -1, time.Time{}) 271 if err == nil && timeLockDelta >= 0 { 272 t.Fatal("block should be rejected due to non-final " + 273 "txn, but was accepted") 274 } else if err != nil && !strings.Contains(err.Error(), "unfinalized") { 275 t.Fatalf("block should be rejected due to non-final "+ 276 "tx, instead: %v", err) 277 } 278 } 279} 280 281// createCSVOutput creates an output paying to a trivially redeemable CSV 282// pkScript with the specified time-lock. 283func createCSVOutput(r *rpctest.Harness, t *testing.T, 284 numSatoshis btcutil.Amount, timeLock int32, 285 isSeconds bool) ([]byte, *wire.OutPoint, *wire.MsgTx, error) { 286 287 // Convert the time-lock to the proper sequence lock based according to 288 // if the lock is seconds or time based. 289 sequenceLock := blockchain.LockTimeToSequence(isSeconds, 290 uint32(timeLock)) 291 292 // Our CSV script is simply: <sequenceLock> OP_CSV OP_DROP 293 b := txscript.NewScriptBuilder(). 294 AddInt64(int64(sequenceLock)). 295 AddOp(txscript.OP_CHECKSEQUENCEVERIFY). 296 AddOp(txscript.OP_DROP) 297 csvScript, err := b.Script() 298 if err != nil { 299 return nil, nil, nil, err 300 } 301 302 // Using the script generated above, create a P2SH output which will be 303 // accepted into the mempool. 304 p2shAddr, err := btcutil.NewAddressScriptHash(csvScript, r.ActiveNet) 305 if err != nil { 306 return nil, nil, nil, err 307 } 308 p2shScript, err := txscript.PayToAddrScript(p2shAddr) 309 if err != nil { 310 return nil, nil, nil, err 311 } 312 output := &wire.TxOut{ 313 PkScript: p2shScript, 314 Value: int64(numSatoshis), 315 } 316 317 // Finally create a valid transaction which creates the output crafted 318 // above. 319 tx, err := r.CreateTransaction([]*wire.TxOut{output}, 10, true) 320 if err != nil { 321 return nil, nil, nil, err 322 } 323 324 var outputIndex uint32 325 if !bytes.Equal(tx.TxOut[0].PkScript, p2shScript) { 326 outputIndex = 1 327 } 328 329 utxo := &wire.OutPoint{ 330 Hash: tx.TxHash(), 331 Index: outputIndex, 332 } 333 334 return csvScript, utxo, tx, nil 335} 336 337// spendCSVOutput spends an output previously created by the createCSVOutput 338// function. The sigScript is a trivial push of OP_TRUE followed by the 339// redeemScript to pass P2SH evaluation. 340func spendCSVOutput(redeemScript []byte, csvUTXO *wire.OutPoint, 341 sequence uint32, targetOutput *wire.TxOut, 342 txVersion int32) (*wire.MsgTx, error) { 343 344 tx := wire.NewMsgTx(txVersion) 345 tx.AddTxIn(&wire.TxIn{ 346 PreviousOutPoint: *csvUTXO, 347 Sequence: sequence, 348 }) 349 tx.AddTxOut(targetOutput) 350 351 b := txscript.NewScriptBuilder(). 352 AddOp(txscript.OP_TRUE). 353 AddData(redeemScript) 354 355 sigScript, err := b.Script() 356 if err != nil { 357 return nil, err 358 } 359 tx.TxIn[0].SignatureScript = sigScript 360 361 return tx, nil 362} 363 364// assertTxInBlock asserts a transaction with the specified txid is found 365// within the block with the passed block hash. 366func assertTxInBlock(r *rpctest.Harness, t *testing.T, blockHash *chainhash.Hash, 367 txid *chainhash.Hash) { 368 369 block, err := r.Node.GetBlock(blockHash) 370 if err != nil { 371 t.Fatalf("unable to get block: %v", err) 372 } 373 if len(block.Transactions) < 2 { 374 t.Fatal("target transaction was not mined") 375 } 376 377 for _, txn := range block.Transactions { 378 txHash := txn.TxHash() 379 if txn.TxHash() == txHash { 380 return 381 } 382 } 383 384 _, _, line, _ := runtime.Caller(1) 385 t.Fatalf("assertion failed at line %v: txid %v was not found in "+ 386 "block %v", line, txid, blockHash) 387} 388 389// TestBIP0068AndBIP0112Activation tests for the proper adherence to the BIP 390// 112 and BIP 68 rule-set after the activation of the CSV-package soft-fork. 391// 392// Overview: 393// - Pre soft-fork: 394// - A transaction spending a CSV output validly should be rejected from the 395// mempool, but accepted in a valid generated block including the 396// transaction. 397// - Post soft-fork: 398// - See the cases exercised within the table driven tests towards the end 399// of this test. 400func TestBIP0068AndBIP0112Activation(t *testing.T) { 401 t.Parallel() 402 403 // We'd like the test proper evaluation and validation of the BIP 68 404 // (sequence locks) and BIP 112 rule-sets which add input-age based 405 // relative lock times. 406 407 btcdCfg := []string{"--rejectnonstd"} 408 r, err := rpctest.New(&chaincfg.SimNetParams, nil, btcdCfg) 409 if err != nil { 410 t.Fatal("unable to create primary harness: ", err) 411 } 412 if err := r.SetUp(true, 1); err != nil { 413 t.Fatalf("unable to setup test chain: %v", err) 414 } 415 defer r.TearDown() 416 417 assertSoftForkStatus(r, t, csvKey, blockchain.ThresholdStarted) 418 419 harnessAddr, err := r.NewAddress() 420 if err != nil { 421 t.Fatalf("unable to obtain harness address: %v", err) 422 } 423 harnessScript, err := txscript.PayToAddrScript(harnessAddr) 424 if err != nil { 425 t.Fatalf("unable to generate pkScript: %v", err) 426 } 427 428 const ( 429 outputAmt = btcutil.SatoshiPerBitcoin 430 relativeBlockLock = 10 431 ) 432 433 sweepOutput := &wire.TxOut{ 434 Value: outputAmt - 5000, 435 PkScript: harnessScript, 436 } 437 438 // As the soft-fork hasn't yet activated _any_ transaction version 439 // which uses the CSV opcode should be accepted. Since at this point, 440 // CSV doesn't actually exist, it's just a NOP. 441 for txVersion := int32(0); txVersion < 3; txVersion++ { 442 // Create a trivially spendable output with a CSV lock-time of 443 // 10 relative blocks. 444 redeemScript, testUTXO, tx, err := createCSVOutput(r, t, outputAmt, 445 relativeBlockLock, false) 446 if err != nil { 447 t.Fatalf("unable to create CSV encumbered output: %v", err) 448 } 449 450 // As the transaction is p2sh it should be accepted into the 451 // mempool and found within the next generated block. 452 if _, err := r.Node.SendRawTransaction(tx, true); err != nil { 453 t.Fatalf("unable to broadcast tx: %v", err) 454 } 455 blocks, err := r.Node.Generate(1) 456 if err != nil { 457 t.Fatalf("unable to generate blocks: %v", err) 458 } 459 txid := tx.TxHash() 460 assertTxInBlock(r, t, blocks[0], &txid) 461 462 // Generate a custom transaction which spends the CSV output. 463 sequenceNum := blockchain.LockTimeToSequence(false, 10) 464 spendingTx, err := spendCSVOutput(redeemScript, testUTXO, 465 sequenceNum, sweepOutput, txVersion) 466 if err != nil { 467 t.Fatalf("unable to spend csv output: %v", err) 468 } 469 470 // This transaction should be rejected from the mempool since 471 // CSV validation is already mempool policy pre-fork. 472 _, err = r.Node.SendRawTransaction(spendingTx, true) 473 if err == nil { 474 t.Fatalf("transaction should have been rejected, but was " + 475 "instead accepted") 476 } 477 478 // However, this transaction should be accepted in a custom 479 // generated block as CSV validation for scripts within blocks 480 // shouldn't yet be active. 481 txns := []*btcutil.Tx{btcutil.NewTx(spendingTx)} 482 block, err := r.GenerateAndSubmitBlock(txns, -1, time.Time{}) 483 if err != nil { 484 t.Fatalf("unable to submit block: %v", err) 485 } 486 txid = spendingTx.TxHash() 487 assertTxInBlock(r, t, block.Hash(), &txid) 488 } 489 490 // At this point, the block height should be 107: we started at height 491 // 101, then generated 2 blocks in each loop iteration above. 492 assertChainHeight(r, t, 107) 493 494 // With the height at 107 we need 200 blocks to be mined after the 495 // genesis target period, so we mine 192 blocks. This'll put us at 496 // height 299. The getblockchaininfo call checks the state for the 497 // block AFTER the current height. 498 numBlocks := (r.ActiveNet.MinerConfirmationWindow * 2) - 8 499 if _, err := r.Node.Generate(numBlocks); err != nil { 500 t.Fatalf("unable to generate blocks: %v", err) 501 } 502 503 assertChainHeight(r, t, 299) 504 assertSoftForkStatus(r, t, csvKey, blockchain.ThresholdActive) 505 506 // Knowing the number of outputs needed for the tests below, create a 507 // fresh output for use within each of the test-cases below. 508 const relativeTimeLock = 512 509 const numTests = 8 510 type csvOutput struct { 511 RedeemScript []byte 512 Utxo *wire.OutPoint 513 Timelock int32 514 } 515 var spendableInputs [numTests]csvOutput 516 517 // Create three outputs which have a block-based sequence locks, and 518 // three outputs which use the above time based sequence lock. 519 for i := 0; i < numTests; i++ { 520 timeLock := relativeTimeLock 521 isSeconds := true 522 if i < 7 { 523 timeLock = relativeBlockLock 524 isSeconds = false 525 } 526 527 redeemScript, utxo, tx, err := createCSVOutput(r, t, outputAmt, 528 int32(timeLock), isSeconds) 529 if err != nil { 530 t.Fatalf("unable to create CSV output: %v", err) 531 } 532 533 if _, err := r.Node.SendRawTransaction(tx, true); err != nil { 534 t.Fatalf("unable to broadcast transaction: %v", err) 535 } 536 537 spendableInputs[i] = csvOutput{ 538 RedeemScript: redeemScript, 539 Utxo: utxo, 540 Timelock: int32(timeLock), 541 } 542 } 543 544 // Mine a single block including all the transactions generated above. 545 if _, err := r.Node.Generate(1); err != nil { 546 t.Fatalf("unable to generate block: %v", err) 547 } 548 549 // Now mine 10 additional blocks giving the inputs generated above a 550 // age of 11. Space out each block 10 minutes after the previous block. 551 prevBlockHash, err := r.Node.GetBestBlockHash() 552 if err != nil { 553 t.Fatalf("unable to get prior block hash: %v", err) 554 } 555 prevBlock, err := r.Node.GetBlock(prevBlockHash) 556 if err != nil { 557 t.Fatalf("unable to get block: %v", err) 558 } 559 for i := 0; i < relativeBlockLock; i++ { 560 timeStamp := prevBlock.Header.Timestamp.Add(time.Minute * 10) 561 b, err := r.GenerateAndSubmitBlock(nil, -1, timeStamp) 562 if err != nil { 563 t.Fatalf("unable to generate block: %v", err) 564 } 565 566 prevBlock = b.MsgBlock() 567 } 568 569 // A helper function to create fully signed transactions in-line during 570 // the array initialization below. 571 var inputIndex uint32 572 makeTxCase := func(sequenceNum uint32, txVersion int32) *wire.MsgTx { 573 csvInput := spendableInputs[inputIndex] 574 575 tx, err := spendCSVOutput(csvInput.RedeemScript, csvInput.Utxo, 576 sequenceNum, sweepOutput, txVersion) 577 if err != nil { 578 t.Fatalf("unable to spend CSV output: %v", err) 579 } 580 581 inputIndex++ 582 return tx 583 } 584 585 tests := [numTests]struct { 586 tx *wire.MsgTx 587 accept bool 588 }{ 589 // A valid transaction with a single input a sequence number 590 // creating a 100 block relative time-lock. This transaction 591 // should be rejected as its version number is 1, and only tx 592 // of version > 2 will trigger the CSV behavior. 593 { 594 tx: makeTxCase(blockchain.LockTimeToSequence(false, 100), 1), 595 accept: false, 596 }, 597 // A transaction of version 2 spending a single input. The 598 // input has a relative time-lock of 1 block, but the disable 599 // bit it set. The transaction should be rejected as a result. 600 { 601 tx: makeTxCase( 602 blockchain.LockTimeToSequence(false, 1)|wire.SequenceLockTimeDisabled, 603 2, 604 ), 605 accept: false, 606 }, 607 // A v2 transaction with a single input having a 9 block 608 // relative time lock. The referenced input is 11 blocks old, 609 // but the CSV output requires a 10 block relative lock-time. 610 // Therefore, the transaction should be rejected. 611 { 612 tx: makeTxCase(blockchain.LockTimeToSequence(false, 9), 2), 613 accept: false, 614 }, 615 // A v2 transaction with a single input having a 10 block 616 // relative time lock. The referenced input is 11 blocks old so 617 // the transaction should be accepted. 618 { 619 tx: makeTxCase(blockchain.LockTimeToSequence(false, 10), 2), 620 accept: true, 621 }, 622 // A v2 transaction with a single input having a 11 block 623 // relative time lock. The input referenced has an input age of 624 // 11 and the CSV op-code requires 10 blocks to have passed, so 625 // this transaction should be accepted. 626 { 627 tx: makeTxCase(blockchain.LockTimeToSequence(false, 11), 2), 628 accept: true, 629 }, 630 // A v2 transaction whose input has a 1000 blck relative time 631 // lock. This should be rejected as the input's age is only 11 632 // blocks. 633 { 634 tx: makeTxCase(blockchain.LockTimeToSequence(false, 1000), 2), 635 accept: false, 636 }, 637 // A v2 transaction with a single input having a 512,000 second 638 // relative time-lock. This transaction should be rejected as 6 639 // days worth of blocks haven't yet been mined. The referenced 640 // input doesn't have sufficient age. 641 { 642 tx: makeTxCase(blockchain.LockTimeToSequence(true, 512000), 2), 643 accept: false, 644 }, 645 // A v2 transaction whose single input has a 512 second 646 // relative time-lock. This transaction should be accepted as 647 // finalized. 648 { 649 tx: makeTxCase(blockchain.LockTimeToSequence(true, 512), 2), 650 accept: true, 651 }, 652 } 653 654 for i, test := range tests { 655 txid, err := r.Node.SendRawTransaction(test.tx, true) 656 switch { 657 // Test case passes, nothing further to report. 658 case test.accept && err == nil: 659 660 // Transaction should have been accepted but we have a non-nil 661 // error. 662 case test.accept && err != nil: 663 t.Fatalf("test #%d, transaction should be accepted, "+ 664 "but was rejected: %v", i, err) 665 666 // Transaction should have been rejected, but it was accepted. 667 case !test.accept && err == nil: 668 t.Fatalf("test #%d, transaction should be rejected, "+ 669 "but was accepted", i) 670 671 // Transaction was rejected as wanted, nothing more to do. 672 case !test.accept && err != nil: 673 } 674 675 // If the transaction should be rejected, manually mine a block 676 // with the non-final transaction. It should be rejected. 677 if !test.accept { 678 txns := []*btcutil.Tx{btcutil.NewTx(test.tx)} 679 _, err := r.GenerateAndSubmitBlock(txns, -1, time.Time{}) 680 if err == nil { 681 t.Fatalf("test #%d, invalid block accepted", i) 682 } 683 684 continue 685 } 686 687 // Generate a block, the transaction should be included within 688 // the newly mined block. 689 blockHashes, err := r.Node.Generate(1) 690 if err != nil { 691 t.Fatalf("unable to mine block: %v", err) 692 } 693 assertTxInBlock(r, t, blockHashes[0], txid) 694 } 695} 696