github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/execution/state/state.go (about)

     1  // Copyright Monax Industries Limited
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package state
     5  
     6  import (
     7  	"crypto/sha256"
     8  	"fmt"
     9  	"sync"
    10  
    11  	"github.com/hyperledger/burrow/execution/registry"
    12  
    13  	"github.com/hyperledger/burrow/acm"
    14  	"github.com/hyperledger/burrow/acm/acmstate"
    15  	"github.com/hyperledger/burrow/acm/validator"
    16  	"github.com/hyperledger/burrow/binary"
    17  	"github.com/hyperledger/burrow/crypto"
    18  	"github.com/hyperledger/burrow/execution/exec"
    19  	"github.com/hyperledger/burrow/execution/names"
    20  	"github.com/hyperledger/burrow/execution/proposal"
    21  	"github.com/hyperledger/burrow/genesis"
    22  	"github.com/hyperledger/burrow/logging"
    23  	"github.com/hyperledger/burrow/storage"
    24  	"github.com/hyperledger/burrow/txs"
    25  	dbm "github.com/tendermint/tm-db"
    26  )
    27  
    28  const (
    29  	DefaultValidatorsWindowSize = 10
    30  	defaultCacheCapacity        = 1024
    31  	uint64Length                = 8
    32  	// Prefix under which the versioned merkle state tree resides - tracking previous versions of history
    33  	forestPrefix = "f"
    34  	// Prefix for storage outside for the merkel tree - does not contribute to AppHash as a result
    35  	// Leaving the forest for the plains like early members of the homo genus
    36  	plainPrefix = "h"
    37  )
    38  
    39  // Implements account and blockchain state
    40  var _ acmstate.IterableReader = &State{}
    41  var _ names.IterableReader = &State{}
    42  var _ Updatable = &writeState{}
    43  
    44  type KeyFormatStore struct {
    45  	Account   *storage.MustKeyFormat
    46  	Storage   *storage.MustKeyFormat
    47  	Name      *storage.MustKeyFormat
    48  	Proposal  *storage.MustKeyFormat
    49  	Validator *storage.MustKeyFormat
    50  	Event     *storage.MustKeyFormat
    51  	Registry  *storage.MustKeyFormat
    52  	TxHash    *storage.MustKeyFormat
    53  	Abi       *storage.MustKeyFormat
    54  }
    55  
    56  var keys = KeyFormatStore{
    57  	// Stored in the forest
    58  	// AccountAddress -> Account
    59  	Account: storage.NewMustKeyFormat("a", crypto.AddressLength),
    60  	// AccountAddress, Key -> Value
    61  	Storage: storage.NewMustKeyFormat("s", crypto.AddressLength, binary.Word256Bytes),
    62  	// Name -> Entry
    63  	Name: storage.NewMustKeyFormat("n", storage.VariadicSegmentLength),
    64  	// ProposalHash -> Proposal
    65  	Proposal: storage.NewMustKeyFormat("p", sha256.Size),
    66  	// ValidatorAddress -> Power
    67  	Validator: storage.NewMustKeyFormat("v", crypto.AddressLength),
    68  	// Height -> StreamEvent
    69  	Event: storage.NewMustKeyFormat("e", uint64Length),
    70  	// Validator -> NodeIdentity
    71  	Registry: storage.NewMustKeyFormat("r", crypto.AddressLength),
    72  
    73  	// Stored on the plain
    74  	// TxHash -> TxHeight, TxIndex
    75  	TxHash: storage.NewMustKeyFormat("th", txs.HashLength),
    76  	// CodeHash -> Abi
    77  	Abi: storage.NewMustKeyFormat("abi", sha256.Size),
    78  }
    79  
    80  var Prefixes [][]byte
    81  
    82  func init() {
    83  	var err error
    84  	Prefixes, err = storage.EnsureKeyFormatStore(keys)
    85  	if err != nil {
    86  		panic(fmt.Errorf("KeyFormatStore is invalid: %v", err))
    87  	}
    88  }
    89  
    90  type Updatable interface {
    91  	acmstate.Writer
    92  	names.Writer
    93  	proposal.Writer
    94  	registry.Writer
    95  	validator.Writer
    96  	acmstate.MetadataWriter
    97  	AddBlock(blockExecution *exec.BlockExecution) error
    98  }
    99  
   100  // Wraps state to give access to writer methods
   101  type writeState struct {
   102  	forest       *storage.MutableForest
   103  	plain        *storage.PrefixDB
   104  	ring         *validator.Ring
   105  	accountStats acmstate.AccountStats
   106  	nodeStats    registry.NodeStats
   107  }
   108  
   109  // This is the immutable merklised read state at a given finalised height
   110  type ImmutableState struct {
   111  	Forest storage.ForestReader
   112  	validator.History
   113  }
   114  
   115  type ReadState struct {
   116  	ImmutableState
   117  	Plain *storage.PrefixDB
   118  }
   119  
   120  // Writers to state are responsible for calling State.Lock() before calling
   121  type State struct {
   122  	sync.Mutex
   123  	db dbm.DB
   124  	ReadState
   125  	writeState writeState
   126  	logger     *logging.Logger
   127  }
   128  
   129  // NewState creates a new State object
   130  func NewState(db dbm.DB) *State {
   131  	forest, err := storage.NewMutableForest(storage.NewPrefixDB(db, forestPrefix), defaultCacheCapacity)
   132  	if err != nil {
   133  		// This should only happen if we have negative cache capacity, which for us is a positive compile-time constant
   134  		panic(fmt.Errorf("could not create new state because error creating MutableForest"))
   135  	}
   136  	plain := storage.NewPrefixDB(db, plainPrefix)
   137  	ring := validator.NewRing(nil, DefaultValidatorsWindowSize)
   138  	return &State{
   139  		db: db,
   140  		ReadState: ReadState{
   141  			ImmutableState: ImmutableState{
   142  				Forest:  forest,
   143  				History: ring,
   144  			},
   145  			Plain: plain,
   146  		},
   147  		writeState: writeState{
   148  			forest:    forest,
   149  			plain:     plain,
   150  			ring:      ring,
   151  			nodeStats: registry.NewNodeStats(),
   152  		},
   153  		logger: logging.NewNoopLogger(),
   154  	}
   155  }
   156  
   157  // Make genesis state from GenesisDoc and save to DB
   158  func MakeGenesisState(db dbm.DB, genesisDoc *genesis.GenesisDoc) (*State, error) {
   159  	s := NewState(db)
   160  
   161  	const errHeader = "MakeGenesisState():"
   162  	// Make accounts state tree
   163  	for _, genAcc := range genesisDoc.Accounts {
   164  		perm := genAcc.Permissions
   165  		acc := &acm.Account{
   166  			Address:     genAcc.Address,
   167  			Balance:     genAcc.Amount,
   168  			Permissions: perm,
   169  		}
   170  		err := s.writeState.UpdateAccount(acc)
   171  		if err != nil {
   172  			return nil, fmt.Errorf("%s %v", errHeader, err)
   173  		}
   174  	}
   175  	// Make genesis validators
   176  	err := s.writeState.MakeGenesisValidators(genesisDoc)
   177  	if err != nil {
   178  		return nil, fmt.Errorf("%s %v", errHeader, err)
   179  	}
   180  	// Set up fallback global permissions
   181  	err = s.writeState.UpdateAccount(genesisDoc.GlobalPermissionsAccount())
   182  	if err != nil {
   183  		return nil, fmt.Errorf("%s %v", errHeader, err)
   184  	}
   185  
   186  	return s, nil
   187  }
   188  
   189  func (s *State) InitialCommit() error {
   190  	_, version, err := s.commit()
   191  	if err != nil {
   192  		return fmt.Errorf("could not save initial state: %v", err)
   193  	}
   194  	if version != VersionOffset {
   195  		return fmt.Errorf("initial state got version %d after committing genesis state but version offset should be %d",
   196  			version, VersionOffset)
   197  	}
   198  	return nil
   199  }
   200  
   201  // Tries to load the execution state from DB, returns nil with no error if no state found
   202  func LoadState(db dbm.DB, version int64) (*State, error) {
   203  	s := NewState(db)
   204  	err := s.writeState.forest.Load(version)
   205  	if err != nil {
   206  		return nil, fmt.Errorf("could not load MutableForest at version %d: %v", version, err)
   207  	}
   208  
   209  	// Populate stats. If this starts taking too long, store the value rather than the full scan at startup
   210  	err = s.loadAccountStats()
   211  	if err != nil {
   212  		return nil, err
   213  	}
   214  
   215  	err = s.loadNodeStats()
   216  	if err != nil {
   217  		return nil, err
   218  	}
   219  
   220  	// load the validator ring
   221  	ring, err := LoadValidatorRing(version, DefaultValidatorsWindowSize, s.writeState.forest.GetImmutable)
   222  	if err != nil {
   223  		return nil, err
   224  	}
   225  	s.writeState.ring = ring
   226  	s.ReadState.History = ring
   227  
   228  	return s, nil
   229  }
   230  
   231  func (s *State) loadAccountStats() error {
   232  	return s.IterateAccounts(func(acc *acm.Account) error {
   233  		if len(acc.EVMCode) > 0 || len(acc.WASMCode) > 0 {
   234  			s.writeState.accountStats.AccountsWithCode++
   235  		} else {
   236  			s.writeState.accountStats.AccountsWithoutCode++
   237  		}
   238  		return nil
   239  	})
   240  }
   241  
   242  func (s *State) loadNodeStats() error {
   243  	return s.IterateNodes(func(id crypto.Address, node *registry.NodeIdentity) error {
   244  		s.writeState.nodeStats.Addresses[node.GetNetworkAddress()][id] = struct{}{}
   245  		return nil
   246  	})
   247  }
   248  
   249  func (s *State) Version() int64 {
   250  	return s.writeState.forest.Version()
   251  }
   252  
   253  func (s *State) Hash() []byte {
   254  	return s.writeState.forest.Hash()
   255  }
   256  
   257  func (s *State) AtLatestVersion() (*ImmutableState, error) {
   258  	return s.AtVersion(s.Version())
   259  }
   260  
   261  // Return a concurrent-safe immutable read state at the given height
   262  func (s *State) AtHeight(height uint64) (*ImmutableState, error) {
   263  	return s.AtVersion(VersionAtHeight(height))
   264  }
   265  
   266  // Return a concurrent-safe immutable read state at the given version
   267  func (s *State) AtVersion(version int64) (*ImmutableState, error) {
   268  	forest, err := s.writeState.forest.GetImmutable(version)
   269  	if err != nil {
   270  		return nil, err
   271  	}
   272  	ring, err := LoadValidatorRing(version, DefaultValidatorsWindowSize, s.writeState.forest.GetImmutable)
   273  	if err != nil {
   274  		return nil, err
   275  	}
   276  	return &ImmutableState{
   277  		Forest:  forest,
   278  		History: ring,
   279  	}, nil
   280  }
   281  
   282  // Perform updates to state whilst holding the write lock, allows a commit to hold the write lock across multiple
   283  // operations while preventing interlaced reads and writes
   284  func (s *State) Update(updater func(up Updatable) error) ([]byte, int64, error) {
   285  	s.Lock()
   286  	defer s.Unlock()
   287  	err := updater(&s.writeState)
   288  	if err != nil {
   289  		return nil, 0, err
   290  	}
   291  	return s.commit()
   292  }
   293  
   294  func (s *State) commit() ([]byte, int64, error) {
   295  	// save state at a new version may still be orphaned before we save the version against the hash
   296  	hash, version, err := s.writeState.forest.Save()
   297  	if err != nil {
   298  		return nil, 0, err
   299  	}
   300  	totalPowerChange, totalFlow, err := s.writeState.ring.Rotate()
   301  	if err != nil {
   302  		return nil, 0, err
   303  	}
   304  	if totalFlow.Sign() != 0 {
   305  		//noinspection ALL
   306  		s.logger.InfoMsg("validator set changes", "total_power_change", totalPowerChange, "total_flow", totalFlow)
   307  	}
   308  	return hash, version, err
   309  }
   310  
   311  // Creates a copy of the database to the supplied db
   312  func (s *State) Copy(db dbm.DB) (*State, error) {
   313  	stateCopy := NewState(db)
   314  	err := s.writeState.forest.IterateRWTree(nil, nil, true,
   315  		func(prefix []byte, tree *storage.RWTree) error {
   316  			return stateCopy.writeState.forest.Write(prefix, func(treeCopy *storage.RWTree) error {
   317  				return tree.IterateWriteTree(nil, nil, true, func(key []byte, value []byte) error {
   318  					treeCopy.Set(key, value)
   319  					return nil
   320  				})
   321  			})
   322  		})
   323  	if err != nil {
   324  		return nil, err
   325  	}
   326  	_, _, err = stateCopy.commit()
   327  	if err != nil {
   328  		return nil, err
   329  	}
   330  	return stateCopy, nil
   331  }
   332  
   333  func (s *State) SetLogger(logger *logging.Logger) {
   334  	s.logger = logger
   335  }
   336  
   337  func (s *State) Dump() string {
   338  	return s.writeState.forest.Dump()
   339  }