disklayer_test.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. // Copyright 2019 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 snapshot
  17. import (
  18. "bytes"
  19. "testing"
  20. "github.com/VictoriaMetrics/fastcache"
  21. "github.com/ethereum/go-ethereum/common"
  22. "github.com/ethereum/go-ethereum/core/rawdb"
  23. "github.com/ethereum/go-ethereum/ethdb/memorydb"
  24. "github.com/ethereum/go-ethereum/rlp"
  25. )
  26. // reverse reverses the contents of a byte slice. It's used to update random accs
  27. // with deterministic changes.
  28. func reverse(blob []byte) []byte {
  29. res := make([]byte, len(blob))
  30. for i, b := range blob {
  31. res[len(blob)-1-i] = b
  32. }
  33. return res
  34. }
  35. // Tests that merging something into a disk layer persists it into the database
  36. // and invalidates any previously written and cached values.
  37. func TestDiskMerge(t *testing.T) {
  38. // Create some accounts in the disk layer
  39. db := memorydb.New()
  40. var (
  41. accNoModNoCache = common.Hash{0x1}
  42. accNoModCache = common.Hash{0x2}
  43. accModNoCache = common.Hash{0x3}
  44. accModCache = common.Hash{0x4}
  45. accDelNoCache = common.Hash{0x5}
  46. accDelCache = common.Hash{0x6}
  47. conNoModNoCache = common.Hash{0x7}
  48. conNoModNoCacheSlot = common.Hash{0x70}
  49. conNoModCache = common.Hash{0x8}
  50. conNoModCacheSlot = common.Hash{0x80}
  51. conModNoCache = common.Hash{0x9}
  52. conModNoCacheSlot = common.Hash{0x90}
  53. conModCache = common.Hash{0xa}
  54. conModCacheSlot = common.Hash{0xa0}
  55. conDelNoCache = common.Hash{0xb}
  56. conDelNoCacheSlot = common.Hash{0xb0}
  57. conDelCache = common.Hash{0xc}
  58. conDelCacheSlot = common.Hash{0xc0}
  59. conNukeNoCache = common.Hash{0xd}
  60. conNukeNoCacheSlot = common.Hash{0xd0}
  61. conNukeCache = common.Hash{0xe}
  62. conNukeCacheSlot = common.Hash{0xe0}
  63. baseRoot = randomHash()
  64. diffRoot = randomHash()
  65. )
  66. rawdb.WriteAccountSnapshot(db, accNoModNoCache, accNoModNoCache[:])
  67. rawdb.WriteAccountSnapshot(db, accNoModCache, accNoModCache[:])
  68. rawdb.WriteAccountSnapshot(db, accModNoCache, accModNoCache[:])
  69. rawdb.WriteAccountSnapshot(db, accModCache, accModCache[:])
  70. rawdb.WriteAccountSnapshot(db, accDelNoCache, accDelNoCache[:])
  71. rawdb.WriteAccountSnapshot(db, accDelCache, accDelCache[:])
  72. rawdb.WriteAccountSnapshot(db, conNoModNoCache, conNoModNoCache[:])
  73. rawdb.WriteStorageSnapshot(db, conNoModNoCache, conNoModNoCacheSlot, conNoModNoCacheSlot[:])
  74. rawdb.WriteAccountSnapshot(db, conNoModCache, conNoModCache[:])
  75. rawdb.WriteStorageSnapshot(db, conNoModCache, conNoModCacheSlot, conNoModCacheSlot[:])
  76. rawdb.WriteAccountSnapshot(db, conModNoCache, conModNoCache[:])
  77. rawdb.WriteStorageSnapshot(db, conModNoCache, conModNoCacheSlot, conModNoCacheSlot[:])
  78. rawdb.WriteAccountSnapshot(db, conModCache, conModCache[:])
  79. rawdb.WriteStorageSnapshot(db, conModCache, conModCacheSlot, conModCacheSlot[:])
  80. rawdb.WriteAccountSnapshot(db, conDelNoCache, conDelNoCache[:])
  81. rawdb.WriteStorageSnapshot(db, conDelNoCache, conDelNoCacheSlot, conDelNoCacheSlot[:])
  82. rawdb.WriteAccountSnapshot(db, conDelCache, conDelCache[:])
  83. rawdb.WriteStorageSnapshot(db, conDelCache, conDelCacheSlot, conDelCacheSlot[:])
  84. rawdb.WriteAccountSnapshot(db, conNukeNoCache, conNukeNoCache[:])
  85. rawdb.WriteStorageSnapshot(db, conNukeNoCache, conNukeNoCacheSlot, conNukeNoCacheSlot[:])
  86. rawdb.WriteAccountSnapshot(db, conNukeCache, conNukeCache[:])
  87. rawdb.WriteStorageSnapshot(db, conNukeCache, conNukeCacheSlot, conNukeCacheSlot[:])
  88. rawdb.WriteSnapshotRoot(db, baseRoot)
  89. // Create a disk layer based on the above and cache in some data
  90. snaps := &Tree{
  91. layers: map[common.Hash]snapshot{
  92. baseRoot: &diskLayer{
  93. diskdb: db,
  94. cache: fastcache.New(500 * 1024),
  95. root: baseRoot,
  96. },
  97. },
  98. }
  99. base := snaps.Snapshot(baseRoot)
  100. base.AccountRLP(accNoModCache)
  101. base.AccountRLP(accModCache)
  102. base.AccountRLP(accDelCache)
  103. base.Storage(conNoModCache, conNoModCacheSlot)
  104. base.Storage(conModCache, conModCacheSlot)
  105. base.Storage(conDelCache, conDelCacheSlot)
  106. base.Storage(conNukeCache, conNukeCacheSlot)
  107. // Modify or delete some accounts, flatten everything onto disk
  108. if err := snaps.Update(diffRoot, baseRoot, map[common.Hash]struct{}{
  109. accDelNoCache: {},
  110. accDelCache: {},
  111. conNukeNoCache: {},
  112. conNukeCache: {},
  113. }, map[common.Hash][]byte{
  114. accModNoCache: reverse(accModNoCache[:]),
  115. accModCache: reverse(accModCache[:]),
  116. }, map[common.Hash]map[common.Hash][]byte{
  117. conModNoCache: {conModNoCacheSlot: reverse(conModNoCacheSlot[:])},
  118. conModCache: {conModCacheSlot: reverse(conModCacheSlot[:])},
  119. conDelNoCache: {conDelNoCacheSlot: nil},
  120. conDelCache: {conDelCacheSlot: nil},
  121. }); err != nil {
  122. t.Fatalf("failed to update snapshot tree: %v", err)
  123. }
  124. if err := snaps.Cap(diffRoot, 0); err != nil {
  125. t.Fatalf("failed to flatten snapshot tree: %v", err)
  126. }
  127. // Retrieve all the data through the disk layer and validate it
  128. base = snaps.Snapshot(diffRoot)
  129. if _, ok := base.(*diskLayer); !ok {
  130. t.Fatalf("update not flattend into the disk layer")
  131. }
  132. // assertAccount ensures that an account matches the given blob.
  133. assertAccount := func(account common.Hash, data []byte) {
  134. t.Helper()
  135. blob, err := base.AccountRLP(account)
  136. if err != nil {
  137. t.Errorf("account access (%x) failed: %v", account, err)
  138. } else if !bytes.Equal(blob, data) {
  139. t.Errorf("account access (%x) mismatch: have %x, want %x", account, blob, data)
  140. }
  141. }
  142. assertAccount(accNoModNoCache, accNoModNoCache[:])
  143. assertAccount(accNoModCache, accNoModCache[:])
  144. assertAccount(accModNoCache, reverse(accModNoCache[:]))
  145. assertAccount(accModCache, reverse(accModCache[:]))
  146. assertAccount(accDelNoCache, nil)
  147. assertAccount(accDelCache, nil)
  148. // assertStorage ensures that a storage slot matches the given blob.
  149. assertStorage := func(account common.Hash, slot common.Hash, data []byte) {
  150. t.Helper()
  151. blob, err := base.Storage(account, slot)
  152. if err != nil {
  153. t.Errorf("storage access (%x:%x) failed: %v", account, slot, err)
  154. } else if !bytes.Equal(blob, data) {
  155. t.Errorf("storage access (%x:%x) mismatch: have %x, want %x", account, slot, blob, data)
  156. }
  157. }
  158. assertStorage(conNoModNoCache, conNoModNoCacheSlot, conNoModNoCacheSlot[:])
  159. assertStorage(conNoModCache, conNoModCacheSlot, conNoModCacheSlot[:])
  160. assertStorage(conModNoCache, conModNoCacheSlot, reverse(conModNoCacheSlot[:]))
  161. assertStorage(conModCache, conModCacheSlot, reverse(conModCacheSlot[:]))
  162. assertStorage(conDelNoCache, conDelNoCacheSlot, nil)
  163. assertStorage(conDelCache, conDelCacheSlot, nil)
  164. assertStorage(conNukeNoCache, conNukeNoCacheSlot, nil)
  165. assertStorage(conNukeCache, conNukeCacheSlot, nil)
  166. // Retrieve all the data directly from the database and validate it
  167. // assertDatabaseAccount ensures that an account from the database matches the given blob.
  168. assertDatabaseAccount := func(account common.Hash, data []byte) {
  169. t.Helper()
  170. if blob := rawdb.ReadAccountSnapshot(db, account); !bytes.Equal(blob, data) {
  171. t.Errorf("account database access (%x) mismatch: have %x, want %x", account, blob, data)
  172. }
  173. }
  174. assertDatabaseAccount(accNoModNoCache, accNoModNoCache[:])
  175. assertDatabaseAccount(accNoModCache, accNoModCache[:])
  176. assertDatabaseAccount(accModNoCache, reverse(accModNoCache[:]))
  177. assertDatabaseAccount(accModCache, reverse(accModCache[:]))
  178. assertDatabaseAccount(accDelNoCache, nil)
  179. assertDatabaseAccount(accDelCache, nil)
  180. // assertDatabaseStorage ensures that a storage slot from the database matches the given blob.
  181. assertDatabaseStorage := func(account common.Hash, slot common.Hash, data []byte) {
  182. t.Helper()
  183. if blob := rawdb.ReadStorageSnapshot(db, account, slot); !bytes.Equal(blob, data) {
  184. t.Errorf("storage database access (%x:%x) mismatch: have %x, want %x", account, slot, blob, data)
  185. }
  186. }
  187. assertDatabaseStorage(conNoModNoCache, conNoModNoCacheSlot, conNoModNoCacheSlot[:])
  188. assertDatabaseStorage(conNoModCache, conNoModCacheSlot, conNoModCacheSlot[:])
  189. assertDatabaseStorage(conModNoCache, conModNoCacheSlot, reverse(conModNoCacheSlot[:]))
  190. assertDatabaseStorage(conModCache, conModCacheSlot, reverse(conModCacheSlot[:]))
  191. assertDatabaseStorage(conDelNoCache, conDelNoCacheSlot, nil)
  192. assertDatabaseStorage(conDelCache, conDelCacheSlot, nil)
  193. assertDatabaseStorage(conNukeNoCache, conNukeNoCacheSlot, nil)
  194. assertDatabaseStorage(conNukeCache, conNukeCacheSlot, nil)
  195. }
  196. // Tests that merging something into a disk layer persists it into the database
  197. // and invalidates any previously written and cached values, discarding anything
  198. // after the in-progress generation marker.
  199. func TestDiskPartialMerge(t *testing.T) {
  200. // Iterate the test a few times to ensure we pick various internal orderings
  201. // for the data slots as well as the progress marker.
  202. for i := 0; i < 1024; i++ {
  203. // Create some accounts in the disk layer
  204. db := memorydb.New()
  205. var (
  206. accNoModNoCache = randomHash()
  207. accNoModCache = randomHash()
  208. accModNoCache = randomHash()
  209. accModCache = randomHash()
  210. accDelNoCache = randomHash()
  211. accDelCache = randomHash()
  212. conNoModNoCache = randomHash()
  213. conNoModNoCacheSlot = randomHash()
  214. conNoModCache = randomHash()
  215. conNoModCacheSlot = randomHash()
  216. conModNoCache = randomHash()
  217. conModNoCacheSlot = randomHash()
  218. conModCache = randomHash()
  219. conModCacheSlot = randomHash()
  220. conDelNoCache = randomHash()
  221. conDelNoCacheSlot = randomHash()
  222. conDelCache = randomHash()
  223. conDelCacheSlot = randomHash()
  224. conNukeNoCache = randomHash()
  225. conNukeNoCacheSlot = randomHash()
  226. conNukeCache = randomHash()
  227. conNukeCacheSlot = randomHash()
  228. baseRoot = randomHash()
  229. diffRoot = randomHash()
  230. genMarker = append(randomHash().Bytes(), randomHash().Bytes()...)
  231. )
  232. // insertAccount injects an account into the database if it's after the
  233. // generator marker, drops the op otherwise. This is needed to seed the
  234. // database with a valid starting snapshot.
  235. insertAccount := func(account common.Hash, data []byte) {
  236. if bytes.Compare(account[:], genMarker) <= 0 {
  237. rawdb.WriteAccountSnapshot(db, account, data[:])
  238. }
  239. }
  240. insertAccount(accNoModNoCache, accNoModNoCache[:])
  241. insertAccount(accNoModCache, accNoModCache[:])
  242. insertAccount(accModNoCache, accModNoCache[:])
  243. insertAccount(accModCache, accModCache[:])
  244. insertAccount(accDelNoCache, accDelNoCache[:])
  245. insertAccount(accDelCache, accDelCache[:])
  246. // insertStorage injects a storage slot into the database if it's after
  247. // the generator marker, drops the op otherwise. This is needed to seed
  248. // the database with a valid starting snapshot.
  249. insertStorage := func(account common.Hash, slot common.Hash, data []byte) {
  250. if bytes.Compare(append(account[:], slot[:]...), genMarker) <= 0 {
  251. rawdb.WriteStorageSnapshot(db, account, slot, data[:])
  252. }
  253. }
  254. insertAccount(conNoModNoCache, conNoModNoCache[:])
  255. insertStorage(conNoModNoCache, conNoModNoCacheSlot, conNoModNoCacheSlot[:])
  256. insertAccount(conNoModCache, conNoModCache[:])
  257. insertStorage(conNoModCache, conNoModCacheSlot, conNoModCacheSlot[:])
  258. insertAccount(conModNoCache, conModNoCache[:])
  259. insertStorage(conModNoCache, conModNoCacheSlot, conModNoCacheSlot[:])
  260. insertAccount(conModCache, conModCache[:])
  261. insertStorage(conModCache, conModCacheSlot, conModCacheSlot[:])
  262. insertAccount(conDelNoCache, conDelNoCache[:])
  263. insertStorage(conDelNoCache, conDelNoCacheSlot, conDelNoCacheSlot[:])
  264. insertAccount(conDelCache, conDelCache[:])
  265. insertStorage(conDelCache, conDelCacheSlot, conDelCacheSlot[:])
  266. insertAccount(conNukeNoCache, conNukeNoCache[:])
  267. insertStorage(conNukeNoCache, conNukeNoCacheSlot, conNukeNoCacheSlot[:])
  268. insertAccount(conNukeCache, conNukeCache[:])
  269. insertStorage(conNukeCache, conNukeCacheSlot, conNukeCacheSlot[:])
  270. rawdb.WriteSnapshotRoot(db, baseRoot)
  271. // Create a disk layer based on the above using a random progress marker
  272. // and cache in some data.
  273. snaps := &Tree{
  274. layers: map[common.Hash]snapshot{
  275. baseRoot: &diskLayer{
  276. diskdb: db,
  277. cache: fastcache.New(500 * 1024),
  278. root: baseRoot,
  279. },
  280. },
  281. }
  282. snaps.layers[baseRoot].(*diskLayer).genMarker = genMarker
  283. base := snaps.Snapshot(baseRoot)
  284. // assertAccount ensures that an account matches the given blob if it's
  285. // already covered by the disk snapshot, and errors out otherwise.
  286. assertAccount := func(account common.Hash, data []byte) {
  287. t.Helper()
  288. blob, err := base.AccountRLP(account)
  289. if bytes.Compare(account[:], genMarker) > 0 && err != ErrNotCoveredYet {
  290. t.Fatalf("test %d: post-marker (%x) account access (%x) succeeded: %x", i, genMarker, account, blob)
  291. }
  292. if bytes.Compare(account[:], genMarker) <= 0 && !bytes.Equal(blob, data) {
  293. t.Fatalf("test %d: pre-marker (%x) account access (%x) mismatch: have %x, want %x", i, genMarker, account, blob, data)
  294. }
  295. }
  296. assertAccount(accNoModCache, accNoModCache[:])
  297. assertAccount(accModCache, accModCache[:])
  298. assertAccount(accDelCache, accDelCache[:])
  299. // assertStorage ensures that a storage slot matches the given blob if
  300. // it's already covered by the disk snapshot, and errors out otherwise.
  301. assertStorage := func(account common.Hash, slot common.Hash, data []byte) {
  302. t.Helper()
  303. blob, err := base.Storage(account, slot)
  304. if bytes.Compare(append(account[:], slot[:]...), genMarker) > 0 && err != ErrNotCoveredYet {
  305. t.Fatalf("test %d: post-marker (%x) storage access (%x:%x) succeeded: %x", i, genMarker, account, slot, blob)
  306. }
  307. if bytes.Compare(append(account[:], slot[:]...), genMarker) <= 0 && !bytes.Equal(blob, data) {
  308. t.Fatalf("test %d: pre-marker (%x) storage access (%x:%x) mismatch: have %x, want %x", i, genMarker, account, slot, blob, data)
  309. }
  310. }
  311. assertStorage(conNoModCache, conNoModCacheSlot, conNoModCacheSlot[:])
  312. assertStorage(conModCache, conModCacheSlot, conModCacheSlot[:])
  313. assertStorage(conDelCache, conDelCacheSlot, conDelCacheSlot[:])
  314. assertStorage(conNukeCache, conNukeCacheSlot, conNukeCacheSlot[:])
  315. // Modify or delete some accounts, flatten everything onto disk
  316. if err := snaps.Update(diffRoot, baseRoot, map[common.Hash]struct{}{
  317. accDelNoCache: {},
  318. accDelCache: {},
  319. conNukeNoCache: {},
  320. conNukeCache: {},
  321. }, map[common.Hash][]byte{
  322. accModNoCache: reverse(accModNoCache[:]),
  323. accModCache: reverse(accModCache[:]),
  324. }, map[common.Hash]map[common.Hash][]byte{
  325. conModNoCache: {conModNoCacheSlot: reverse(conModNoCacheSlot[:])},
  326. conModCache: {conModCacheSlot: reverse(conModCacheSlot[:])},
  327. conDelNoCache: {conDelNoCacheSlot: nil},
  328. conDelCache: {conDelCacheSlot: nil},
  329. }); err != nil {
  330. t.Fatalf("test %d: failed to update snapshot tree: %v", i, err)
  331. }
  332. if err := snaps.Cap(diffRoot, 0); err != nil {
  333. t.Fatalf("test %d: failed to flatten snapshot tree: %v", i, err)
  334. }
  335. // Retrieve all the data through the disk layer and validate it
  336. base = snaps.Snapshot(diffRoot)
  337. if _, ok := base.(*diskLayer); !ok {
  338. t.Fatalf("test %d: update not flattend into the disk layer", i)
  339. }
  340. assertAccount(accNoModNoCache, accNoModNoCache[:])
  341. assertAccount(accNoModCache, accNoModCache[:])
  342. assertAccount(accModNoCache, reverse(accModNoCache[:]))
  343. assertAccount(accModCache, reverse(accModCache[:]))
  344. assertAccount(accDelNoCache, nil)
  345. assertAccount(accDelCache, nil)
  346. assertStorage(conNoModNoCache, conNoModNoCacheSlot, conNoModNoCacheSlot[:])
  347. assertStorage(conNoModCache, conNoModCacheSlot, conNoModCacheSlot[:])
  348. assertStorage(conModNoCache, conModNoCacheSlot, reverse(conModNoCacheSlot[:]))
  349. assertStorage(conModCache, conModCacheSlot, reverse(conModCacheSlot[:]))
  350. assertStorage(conDelNoCache, conDelNoCacheSlot, nil)
  351. assertStorage(conDelCache, conDelCacheSlot, nil)
  352. assertStorage(conNukeNoCache, conNukeNoCacheSlot, nil)
  353. assertStorage(conNukeCache, conNukeCacheSlot, nil)
  354. // Retrieve all the data directly from the database and validate it
  355. // assertDatabaseAccount ensures that an account inside the database matches
  356. // the given blob if it's already covered by the disk snapshot, and does not
  357. // exist otherwise.
  358. assertDatabaseAccount := func(account common.Hash, data []byte) {
  359. t.Helper()
  360. blob := rawdb.ReadAccountSnapshot(db, account)
  361. if bytes.Compare(account[:], genMarker) > 0 && blob != nil {
  362. t.Fatalf("test %d: post-marker (%x) account database access (%x) succeeded: %x", i, genMarker, account, blob)
  363. }
  364. if bytes.Compare(account[:], genMarker) <= 0 && !bytes.Equal(blob, data) {
  365. t.Fatalf("test %d: pre-marker (%x) account database access (%x) mismatch: have %x, want %x", i, genMarker, account, blob, data)
  366. }
  367. }
  368. assertDatabaseAccount(accNoModNoCache, accNoModNoCache[:])
  369. assertDatabaseAccount(accNoModCache, accNoModCache[:])
  370. assertDatabaseAccount(accModNoCache, reverse(accModNoCache[:]))
  371. assertDatabaseAccount(accModCache, reverse(accModCache[:]))
  372. assertDatabaseAccount(accDelNoCache, nil)
  373. assertDatabaseAccount(accDelCache, nil)
  374. // assertDatabaseStorage ensures that a storage slot inside the database
  375. // matches the given blob if it's already covered by the disk snapshot,
  376. // and does not exist otherwise.
  377. assertDatabaseStorage := func(account common.Hash, slot common.Hash, data []byte) {
  378. t.Helper()
  379. blob := rawdb.ReadStorageSnapshot(db, account, slot)
  380. if bytes.Compare(append(account[:], slot[:]...), genMarker) > 0 && blob != nil {
  381. t.Fatalf("test %d: post-marker (%x) storage database access (%x:%x) succeeded: %x", i, genMarker, account, slot, blob)
  382. }
  383. if bytes.Compare(append(account[:], slot[:]...), genMarker) <= 0 && !bytes.Equal(blob, data) {
  384. t.Fatalf("test %d: pre-marker (%x) storage database access (%x:%x) mismatch: have %x, want %x", i, genMarker, account, slot, blob, data)
  385. }
  386. }
  387. assertDatabaseStorage(conNoModNoCache, conNoModNoCacheSlot, conNoModNoCacheSlot[:])
  388. assertDatabaseStorage(conNoModCache, conNoModCacheSlot, conNoModCacheSlot[:])
  389. assertDatabaseStorage(conModNoCache, conModNoCacheSlot, reverse(conModNoCacheSlot[:]))
  390. assertDatabaseStorage(conModCache, conModCacheSlot, reverse(conModCacheSlot[:]))
  391. assertDatabaseStorage(conDelNoCache, conDelNoCacheSlot, nil)
  392. assertDatabaseStorage(conDelCache, conDelCacheSlot, nil)
  393. assertDatabaseStorage(conNukeNoCache, conNukeNoCacheSlot, nil)
  394. assertDatabaseStorage(conNukeCache, conNukeCacheSlot, nil)
  395. }
  396. }
  397. // Tests that when the bottom-most diff layer is merged into the disk
  398. // layer whether the corresponding generator is persisted correctly.
  399. func TestDiskGeneratorPersistence(t *testing.T) {
  400. var (
  401. accOne = randomHash()
  402. accTwo = randomHash()
  403. accOneSlotOne = randomHash()
  404. accOneSlotTwo = randomHash()
  405. accThree = randomHash()
  406. accThreeSlot = randomHash()
  407. baseRoot = randomHash()
  408. diffRoot = randomHash()
  409. diffTwoRoot = randomHash()
  410. genMarker = append(randomHash().Bytes(), randomHash().Bytes()...)
  411. )
  412. // Testing scenario 1, the disk layer is still under the construction.
  413. db := rawdb.NewMemoryDatabase()
  414. rawdb.WriteAccountSnapshot(db, accOne, accOne[:])
  415. rawdb.WriteStorageSnapshot(db, accOne, accOneSlotOne, accOneSlotOne[:])
  416. rawdb.WriteStorageSnapshot(db, accOne, accOneSlotTwo, accOneSlotTwo[:])
  417. rawdb.WriteSnapshotRoot(db, baseRoot)
  418. // Create a disk layer based on all above updates
  419. snaps := &Tree{
  420. layers: map[common.Hash]snapshot{
  421. baseRoot: &diskLayer{
  422. diskdb: db,
  423. cache: fastcache.New(500 * 1024),
  424. root: baseRoot,
  425. genMarker: genMarker,
  426. },
  427. },
  428. }
  429. // Modify or delete some accounts, flatten everything onto disk
  430. if err := snaps.Update(diffRoot, baseRoot, nil, map[common.Hash][]byte{
  431. accTwo: accTwo[:],
  432. }, nil); err != nil {
  433. t.Fatalf("failed to update snapshot tree: %v", err)
  434. }
  435. if err := snaps.Cap(diffRoot, 0); err != nil {
  436. t.Fatalf("failed to flatten snapshot tree: %v", err)
  437. }
  438. blob := rawdb.ReadSnapshotGenerator(db)
  439. var generator journalGenerator
  440. if err := rlp.DecodeBytes(blob, &generator); err != nil {
  441. t.Fatalf("Failed to decode snapshot generator %v", err)
  442. }
  443. if !bytes.Equal(generator.Marker, genMarker) {
  444. t.Fatalf("Generator marker is not matched")
  445. }
  446. // Test scenario 2, the disk layer is fully generated
  447. // Modify or delete some accounts, flatten everything onto disk
  448. if err := snaps.Update(diffTwoRoot, diffRoot, nil, map[common.Hash][]byte{
  449. accThree: accThree.Bytes(),
  450. }, map[common.Hash]map[common.Hash][]byte{
  451. accThree: {accThreeSlot: accThreeSlot.Bytes()},
  452. }); err != nil {
  453. t.Fatalf("failed to update snapshot tree: %v", err)
  454. }
  455. diskLayer := snaps.layers[snaps.diskRoot()].(*diskLayer)
  456. diskLayer.genMarker = nil // Construction finished
  457. if err := snaps.Cap(diffTwoRoot, 0); err != nil {
  458. t.Fatalf("failed to flatten snapshot tree: %v", err)
  459. }
  460. blob = rawdb.ReadSnapshotGenerator(db)
  461. if err := rlp.DecodeBytes(blob, &generator); err != nil {
  462. t.Fatalf("Failed to decode snapshot generator %v", err)
  463. }
  464. if len(generator.Marker) != 0 {
  465. t.Fatalf("Failed to update snapshot generator")
  466. }
  467. }
  468. // Tests that merging something into a disk layer persists it into the database
  469. // and invalidates any previously written and cached values, discarding anything
  470. // after the in-progress generation marker.
  471. //
  472. // This test case is a tiny specialized case of TestDiskPartialMerge, which tests
  473. // some very specific cornercases that random tests won't ever trigger.
  474. func TestDiskMidAccountPartialMerge(t *testing.T) {
  475. // TODO(@karalabe) ?
  476. }
  477. // TestDiskSeek tests that seek-operations work on the disk layer
  478. func TestDiskSeek(t *testing.T) {
  479. // Create some accounts in the disk layer
  480. db := rawdb.NewMemoryDatabase()
  481. defer db.Close()
  482. // Fill even keys [0,2,4...]
  483. for i := 0; i < 0xff; i += 2 {
  484. acc := common.Hash{byte(i)}
  485. rawdb.WriteAccountSnapshot(db, acc, acc[:])
  486. }
  487. // Add an 'higher' key, with incorrect (higher) prefix
  488. highKey := []byte{rawdb.SnapshotAccountPrefix[0] + 1}
  489. db.Put(highKey, []byte{0xff, 0xff})
  490. baseRoot := randomHash()
  491. rawdb.WriteSnapshotRoot(db, baseRoot)
  492. snaps := &Tree{
  493. layers: map[common.Hash]snapshot{
  494. baseRoot: &diskLayer{
  495. diskdb: db,
  496. cache: fastcache.New(500 * 1024),
  497. root: baseRoot,
  498. },
  499. },
  500. }
  501. // Test some different seek positions
  502. type testcase struct {
  503. pos byte
  504. expkey byte
  505. }
  506. var cases = []testcase{
  507. {0xff, 0x55}, // this should exit immediately without checking key
  508. {0x01, 0x02},
  509. {0xfe, 0xfe},
  510. {0xfd, 0xfe},
  511. {0x00, 0x00},
  512. }
  513. for i, tc := range cases {
  514. it, err := snaps.AccountIterator(baseRoot, common.Hash{tc.pos})
  515. if err != nil {
  516. t.Fatalf("case %d, error: %v", i, err)
  517. }
  518. count := 0
  519. for it.Next() {
  520. k, v, err := it.Hash()[0], it.Account()[0], it.Error()
  521. if err != nil {
  522. t.Fatalf("test %d, item %d, error: %v", i, count, err)
  523. }
  524. // First item in iterator should have the expected key
  525. if count == 0 && k != tc.expkey {
  526. t.Fatalf("test %d, item %d, got %v exp %v", i, count, k, tc.expkey)
  527. }
  528. count++
  529. if v != k {
  530. t.Fatalf("test %d, item %d, value wrong, got %v exp %v", i, count, v, k)
  531. }
  532. }
  533. }
  534. }