database_util_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. // Copyright 2015 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. package core
  17. import (
  18. "bytes"
  19. "math/big"
  20. "testing"
  21. "github.com/ethereum/go-ethereum/common"
  22. "github.com/ethereum/go-ethereum/core/types"
  23. "github.com/ethereum/go-ethereum/crypto/sha3"
  24. "github.com/ethereum/go-ethereum/ethdb"
  25. "github.com/ethereum/go-ethereum/rlp"
  26. )
  27. // Tests block header storage and retrieval operations.
  28. func TestHeaderStorage(t *testing.T) {
  29. db, _ := ethdb.NewMemDatabase()
  30. // Create a test header to move around the database and make sure it's really new
  31. header := &types.Header{Number: big.NewInt(42), Extra: []byte("test header")}
  32. if entry := GetHeader(db, header.Hash(), header.Number.Uint64()); entry != nil {
  33. t.Fatalf("Non existent header returned: %v", entry)
  34. }
  35. // Write and verify the header in the database
  36. if err := WriteHeader(db, header); err != nil {
  37. t.Fatalf("Failed to write header into database: %v", err)
  38. }
  39. if entry := GetHeader(db, header.Hash(), header.Number.Uint64()); entry == nil {
  40. t.Fatalf("Stored header not found")
  41. } else if entry.Hash() != header.Hash() {
  42. t.Fatalf("Retrieved header mismatch: have %v, want %v", entry, header)
  43. }
  44. if entry := GetHeaderRLP(db, header.Hash(), header.Number.Uint64()); entry == nil {
  45. t.Fatalf("Stored header RLP not found")
  46. } else {
  47. hasher := sha3.NewKeccak256()
  48. hasher.Write(entry)
  49. if hash := common.BytesToHash(hasher.Sum(nil)); hash != header.Hash() {
  50. t.Fatalf("Retrieved RLP header mismatch: have %v, want %v", entry, header)
  51. }
  52. }
  53. // Delete the header and verify the execution
  54. DeleteHeader(db, header.Hash(), header.Number.Uint64())
  55. if entry := GetHeader(db, header.Hash(), header.Number.Uint64()); entry != nil {
  56. t.Fatalf("Deleted header returned: %v", entry)
  57. }
  58. }
  59. // Tests block body storage and retrieval operations.
  60. func TestBodyStorage(t *testing.T) {
  61. db, _ := ethdb.NewMemDatabase()
  62. // Create a test body to move around the database and make sure it's really new
  63. body := &types.Body{Uncles: []*types.Header{{Extra: []byte("test header")}}}
  64. hasher := sha3.NewKeccak256()
  65. rlp.Encode(hasher, body)
  66. hash := common.BytesToHash(hasher.Sum(nil))
  67. if entry := GetBody(db, hash, 0); entry != nil {
  68. t.Fatalf("Non existent body returned: %v", entry)
  69. }
  70. // Write and verify the body in the database
  71. if err := WriteBody(db, hash, 0, body); err != nil {
  72. t.Fatalf("Failed to write body into database: %v", err)
  73. }
  74. if entry := GetBody(db, hash, 0); entry == nil {
  75. t.Fatalf("Stored body not found")
  76. } else if types.DeriveSha(types.Transactions(entry.Transactions)) != types.DeriveSha(types.Transactions(body.Transactions)) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(body.Uncles) {
  77. t.Fatalf("Retrieved body mismatch: have %v, want %v", entry, body)
  78. }
  79. if entry := GetBodyRLP(db, hash, 0); entry == nil {
  80. t.Fatalf("Stored body RLP not found")
  81. } else {
  82. hasher := sha3.NewKeccak256()
  83. hasher.Write(entry)
  84. if calc := common.BytesToHash(hasher.Sum(nil)); calc != hash {
  85. t.Fatalf("Retrieved RLP body mismatch: have %v, want %v", entry, body)
  86. }
  87. }
  88. // Delete the body and verify the execution
  89. DeleteBody(db, hash, 0)
  90. if entry := GetBody(db, hash, 0); entry != nil {
  91. t.Fatalf("Deleted body returned: %v", entry)
  92. }
  93. }
  94. // Tests block storage and retrieval operations.
  95. func TestBlockStorage(t *testing.T) {
  96. db, _ := ethdb.NewMemDatabase()
  97. // Create a test block to move around the database and make sure it's really new
  98. block := types.NewBlockWithHeader(&types.Header{
  99. Extra: []byte("test block"),
  100. UncleHash: types.EmptyUncleHash,
  101. TxHash: types.EmptyRootHash,
  102. ReceiptHash: types.EmptyRootHash,
  103. })
  104. if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry != nil {
  105. t.Fatalf("Non existent block returned: %v", entry)
  106. }
  107. if entry := GetHeader(db, block.Hash(), block.NumberU64()); entry != nil {
  108. t.Fatalf("Non existent header returned: %v", entry)
  109. }
  110. if entry := GetBody(db, block.Hash(), block.NumberU64()); entry != nil {
  111. t.Fatalf("Non existent body returned: %v", entry)
  112. }
  113. // Write and verify the block in the database
  114. if err := WriteBlock(db, block); err != nil {
  115. t.Fatalf("Failed to write block into database: %v", err)
  116. }
  117. if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry == nil {
  118. t.Fatalf("Stored block not found")
  119. } else if entry.Hash() != block.Hash() {
  120. t.Fatalf("Retrieved block mismatch: have %v, want %v", entry, block)
  121. }
  122. if entry := GetHeader(db, block.Hash(), block.NumberU64()); entry == nil {
  123. t.Fatalf("Stored header not found")
  124. } else if entry.Hash() != block.Header().Hash() {
  125. t.Fatalf("Retrieved header mismatch: have %v, want %v", entry, block.Header())
  126. }
  127. if entry := GetBody(db, block.Hash(), block.NumberU64()); entry == nil {
  128. t.Fatalf("Stored body not found")
  129. } else if types.DeriveSha(types.Transactions(entry.Transactions)) != types.DeriveSha(block.Transactions()) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(block.Uncles()) {
  130. t.Fatalf("Retrieved body mismatch: have %v, want %v", entry, block.Body())
  131. }
  132. // Delete the block and verify the execution
  133. DeleteBlock(db, block.Hash(), block.NumberU64())
  134. if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry != nil {
  135. t.Fatalf("Deleted block returned: %v", entry)
  136. }
  137. if entry := GetHeader(db, block.Hash(), block.NumberU64()); entry != nil {
  138. t.Fatalf("Deleted header returned: %v", entry)
  139. }
  140. if entry := GetBody(db, block.Hash(), block.NumberU64()); entry != nil {
  141. t.Fatalf("Deleted body returned: %v", entry)
  142. }
  143. }
  144. // Tests that partial block contents don't get reassembled into full blocks.
  145. func TestPartialBlockStorage(t *testing.T) {
  146. db, _ := ethdb.NewMemDatabase()
  147. block := types.NewBlockWithHeader(&types.Header{
  148. Extra: []byte("test block"),
  149. UncleHash: types.EmptyUncleHash,
  150. TxHash: types.EmptyRootHash,
  151. ReceiptHash: types.EmptyRootHash,
  152. })
  153. // Store a header and check that it's not recognized as a block
  154. if err := WriteHeader(db, block.Header()); err != nil {
  155. t.Fatalf("Failed to write header into database: %v", err)
  156. }
  157. if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry != nil {
  158. t.Fatalf("Non existent block returned: %v", entry)
  159. }
  160. DeleteHeader(db, block.Hash(), block.NumberU64())
  161. // Store a body and check that it's not recognized as a block
  162. if err := WriteBody(db, block.Hash(), block.NumberU64(), block.Body()); err != nil {
  163. t.Fatalf("Failed to write body into database: %v", err)
  164. }
  165. if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry != nil {
  166. t.Fatalf("Non existent block returned: %v", entry)
  167. }
  168. DeleteBody(db, block.Hash(), block.NumberU64())
  169. // Store a header and a body separately and check reassembly
  170. if err := WriteHeader(db, block.Header()); err != nil {
  171. t.Fatalf("Failed to write header into database: %v", err)
  172. }
  173. if err := WriteBody(db, block.Hash(), block.NumberU64(), block.Body()); err != nil {
  174. t.Fatalf("Failed to write body into database: %v", err)
  175. }
  176. if entry := GetBlock(db, block.Hash(), block.NumberU64()); entry == nil {
  177. t.Fatalf("Stored block not found")
  178. } else if entry.Hash() != block.Hash() {
  179. t.Fatalf("Retrieved block mismatch: have %v, want %v", entry, block)
  180. }
  181. }
  182. // Tests block total difficulty storage and retrieval operations.
  183. func TestTdStorage(t *testing.T) {
  184. db, _ := ethdb.NewMemDatabase()
  185. // Create a test TD to move around the database and make sure it's really new
  186. hash, td := common.Hash{}, big.NewInt(314)
  187. if entry := GetTd(db, hash, 0); entry != nil {
  188. t.Fatalf("Non existent TD returned: %v", entry)
  189. }
  190. // Write and verify the TD in the database
  191. if err := WriteTd(db, hash, 0, td); err != nil {
  192. t.Fatalf("Failed to write TD into database: %v", err)
  193. }
  194. if entry := GetTd(db, hash, 0); entry == nil {
  195. t.Fatalf("Stored TD not found")
  196. } else if entry.Cmp(td) != 0 {
  197. t.Fatalf("Retrieved TD mismatch: have %v, want %v", entry, td)
  198. }
  199. // Delete the TD and verify the execution
  200. DeleteTd(db, hash, 0)
  201. if entry := GetTd(db, hash, 0); entry != nil {
  202. t.Fatalf("Deleted TD returned: %v", entry)
  203. }
  204. }
  205. // Tests that canonical numbers can be mapped to hashes and retrieved.
  206. func TestCanonicalMappingStorage(t *testing.T) {
  207. db, _ := ethdb.NewMemDatabase()
  208. // Create a test canonical number and assinged hash to move around
  209. hash, number := common.Hash{0: 0xff}, uint64(314)
  210. if entry := GetCanonicalHash(db, number); entry != (common.Hash{}) {
  211. t.Fatalf("Non existent canonical mapping returned: %v", entry)
  212. }
  213. // Write and verify the TD in the database
  214. if err := WriteCanonicalHash(db, hash, number); err != nil {
  215. t.Fatalf("Failed to write canonical mapping into database: %v", err)
  216. }
  217. if entry := GetCanonicalHash(db, number); entry == (common.Hash{}) {
  218. t.Fatalf("Stored canonical mapping not found")
  219. } else if entry != hash {
  220. t.Fatalf("Retrieved canonical mapping mismatch: have %v, want %v", entry, hash)
  221. }
  222. // Delete the TD and verify the execution
  223. DeleteCanonicalHash(db, number)
  224. if entry := GetCanonicalHash(db, number); entry != (common.Hash{}) {
  225. t.Fatalf("Deleted canonical mapping returned: %v", entry)
  226. }
  227. }
  228. // Tests that head headers and head blocks can be assigned, individually.
  229. func TestHeadStorage(t *testing.T) {
  230. db, _ := ethdb.NewMemDatabase()
  231. blockHead := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block header")})
  232. blockFull := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block full")})
  233. blockFast := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block fast")})
  234. // Check that no head entries are in a pristine database
  235. if entry := GetHeadHeaderHash(db); entry != (common.Hash{}) {
  236. t.Fatalf("Non head header entry returned: %v", entry)
  237. }
  238. if entry := GetHeadBlockHash(db); entry != (common.Hash{}) {
  239. t.Fatalf("Non head block entry returned: %v", entry)
  240. }
  241. if entry := GetHeadFastBlockHash(db); entry != (common.Hash{}) {
  242. t.Fatalf("Non fast head block entry returned: %v", entry)
  243. }
  244. // Assign separate entries for the head header and block
  245. if err := WriteHeadHeaderHash(db, blockHead.Hash()); err != nil {
  246. t.Fatalf("Failed to write head header hash: %v", err)
  247. }
  248. if err := WriteHeadBlockHash(db, blockFull.Hash()); err != nil {
  249. t.Fatalf("Failed to write head block hash: %v", err)
  250. }
  251. if err := WriteHeadFastBlockHash(db, blockFast.Hash()); err != nil {
  252. t.Fatalf("Failed to write fast head block hash: %v", err)
  253. }
  254. // Check that both heads are present, and different (i.e. two heads maintained)
  255. if entry := GetHeadHeaderHash(db); entry != blockHead.Hash() {
  256. t.Fatalf("Head header hash mismatch: have %v, want %v", entry, blockHead.Hash())
  257. }
  258. if entry := GetHeadBlockHash(db); entry != blockFull.Hash() {
  259. t.Fatalf("Head block hash mismatch: have %v, want %v", entry, blockFull.Hash())
  260. }
  261. if entry := GetHeadFastBlockHash(db); entry != blockFast.Hash() {
  262. t.Fatalf("Fast head block hash mismatch: have %v, want %v", entry, blockFast.Hash())
  263. }
  264. }
  265. // Tests that positional lookup metadata can be stored and retrieved.
  266. func TestLookupStorage(t *testing.T) {
  267. db, _ := ethdb.NewMemDatabase()
  268. tx1 := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), big.NewInt(111), 1111, big.NewInt(11111), []byte{0x11, 0x11, 0x11})
  269. tx2 := types.NewTransaction(2, common.BytesToAddress([]byte{0x22}), big.NewInt(222), 2222, big.NewInt(22222), []byte{0x22, 0x22, 0x22})
  270. tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), big.NewInt(333), 3333, big.NewInt(33333), []byte{0x33, 0x33, 0x33})
  271. txs := []*types.Transaction{tx1, tx2, tx3}
  272. block := types.NewBlock(&types.Header{Number: big.NewInt(314)}, txs, nil, nil)
  273. // Check that no transactions entries are in a pristine database
  274. for i, tx := range txs {
  275. if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn != nil {
  276. t.Fatalf("tx #%d [%x]: non existent transaction returned: %v", i, tx.Hash(), txn)
  277. }
  278. }
  279. // Insert all the transactions into the database, and verify contents
  280. if err := WriteBlock(db, block); err != nil {
  281. t.Fatalf("failed to write block contents: %v", err)
  282. }
  283. if err := WriteTxLookupEntries(db, block); err != nil {
  284. t.Fatalf("failed to write transactions: %v", err)
  285. }
  286. for i, tx := range txs {
  287. if txn, hash, number, index := GetTransaction(db, tx.Hash()); txn == nil {
  288. t.Fatalf("tx #%d [%x]: transaction not found", i, tx.Hash())
  289. } else {
  290. if hash != block.Hash() || number != block.NumberU64() || index != uint64(i) {
  291. t.Fatalf("tx #%d [%x]: positional metadata mismatch: have %x/%d/%d, want %x/%v/%v", i, tx.Hash(), hash, number, index, block.Hash(), block.NumberU64(), i)
  292. }
  293. if tx.String() != txn.String() {
  294. t.Fatalf("tx #%d [%x]: transaction mismatch: have %v, want %v", i, tx.Hash(), txn, tx)
  295. }
  296. }
  297. }
  298. // Delete the transactions and check purge
  299. for i, tx := range txs {
  300. DeleteTxLookupEntry(db, tx.Hash())
  301. if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn != nil {
  302. t.Fatalf("tx #%d [%x]: deleted transaction returned: %v", i, tx.Hash(), txn)
  303. }
  304. }
  305. }
  306. // Tests that receipts associated with a single block can be stored and retrieved.
  307. func TestBlockReceiptStorage(t *testing.T) {
  308. db, _ := ethdb.NewMemDatabase()
  309. receipt1 := &types.Receipt{
  310. Status: types.ReceiptStatusFailed,
  311. CumulativeGasUsed: 1,
  312. Logs: []*types.Log{
  313. {Address: common.BytesToAddress([]byte{0x11})},
  314. {Address: common.BytesToAddress([]byte{0x01, 0x11})},
  315. },
  316. TxHash: common.BytesToHash([]byte{0x11, 0x11}),
  317. ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
  318. GasUsed: 111111,
  319. }
  320. receipt2 := &types.Receipt{
  321. PostState: common.Hash{2}.Bytes(),
  322. CumulativeGasUsed: 2,
  323. Logs: []*types.Log{
  324. {Address: common.BytesToAddress([]byte{0x22})},
  325. {Address: common.BytesToAddress([]byte{0x02, 0x22})},
  326. },
  327. TxHash: common.BytesToHash([]byte{0x22, 0x22}),
  328. ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}),
  329. GasUsed: 222222,
  330. }
  331. receipts := []*types.Receipt{receipt1, receipt2}
  332. // Check that no receipt entries are in a pristine database
  333. hash := common.BytesToHash([]byte{0x03, 0x14})
  334. if rs := GetBlockReceipts(db, hash, 0); len(rs) != 0 {
  335. t.Fatalf("non existent receipts returned: %v", rs)
  336. }
  337. // Insert the receipt slice into the database and check presence
  338. if err := WriteBlockReceipts(db, hash, 0, receipts); err != nil {
  339. t.Fatalf("failed to write block receipts: %v", err)
  340. }
  341. if rs := GetBlockReceipts(db, hash, 0); len(rs) == 0 {
  342. t.Fatalf("no receipts returned")
  343. } else {
  344. for i := 0; i < len(receipts); i++ {
  345. rlpHave, _ := rlp.EncodeToBytes(rs[i])
  346. rlpWant, _ := rlp.EncodeToBytes(receipts[i])
  347. if !bytes.Equal(rlpHave, rlpWant) {
  348. t.Fatalf("receipt #%d: receipt mismatch: have %v, want %v", i, rs[i], receipts[i])
  349. }
  350. }
  351. }
  352. // Delete the receipt slice and check purge
  353. DeleteBlockReceipts(db, hash, 0)
  354. if rs := GetBlockReceipts(db, hash, 0); len(rs) != 0 {
  355. t.Fatalf("deleted receipts returned: %v", rs)
  356. }
  357. }