228 lines
4.4 KiB
Go
228 lines
4.4 KiB
Go
package ledger
|
|
|
|
import (
|
|
"fmt"
|
|
"math/big"
|
|
"sync"
|
|
|
|
"github.com/meshplus/bitxhub-kit/types"
|
|
)
|
|
|
|
type stateChange interface {
|
|
// revert undoes the state changes by this entry
|
|
revert(*ChainLedger)
|
|
|
|
// dirted returns the address modified by this state entry
|
|
dirtied() *types.Address
|
|
}
|
|
|
|
type stateChanger struct {
|
|
changes []stateChange
|
|
dirties map[types.Address]int // dirty address and the number of changes
|
|
|
|
lock sync.RWMutex
|
|
}
|
|
|
|
func newChanger() *stateChanger {
|
|
return &stateChanger{
|
|
dirties: make(map[types.Address]int),
|
|
}
|
|
}
|
|
|
|
func (s *stateChanger) append(change stateChange) {
|
|
s.lock.Lock()
|
|
defer s.lock.Unlock()
|
|
|
|
s.changes = append(s.changes, change)
|
|
if addr := change.dirtied(); addr != nil {
|
|
s.dirties[*addr]++
|
|
}
|
|
}
|
|
|
|
func (s *stateChanger) revert(ledger *ChainLedger, snapshot int) {
|
|
s.lock.Lock()
|
|
defer s.lock.Unlock()
|
|
|
|
for i := len(s.changes) - 1; i >= snapshot; i-- {
|
|
s.changes[i].revert(ledger)
|
|
|
|
if addr := s.changes[i].dirtied(); addr != nil {
|
|
if s.dirties[*addr]--; s.dirties[*addr] == 0 {
|
|
delete(s.dirties, *addr)
|
|
}
|
|
}
|
|
}
|
|
|
|
s.changes = s.changes[:snapshot]
|
|
}
|
|
|
|
func (s *stateChanger) dirty(addr types.Address) {
|
|
s.dirties[addr]++
|
|
}
|
|
|
|
func (s *stateChanger) length() int {
|
|
return len(s.changes)
|
|
}
|
|
|
|
type (
|
|
createObjectChange struct {
|
|
account *types.Address
|
|
}
|
|
resetObjectChange struct {
|
|
prev *Account
|
|
}
|
|
suicideChange struct {
|
|
account *types.Address
|
|
prev bool
|
|
prevbalance *big.Int
|
|
}
|
|
balanceChange struct {
|
|
account *types.Address
|
|
prev *big.Int
|
|
}
|
|
nonceChange struct {
|
|
account *types.Address
|
|
prev uint64
|
|
}
|
|
storageChange struct {
|
|
account *types.Address
|
|
key, prevalue *types.Hash
|
|
}
|
|
codeChange struct {
|
|
account *types.Address
|
|
prevcode []byte
|
|
}
|
|
refundChange struct {
|
|
prev uint64
|
|
}
|
|
addLogChange struct {
|
|
txHash *types.Hash
|
|
}
|
|
addPreimageChange struct {
|
|
hash types.Hash
|
|
}
|
|
touchChange struct {
|
|
account *types.Address
|
|
}
|
|
accessListAddAccountChange struct {
|
|
address *types.Address
|
|
}
|
|
accessListAddSlotChange struct {
|
|
address *types.Address
|
|
slot *types.Hash
|
|
}
|
|
)
|
|
|
|
func (ch createObjectChange) revert(l *ChainLedger) {
|
|
delete(l.accounts, ch.account.String())
|
|
l.accountCache.rmAccount(ch.account)
|
|
}
|
|
|
|
func (ch createObjectChange) dirtied() *types.Address {
|
|
return ch.account
|
|
}
|
|
|
|
func (ch resetObjectChange) revert(l *ChainLedger) {
|
|
l.setAccount(ch.prev)
|
|
}
|
|
|
|
func (ch resetObjectChange) dirtied() *types.Address {
|
|
return nil
|
|
}
|
|
|
|
func (ch suicideChange) revert(l *ChainLedger) {
|
|
account := l.GetAccount(ch.account)
|
|
account.suicided = ch.prev
|
|
account.SetBalance(ch.prevbalance)
|
|
}
|
|
|
|
func (ch suicideChange) dirtied() *types.Address {
|
|
return ch.account
|
|
}
|
|
|
|
func (ch touchChange) revert(l *ChainLedger) {
|
|
}
|
|
|
|
func (ch touchChange) dirtied() *types.Address {
|
|
return ch.account
|
|
}
|
|
|
|
func (ch balanceChange) revert(l *ChainLedger) {
|
|
fmt.Println(ch.prev.Int64())
|
|
l.GetAccount(ch.account).SetBalance(ch.prev)
|
|
}
|
|
|
|
func (ch balanceChange) dirtied() *types.Address {
|
|
return ch.account
|
|
}
|
|
|
|
func (ch nonceChange) revert(l *ChainLedger) {
|
|
l.GetAccount(ch.account).SetNonce(ch.prev)
|
|
}
|
|
|
|
func (ch nonceChange) dirtied() *types.Address {
|
|
return ch.account
|
|
}
|
|
|
|
func (ch codeChange) revert(l *ChainLedger) {
|
|
l.GetAccount(ch.account).SetCodeAndHash(ch.prevcode)
|
|
}
|
|
|
|
func (ch codeChange) dirtied() *types.Address {
|
|
return ch.account
|
|
}
|
|
|
|
func (ch storageChange) revert(l *ChainLedger) {
|
|
l.GetAccount(ch.account).SetState(ch.key.Bytes(), ch.prevalue.Bytes())
|
|
}
|
|
|
|
func (ch storageChange) dirtied() *types.Address {
|
|
return ch.account
|
|
}
|
|
|
|
func (ch refundChange) revert(l *ChainLedger) {
|
|
l.refund = ch.prev
|
|
}
|
|
|
|
func (ch refundChange) dirtied() *types.Address {
|
|
return nil
|
|
}
|
|
|
|
func (ch addPreimageChange) revert(l *ChainLedger) {
|
|
delete(l.preimages, ch.hash)
|
|
}
|
|
|
|
func (ch addPreimageChange) dirtied() *types.Address {
|
|
return nil
|
|
}
|
|
|
|
func (ch accessListAddAccountChange) revert(l *ChainLedger) {
|
|
l.accessList.DeleteAddress(*ch.address)
|
|
}
|
|
|
|
func (ch accessListAddAccountChange) dirtied() *types.Address {
|
|
return nil
|
|
}
|
|
|
|
func (ch accessListAddSlotChange) revert(l *ChainLedger) {
|
|
l.accessList.DeleteSlot(*ch.address, *ch.slot)
|
|
}
|
|
|
|
func (ch accessListAddSlotChange) dirtied() *types.Address {
|
|
return nil
|
|
}
|
|
|
|
func (ch addLogChange) revert(l *ChainLedger) {
|
|
logs := l.logs.logs[*ch.txHash]
|
|
if len(logs) == 1 {
|
|
delete(l.logs.logs, *ch.txHash)
|
|
} else {
|
|
l.logs.logs[*ch.txHash] = logs[:len(logs)-1]
|
|
}
|
|
l.logs.logSize--
|
|
}
|
|
|
|
func (ch addLogChange) dirtied() *types.Address {
|
|
return nil
|
|
}
|