github.com/dim4egster/coreth@v0.10.2/plugin/evm/atomic_state.go (about) 1 // (c) 2020-2021, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package evm 5 6 import ( 7 "fmt" 8 9 "github.com/dim4egster/qmallgo/chains/atomic" 10 "github.com/dim4egster/qmallgo/database" 11 "github.com/dim4egster/qmallgo/ids" 12 "github.com/ethereum/go-ethereum/common" 13 "github.com/ethereum/go-ethereum/log" 14 ) 15 16 var _ AtomicState = &atomicState{} 17 18 // AtomicState is an abstraction created through AtomicBackend 19 // and can be used to apply the VM's state change for atomic txs 20 // or reject them to free memory. 21 // The root of the atomic trie after applying the state change 22 // is accessible through this interface as well. 23 type AtomicState interface { 24 // Root of the atomic trie after applying the state change. 25 Root() common.Hash 26 // Accept applies the state change to VM's persistent storage 27 // Changes are persisted atomically along with the provided [commitBatch]. 28 Accept(commitBatch database.Batch) error 29 // Reject frees memory associated with the state change. 30 Reject() error 31 } 32 33 // atomicState implements the AtomicState interface using 34 // a pointer to the atomicBackend. 35 type atomicState struct { 36 backend *atomicBackend 37 blockHash common.Hash 38 blockHeight uint64 39 txs []*Tx 40 atomicOps map[ids.ID]*atomic.Requests 41 atomicRoot common.Hash 42 } 43 44 func (a *atomicState) Root() common.Hash { 45 return a.atomicRoot 46 } 47 48 // Accept applies the state change to VM's persistent storage. 49 func (a *atomicState) Accept(commitBatch database.Batch) error { 50 // Update the atomic tx repository. Note it is necessary to invoke 51 // the correct method taking bonus blocks into consideration. 52 if a.backend.IsBonus(a.blockHeight, a.blockHash) { 53 if err := a.backend.repo.WriteBonus(a.blockHeight, a.txs); err != nil { 54 return err 55 } 56 } else { 57 if err := a.backend.repo.Write(a.blockHeight, a.txs); err != nil { 58 return err 59 } 60 } 61 62 // Accept the root of this atomic trie (will be persisted if at a commit interval) 63 if _, err := a.backend.atomicTrie.AcceptTrie(a.blockHeight, a.atomicRoot); err != nil { 64 return err 65 } 66 // Update the last accepted block to this block and remove it from 67 // the map tracking undecided blocks. 68 a.backend.lastAcceptedHash = a.blockHash 69 delete(a.backend.verifiedRoots, a.blockHash) 70 71 // get changes from the atomic trie and repository in a batch 72 // to be committed atomically with [commitBatch] and shared memory. 73 atomicChangesBatch, err := a.backend.db.CommitBatch() 74 if err != nil { 75 return fmt.Errorf("could not create commit batch in atomicState accept: %w", err) 76 } 77 78 // If this is a bonus block, write [commitBatch] without applying atomic ops 79 // to shared memory. 80 if a.backend.IsBonus(a.blockHeight, a.blockHash) { 81 log.Info("skipping atomic tx acceptance on bonus block", "block", a.blockHash) 82 return atomic.WriteAll(commitBatch, atomicChangesBatch) 83 } 84 85 // Otherwise, atomically commit pending changes in the version db with 86 // atomic ops to shared memory. 87 return a.backend.sharedMemory.Apply(a.atomicOps, commitBatch, atomicChangesBatch) 88 } 89 90 // Reject frees memory associated with the state change. 91 func (a *atomicState) Reject() error { 92 // Remove the block from the map of undecided blocks. 93 delete(a.backend.verifiedRoots, a.blockHash) 94 // Unpin the rejected atomic trie root from memory. 95 return a.backend.atomicTrie.RejectTrie(a.atomicRoot) 96 }