estimatefee_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  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. package mempool
  5. import (
  6. "bytes"
  7. "math/rand"
  8. "testing"
  9. "github.com/pkt-cash/pktd/btcutil/er"
  10. "github.com/pkt-cash/pktd/btcutil"
  11. "github.com/pkt-cash/pktd/chaincfg/chainhash"
  12. "github.com/pkt-cash/pktd/mining"
  13. "github.com/pkt-cash/pktd/wire"
  14. )
  15. // newTestFeeEstimator creates a feeEstimator with some different parameters
  16. // for testing purposes.
  17. func newTestFeeEstimator(binSize, maxReplacements, maxRollback uint32) *FeeEstimator {
  18. return &FeeEstimator{
  19. maxRollback: maxRollback,
  20. lastKnownHeight: 0,
  21. binSize: int32(binSize),
  22. minRegisteredBlocks: 0,
  23. maxReplacements: int32(maxReplacements),
  24. observed: make(map[chainhash.Hash]*observedTransaction),
  25. dropped: make([]*registeredBlock, 0, maxRollback),
  26. }
  27. }
  28. // lastBlock is a linked list of the block hashes which have been
  29. // processed by the test FeeEstimator.
  30. type lastBlock struct {
  31. hash *chainhash.Hash
  32. prev *lastBlock
  33. }
  34. // estimateFeeTester interacts with the FeeEstimator to keep track
  35. // of its expected state.
  36. type estimateFeeTester struct {
  37. ef *FeeEstimator
  38. t *testing.T
  39. version int32
  40. height int32
  41. last *lastBlock
  42. }
  43. func (eft *estimateFeeTester) testTx(fee btcutil.Amount) *TxDesc {
  44. eft.version++
  45. return &TxDesc{
  46. TxDesc: mining.TxDesc{
  47. Tx: btcutil.NewTx(&wire.MsgTx{
  48. Version: eft.version,
  49. }),
  50. Height: eft.height,
  51. Fee: int64(fee),
  52. },
  53. StartingPriority: 0,
  54. }
  55. }
  56. func expectedFeePerKilobyte(t *TxDesc) BtcPerKilobyte {
  57. size := float64(t.TxDesc.Tx.MsgTx().SerializeSize())
  58. fee := float64(t.TxDesc.Fee)
  59. return SatoshiPerByte(fee / size).ToBtcPerKb()
  60. }
  61. func (eft *estimateFeeTester) newBlock(txs []*wire.MsgTx) {
  62. eft.height++
  63. block := btcutil.NewBlock(&wire.MsgBlock{
  64. Transactions: txs,
  65. })
  66. block.SetHeight(eft.height)
  67. eft.last = &lastBlock{block.Hash(), eft.last}
  68. eft.ef.RegisterBlock(block)
  69. }
  70. func (eft *estimateFeeTester) rollback() {
  71. if eft.last == nil {
  72. return
  73. }
  74. err := eft.ef.Rollback(eft.last.hash)
  75. if err != nil {
  76. eft.t.Errorf("Could not rollback: %v", err)
  77. }
  78. eft.height--
  79. eft.last = eft.last.prev
  80. }
  81. // TestEstimateFee tests basic functionality in the FeeEstimator.
  82. func TestEstimateFee(t *testing.T) {
  83. ef := newTestFeeEstimator(5, 3, 1)
  84. eft := estimateFeeTester{ef: ef, t: t}
  85. // Try with no txs and get zero for all queries.
  86. expected := BtcPerKilobyte(0.0)
  87. for i := uint32(1); i <= estimateFeeDepth; i++ {
  88. estimated, _ := ef.EstimateFee(i)
  89. if estimated != expected {
  90. t.Errorf("Estimate fee error: expected %f when estimator is empty; got %f", expected, estimated)
  91. }
  92. }
  93. // Now insert a tx.
  94. tx := eft.testTx(1000000)
  95. ef.ObserveTransaction(tx)
  96. // Expected should still be zero because this is still in the mempool.
  97. expected = BtcPerKilobyte(0.0)
  98. for i := uint32(1); i <= estimateFeeDepth; i++ {
  99. estimated, _ := ef.EstimateFee(i)
  100. if estimated != expected {
  101. t.Errorf("Estimate fee error: expected %f when estimator has one tx in mempool; got %f", expected, estimated)
  102. }
  103. }
  104. // Change minRegisteredBlocks to make sure that works. Error return
  105. // value expected.
  106. ef.minRegisteredBlocks = 1
  107. expected = BtcPerKilobyte(-1.0)
  108. for i := uint32(1); i <= estimateFeeDepth; i++ {
  109. estimated, _ := ef.EstimateFee(i)
  110. if estimated != expected {
  111. t.Errorf("Estimate fee error: expected %f before any blocks have been registered; got %f", expected, estimated)
  112. }
  113. }
  114. // Record a block with the new tx.
  115. eft.newBlock([]*wire.MsgTx{tx.Tx.MsgTx()})
  116. expected = expectedFeePerKilobyte(tx)
  117. for i := uint32(1); i <= estimateFeeDepth; i++ {
  118. estimated, _ := ef.EstimateFee(i)
  119. if estimated != expected {
  120. t.Errorf("Estimate fee error: expected %f when one tx is binned; got %f", expected, estimated)
  121. }
  122. }
  123. // Roll back the last block; this was an orphan block.
  124. ef.minRegisteredBlocks = 0
  125. eft.rollback()
  126. expected = BtcPerKilobyte(0.0)
  127. for i := uint32(1); i <= estimateFeeDepth; i++ {
  128. estimated, _ := ef.EstimateFee(i)
  129. if estimated != expected {
  130. t.Errorf("Estimate fee error: expected %f after rolling back block; got %f", expected, estimated)
  131. }
  132. }
  133. // Record an empty block and then a block with the new tx.
  134. // This test was made because of a bug that only appeared when there
  135. // were no transactions in the first bin.
  136. eft.newBlock([]*wire.MsgTx{})
  137. eft.newBlock([]*wire.MsgTx{tx.Tx.MsgTx()})
  138. expected = expectedFeePerKilobyte(tx)
  139. for i := uint32(1); i <= estimateFeeDepth; i++ {
  140. estimated, _ := ef.EstimateFee(i)
  141. if estimated != expected {
  142. t.Errorf("Estimate fee error: expected %f when one tx is binned; got %f", expected, estimated)
  143. }
  144. }
  145. // Create some more transactions.
  146. txA := eft.testTx(500000)
  147. txB := eft.testTx(2000000)
  148. txC := eft.testTx(4000000)
  149. ef.ObserveTransaction(txA)
  150. ef.ObserveTransaction(txB)
  151. ef.ObserveTransaction(txC)
  152. // Record 7 empty blocks.
  153. for i := 0; i < 7; i++ {
  154. eft.newBlock([]*wire.MsgTx{})
  155. }
  156. // Mine the first tx.
  157. eft.newBlock([]*wire.MsgTx{txA.Tx.MsgTx()})
  158. // Now the estimated amount should depend on the value
  159. // of the argument to estimate fee.
  160. for i := uint32(1); i <= estimateFeeDepth; i++ {
  161. estimated, _ := ef.EstimateFee(i)
  162. if i > 2 {
  163. expected = expectedFeePerKilobyte(txA)
  164. } else {
  165. expected = expectedFeePerKilobyte(tx)
  166. }
  167. if estimated != expected {
  168. t.Errorf("Estimate fee error: expected %f on round %d; got %f", expected, i, estimated)
  169. }
  170. }
  171. // Record 5 more empty blocks.
  172. for i := 0; i < 5; i++ {
  173. eft.newBlock([]*wire.MsgTx{})
  174. }
  175. // Mine the next tx.
  176. eft.newBlock([]*wire.MsgTx{txB.Tx.MsgTx()})
  177. // Now the estimated amount should depend on the value
  178. // of the argument to estimate fee.
  179. for i := uint32(1); i <= estimateFeeDepth; i++ {
  180. estimated, _ := ef.EstimateFee(i)
  181. if i <= 2 {
  182. expected = expectedFeePerKilobyte(txB)
  183. } else if i <= 8 {
  184. expected = expectedFeePerKilobyte(tx)
  185. } else {
  186. expected = expectedFeePerKilobyte(txA)
  187. }
  188. if estimated != expected {
  189. t.Errorf("Estimate fee error: expected %f on round %d; got %f", expected, i, estimated)
  190. }
  191. }
  192. // Record 9 more empty blocks.
  193. for i := 0; i < 10; i++ {
  194. eft.newBlock([]*wire.MsgTx{})
  195. }
  196. // Mine txC.
  197. eft.newBlock([]*wire.MsgTx{txC.Tx.MsgTx()})
  198. // This should have no effect on the outcome because too
  199. // many blocks have been mined for txC to be recorded.
  200. for i := uint32(1); i <= estimateFeeDepth; i++ {
  201. estimated, _ := ef.EstimateFee(i)
  202. if i <= 2 {
  203. expected = expectedFeePerKilobyte(txC)
  204. } else if i <= 8 {
  205. expected = expectedFeePerKilobyte(txB)
  206. } else if i <= 8+6 {
  207. expected = expectedFeePerKilobyte(tx)
  208. } else {
  209. expected = expectedFeePerKilobyte(txA)
  210. }
  211. if estimated != expected {
  212. t.Errorf("Estimate fee error: expected %f on round %d; got %f", expected, i, estimated)
  213. }
  214. }
  215. }
  216. func (eft *estimateFeeTester) estimates() [estimateFeeDepth]BtcPerKilobyte {
  217. // Generate estimates
  218. var estimates [estimateFeeDepth]BtcPerKilobyte
  219. for i := 0; i < estimateFeeDepth; i++ {
  220. estimates[i], _ = eft.ef.EstimateFee(uint32(i + 1))
  221. }
  222. // Check that all estimated fee results go in descending order.
  223. for i := 1; i < estimateFeeDepth; i++ {
  224. if estimates[i] > estimates[i-1] {
  225. eft.t.Error("Estimates not in descending order; got ",
  226. estimates[i], " for estimate ", i, " and ", estimates[i-1], " for ", (i - 1))
  227. panic("invalid state.")
  228. }
  229. }
  230. return estimates
  231. }
  232. func (eft *estimateFeeTester) round(txHistory [][]*TxDesc,
  233. estimateHistory [][estimateFeeDepth]BtcPerKilobyte,
  234. txPerRound, txPerBlock uint32) ([][]*TxDesc, [][estimateFeeDepth]BtcPerKilobyte) {
  235. // generate new txs.
  236. var newTxs []*TxDesc
  237. for i := uint32(0); i < txPerRound; i++ {
  238. newTx := eft.testTx(btcutil.Amount(rand.Intn(1000000)))
  239. eft.ef.ObserveTransaction(newTx)
  240. newTxs = append(newTxs, newTx)
  241. }
  242. // Generate mempool.
  243. mempool := make(map[*observedTransaction]*TxDesc)
  244. for _, h := range txHistory {
  245. for _, t := range h {
  246. if o, exists := eft.ef.observed[*t.Tx.Hash()]; exists && o.mined == mining.UnminedHeight {
  247. mempool[o] = t
  248. }
  249. }
  250. }
  251. // generate new block, with no duplicates.
  252. i := uint32(0)
  253. newBlockList := make([]*wire.MsgTx, 0, txPerBlock)
  254. for _, t := range mempool {
  255. newBlockList = append(newBlockList, t.TxDesc.Tx.MsgTx())
  256. i++
  257. if i == txPerBlock {
  258. break
  259. }
  260. }
  261. // Register a new block.
  262. eft.newBlock(newBlockList)
  263. // return results.
  264. estimates := eft.estimates()
  265. // Return results
  266. return append(txHistory, newTxs), append(estimateHistory, estimates)
  267. }
  268. // TestEstimateFeeRollback tests the rollback function, which undoes the
  269. // effect of a adding a new block.
  270. func TestEstimateFeeRollback(t *testing.T) {
  271. txPerRound := uint32(7)
  272. txPerBlock := uint32(5)
  273. binSize := uint32(6)
  274. maxReplacements := uint32(4)
  275. stepsBack := 2
  276. rounds := 30
  277. eft := estimateFeeTester{ef: newTestFeeEstimator(binSize, maxReplacements, uint32(stepsBack)), t: t}
  278. var txHistory [][]*TxDesc
  279. estimateHistory := [][estimateFeeDepth]BtcPerKilobyte{eft.estimates()}
  280. for round := 0; round < rounds; round++ {
  281. // Go forward a few rounds.
  282. for step := 0; step <= stepsBack; step++ {
  283. txHistory, estimateHistory =
  284. eft.round(txHistory, estimateHistory, txPerRound, txPerBlock)
  285. }
  286. // Now go back.
  287. for step := 0; step < stepsBack; step++ {
  288. eft.rollback()
  289. // After rolling back, we should have the same estimated
  290. // fees as before.
  291. expected := estimateHistory[len(estimateHistory)-step-2]
  292. estimates := eft.estimates()
  293. // Ensure that these are both the same.
  294. for i := 0; i < estimateFeeDepth; i++ {
  295. if expected[i] != estimates[i] {
  296. t.Errorf("Rollback value mismatch. Expected %f, got %f. ",
  297. expected[i], estimates[i])
  298. return
  299. }
  300. }
  301. }
  302. // Erase history.
  303. txHistory = txHistory[0 : len(txHistory)-stepsBack]
  304. estimateHistory = estimateHistory[0 : len(estimateHistory)-stepsBack]
  305. }
  306. }
  307. func (eft *estimateFeeTester) checkSaveAndRestore(
  308. previousEstimates [estimateFeeDepth]BtcPerKilobyte) {
  309. // Get the save state.
  310. save := eft.ef.Save()
  311. // Save and restore database.
  312. var err er.R
  313. eft.ef, err = RestoreFeeEstimator(save)
  314. if err != nil {
  315. eft.t.Fatalf("Could not restore database: %s", err)
  316. }
  317. // Save again and check that it matches the previous one.
  318. redo := eft.ef.Save()
  319. if !bytes.Equal(save, redo) {
  320. eft.t.Fatalf("Restored states do not match: %v %v", save, redo)
  321. }
  322. // Check that the results match.
  323. newEstimates := eft.estimates()
  324. for i, prev := range previousEstimates {
  325. if prev != newEstimates[i] {
  326. eft.t.Error("Mismatch in estimate ", i, " after restore; got ", newEstimates[i], " but expected ", prev)
  327. }
  328. }
  329. }
  330. // TestSave tests saving and restoring to a []byte.
  331. func TestDatabase(t *testing.T) {
  332. txPerRound := uint32(7)
  333. txPerBlock := uint32(5)
  334. binSize := uint32(6)
  335. maxReplacements := uint32(4)
  336. rounds := 8
  337. eft := estimateFeeTester{ef: newTestFeeEstimator(binSize, maxReplacements, uint32(rounds)+1), t: t}
  338. var txHistory [][]*TxDesc
  339. estimateHistory := [][estimateFeeDepth]BtcPerKilobyte{eft.estimates()}
  340. for round := 0; round < rounds; round++ {
  341. eft.checkSaveAndRestore(estimateHistory[len(estimateHistory)-1])
  342. // Go forward one step.
  343. txHistory, estimateHistory =
  344. eft.round(txHistory, estimateHistory, txPerRound, txPerBlock)
  345. }
  346. // Reverse the process and try again.
  347. for round := 1; round <= rounds; round++ {
  348. eft.rollback()
  349. eft.checkSaveAndRestore(estimateHistory[len(estimateHistory)-round-1])
  350. }
  351. }