| 
									
										
										
										
											2019-08-06 13:40:28 +03:00
										 |  |  | // Copyright 2019 The go-ethereum Authors | 
					
						
							|  |  |  | // This file is part of the go-ethereum library. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							|  |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package snapshot | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2019-11-26 09:48:29 +02:00
										 |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2019-10-04 15:24:01 +02:00
										 |  |  | 	"sync" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-25 15:30:29 +01:00
										 |  |  | 	"github.com/VictoriaMetrics/fastcache" | 
					
						
							| 
									
										
										
										
											2019-08-06 13:40:28 +03:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/core/rawdb" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/ethdb" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/rlp" | 
					
						
							| 
									
										
										
										
											2019-11-26 09:48:29 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/trie" | 
					
						
							| 
									
										
										
										
											2019-08-06 13:40:28 +03:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // diskLayer is a low level persistent snapshot built on top of a key-value store. | 
					
						
							|  |  |  | type diskLayer struct { | 
					
						
							| 
									
										
										
										
											2019-11-26 09:48:29 +02:00
										 |  |  | 	diskdb ethdb.KeyValueStore // Key-value store containing the base snapshot | 
					
						
							| 
									
										
										
										
											2021-01-07 15:36:21 +09:00
										 |  |  | 	triedb *trie.Database      // Trie node cache for reconstruction purposes | 
					
						
							| 
									
										
										
										
											2019-11-26 09:48:29 +02:00
										 |  |  | 	cache  *fastcache.Cache    // Cache to avoid hitting the disk for direct access | 
					
						
							| 
									
										
										
										
											2019-08-06 13:40:28 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-22 13:23:49 +02:00
										 |  |  | 	root  common.Hash // Root hash of the base snapshot | 
					
						
							|  |  |  | 	stale bool        // Signals that the layer became stale (state progressed) | 
					
						
							| 
									
										
										
										
											2019-10-04 15:24:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-03 09:10:23 +02:00
										 |  |  | 	genMarker  []byte                    // Marker for the state that's indexed during initial layer generation | 
					
						
							|  |  |  | 	genPending chan struct{}             // Notification channel when generation is done (test synchronicity) | 
					
						
							|  |  |  | 	genAbort   chan chan *generatorStats // Notification channel to abort generating the snapshot in this layer | 
					
						
							| 
									
										
										
										
											2019-11-26 09:48:29 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-04 15:24:01 +02:00
										 |  |  | 	lock sync.RWMutex | 
					
						
							| 
									
										
										
										
											2019-08-06 13:40:28 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-22 13:23:49 +02:00
										 |  |  | // Root returns  root hash for which this snapshot was made. | 
					
						
							|  |  |  | func (dl *diskLayer) Root() common.Hash { | 
					
						
							|  |  |  | 	return dl.root | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-10 11:00:03 +02:00
										 |  |  | // Parent always returns nil as there's no layer below the disk. | 
					
						
							|  |  |  | func (dl *diskLayer) Parent() snapshot { | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-22 13:23:49 +02:00
										 |  |  | // Stale return whether this layer has become stale (was flattened across) or if | 
					
						
							|  |  |  | // it's still live. | 
					
						
							|  |  |  | func (dl *diskLayer) Stale() bool { | 
					
						
							|  |  |  | 	dl.lock.RLock() | 
					
						
							|  |  |  | 	defer dl.lock.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return dl.stale | 
					
						
							| 
									
										
										
										
											2019-08-06 13:40:28 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Account directly retrieves the account associated with a particular hash in | 
					
						
							|  |  |  | // the snapshot slim data format. | 
					
						
							| 
									
										
										
										
											2019-10-04 15:24:01 +02:00
										 |  |  | func (dl *diskLayer) Account(hash common.Hash) (*Account, error) { | 
					
						
							|  |  |  | 	data, err := dl.AccountRLP(hash) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-06 13:40:28 +03:00
										 |  |  | 	if len(data) == 0 { // can be both nil and []byte{} | 
					
						
							| 
									
										
										
										
											2019-10-04 15:24:01 +02:00
										 |  |  | 		return nil, nil | 
					
						
							| 
									
										
										
										
											2019-08-06 13:40:28 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	account := new(Account) | 
					
						
							|  |  |  | 	if err := rlp.DecodeBytes(data, account); err != nil { | 
					
						
							|  |  |  | 		panic(err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-10-04 15:24:01 +02:00
										 |  |  | 	return account, nil | 
					
						
							| 
									
										
										
										
											2019-08-06 13:40:28 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // AccountRLP directly retrieves the account RLP associated with a particular | 
					
						
							|  |  |  | // hash in the snapshot slim data format. | 
					
						
							| 
									
										
										
										
											2019-10-04 15:24:01 +02:00
										 |  |  | func (dl *diskLayer) AccountRLP(hash common.Hash) ([]byte, error) { | 
					
						
							|  |  |  | 	dl.lock.RLock() | 
					
						
							|  |  |  | 	defer dl.lock.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If the layer was flattened into, consider it invalid (any live reference to | 
					
						
							|  |  |  | 	// the original should be marked as unusable). | 
					
						
							|  |  |  | 	if dl.stale { | 
					
						
							|  |  |  | 		return nil, ErrSnapshotStale | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-11-26 09:48:29 +02:00
										 |  |  | 	// If the layer is being generated, ensure the requested hash has already been | 
					
						
							|  |  |  | 	// covered by the generator. | 
					
						
							|  |  |  | 	if dl.genMarker != nil && bytes.Compare(hash[:], dl.genMarker) > 0 { | 
					
						
							|  |  |  | 		return nil, ErrNotCoveredYet | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// If we're in the disk layer, all diff layers missed | 
					
						
							|  |  |  | 	snapshotDirtyAccountMissMeter.Mark(1) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-06 13:40:28 +03:00
										 |  |  | 	// Try to retrieve the account from the memory cache | 
					
						
							| 
									
										
										
										
											2019-11-26 09:48:29 +02:00
										 |  |  | 	if blob, found := dl.cache.HasGet(nil, hash[:]); found { | 
					
						
							|  |  |  | 		snapshotCleanAccountHitMeter.Mark(1) | 
					
						
							|  |  |  | 		snapshotCleanAccountReadMeter.Mark(int64(len(blob))) | 
					
						
							| 
									
										
										
										
											2019-10-04 15:24:01 +02:00
										 |  |  | 		return blob, nil | 
					
						
							| 
									
										
										
										
											2019-08-06 13:40:28 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// Cache doesn't contain account, pull from disk and cache for later | 
					
						
							| 
									
										
										
										
											2019-11-26 09:48:29 +02:00
										 |  |  | 	blob := rawdb.ReadAccountSnapshot(dl.diskdb, hash) | 
					
						
							| 
									
										
										
										
											2019-11-25 15:30:29 +01:00
										 |  |  | 	dl.cache.Set(hash[:], blob) | 
					
						
							| 
									
										
										
										
											2019-08-06 13:40:28 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-26 09:48:29 +02:00
										 |  |  | 	snapshotCleanAccountMissMeter.Mark(1) | 
					
						
							| 
									
										
										
										
											2019-12-03 10:00:26 +02:00
										 |  |  | 	if n := len(blob); n > 0 { | 
					
						
							|  |  |  | 		snapshotCleanAccountWriteMeter.Mark(int64(n)) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		snapshotCleanAccountInexMeter.Mark(1) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-10-04 15:24:01 +02:00
										 |  |  | 	return blob, nil | 
					
						
							| 
									
										
										
										
											2019-08-06 13:40:28 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Storage directly retrieves the storage data associated with a particular hash, | 
					
						
							|  |  |  | // within a particular account. | 
					
						
							| 
									
										
										
										
											2019-10-04 15:24:01 +02:00
										 |  |  | func (dl *diskLayer) Storage(accountHash, storageHash common.Hash) ([]byte, error) { | 
					
						
							|  |  |  | 	dl.lock.RLock() | 
					
						
							|  |  |  | 	defer dl.lock.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If the layer was flattened into, consider it invalid (any live reference to | 
					
						
							|  |  |  | 	// the original should be marked as unusable). | 
					
						
							|  |  |  | 	if dl.stale { | 
					
						
							|  |  |  | 		return nil, ErrSnapshotStale | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-11-25 15:30:29 +01:00
										 |  |  | 	key := append(accountHash[:], storageHash[:]...) | 
					
						
							| 
									
										
										
										
											2019-08-06 13:40:28 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-26 09:48:29 +02:00
										 |  |  | 	// If the layer is being generated, ensure the requested hash has already been | 
					
						
							|  |  |  | 	// covered by the generator. | 
					
						
							|  |  |  | 	if dl.genMarker != nil && bytes.Compare(key, dl.genMarker) > 0 { | 
					
						
							|  |  |  | 		return nil, ErrNotCoveredYet | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// If we're in the disk layer, all diff layers missed | 
					
						
							|  |  |  | 	snapshotDirtyStorageMissMeter.Mark(1) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-06 13:40:28 +03:00
										 |  |  | 	// Try to retrieve the storage slot from the memory cache | 
					
						
							| 
									
										
										
										
											2019-11-26 09:48:29 +02:00
										 |  |  | 	if blob, found := dl.cache.HasGet(nil, key); found { | 
					
						
							|  |  |  | 		snapshotCleanStorageHitMeter.Mark(1) | 
					
						
							|  |  |  | 		snapshotCleanStorageReadMeter.Mark(int64(len(blob))) | 
					
						
							| 
									
										
										
										
											2019-10-04 15:24:01 +02:00
										 |  |  | 		return blob, nil | 
					
						
							| 
									
										
										
										
											2019-08-06 13:40:28 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// Cache doesn't contain storage slot, pull from disk and cache for later | 
					
						
							| 
									
										
										
										
											2019-11-26 09:48:29 +02:00
										 |  |  | 	blob := rawdb.ReadStorageSnapshot(dl.diskdb, accountHash, storageHash) | 
					
						
							| 
									
										
										
										
											2019-08-06 13:40:28 +03:00
										 |  |  | 	dl.cache.Set(key, blob) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-26 09:48:29 +02:00
										 |  |  | 	snapshotCleanStorageMissMeter.Mark(1) | 
					
						
							| 
									
										
										
										
											2019-12-03 10:00:26 +02:00
										 |  |  | 	if n := len(blob); n > 0 { | 
					
						
							|  |  |  | 		snapshotCleanStorageWriteMeter.Mark(int64(n)) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		snapshotCleanStorageInexMeter.Mark(1) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-10-04 15:24:01 +02:00
										 |  |  | 	return blob, nil | 
					
						
							| 
									
										
										
										
											2019-08-06 13:40:28 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Update creates a new layer on top of the existing snapshot diff tree with | 
					
						
							|  |  |  | // the specified data items. Note, the maps are retained by the method to avoid | 
					
						
							|  |  |  | // copying everything. | 
					
						
							| 
									
										
										
										
											2020-03-03 15:52:00 +02:00
										 |  |  | func (dl *diskLayer) Update(blockHash common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer { | 
					
						
							|  |  |  | 	return newDiffLayer(dl, blockHash, destructs, accounts, storage) | 
					
						
							| 
									
										
										
										
											2019-08-06 13:40:28 +03:00
										 |  |  | } |