csv_fork_test.go 22 KB

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