disklayer_test.go 24 KB

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