Skip to content

Commit

Permalink
Merge branch 'master' into ramtin/5222-unify-balance-representation
Browse files Browse the repository at this point in the history
  • Loading branch information
ramtinms authored Jan 22, 2024
2 parents 3a26c2e + 89594b2 commit 42e05c5
Show file tree
Hide file tree
Showing 24 changed files with 2,276 additions and 687 deletions.
88 changes: 58 additions & 30 deletions config/default-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,38 +140,66 @@ network-config:
# The size of the queue for notifications about invalid RPC messages
notification-cache-size: 10_000
validation: # RPC control message validation inspector configs
# Rpc validation inspector number of pool workers
workers: 5
# The size of the queue used by worker pool for the control message validation inspector
queue-size: 100
# The max sample size used for RPC message validation. If the total number of RPC messages exceeds this value a sample will be taken but messages will not be truncated
message-max-sample-size: 1000
# Max number of control messages in a sample to be inspected when inspecting GRAFT and PRUNE message types. If the total number of control messages (GRAFT or PRUNE)
# exceeds this max sample size then the respective message will be truncated before being processed.
graft-and-prune-message-max-sample-size: 1000
# The threshold at which an error will be returned if the number of invalid RPC messages exceeds this value
error-threshold: 500
ihave: # Max number of ihave messages in a sample to be inspected. If the number of ihave messages exceeds this configured value
# the control message ihaves will be truncated to the max sample size. This sample is randomly selected.
inspection-queue:
# Rpc validation inspector number of pool workers
workers: 5
# The size of the queue used by worker pool for the control message validation inspector
queue-size: 100
publish-messages:
# The maximum number of messages in a single RPC message that are randomly sampled for async inspection.
# When the size of a single RPC message exceeds this threshold, a random sample is taken for inspection, but the RPC message is not truncated.
max-sample-size: 1000
# Max number of ihave message ids in a sample to be inspected per ihave. Each ihave message includes a list of message ids
# each. If the size of the message ids list for a single ihave message exceeds the configured max message id sample size the list of message ids will be truncated.
max-message-id-sample-size: 1000
# The threshold at which an error will be returned if the number of invalid RPC messages exceeds this value
error-threshold: 500
graft-and-prune:
# The maximum number of GRAFT or PRUNE messages in a single RPC message.
# When the total number of GRAFT or PRUNE messages in a single RPC message exceeds this threshold,
# a random sample of GRAFT or PRUNE messages will be taken and the RPC message will be truncated to this sample size.
message-count-threshold: 1000
# Maximum number of total duplicate topic ids in a single GRAFT or PRUNE message, ideally this should be 0 but we allow for some tolerance
# to avoid penalizing peers that are not malicious but are misbehaving due to bugs or other issues.
# A topic id is considered duplicate if it appears more than once in a single GRAFT or PRUNE message.
duplicate-topic-id-threshold: 50
ihave:
# The maximum allowed number of iHave messages in a single RPC message.
# Each iHave message represents the list of message ids. When the total number of iHave messages
# in a single RPC message exceeds this threshold, a random sample of iHave messages will be taken and the RPC message will be truncated to this sample size.
# The sample size is equal to the configured message-count-threshold.
message-count-threshold: 1000
# The maximum allowed number of message ids in a single iHave message.
# Each iHave message represents the list of message ids for a specific topic, and this parameter controls the maximum number of message ids
# that can be included in a single iHave message. When the total number of message ids in a single iHave message exceeds this threshold,
# a random sample of message ids will be taken and the iHave message will be truncated to this sample size.
# The sample size is equal to the configured message-id-count-threshold.
message-id-count-threshold: 1000
# The tolerance threshold for having duplicate topics in an iHave message under inspection.
# When the total number of duplicate topic ids in a single iHave message exceeds this threshold, the inspection of message will fail.
# Note that a topic ID is counted as a duplicate only if it is repeated more than once.
duplicate-topic-id-threshold: 50
# Threshold of tolerance for having duplicate message IDs in a single iHave message under inspection.
# When the total number of duplicate message ids in a single iHave message exceeds this threshold, the inspection of message will fail.
# Ideally, an iHave message should not have any duplicate message IDs, hence a message id is considered duplicate when it is repeated more than once
# within the same iHave message. When the total number of duplicate message ids in a single iHave message exceeds this threshold, the inspection of message will fail.
duplicate-message-id-threshold: 100
iwant:
# Max number of iwant messages in a sample to be inspected. If the total number of iWant control messages
# exceeds this max sample size then the respective message will be truncated before being processed.
max-sample-size: 1000
# Max number of iwant message ids in a sample to be inspected per iwant. Each iwant message includes a list of message ids
# each, if the size of this list exceeds the configured max message id sample size the list of message ids will be truncated.
max-message-id-sample-size: 1000
# The allowed threshold of iWant messages received without a corresponding tracked iHave message that was sent. If the cache miss threshold is exceeded an
# invalid control message notification is disseminated and the sender will be penalized.
cache-miss-threshold: .5
# The iWants size at which message id cache misses will be checked.
cache-miss-check-size: 1000
# The max allowed duplicate message IDs in a single iWant control message. If the duplicate message threshold is exceeded an invalid control message
# notification is disseminated and the sender will be penalized.
duplicate-message-id-threshold: .15
# The maximum allowed number of iWant messages in a single RPC message.
# Each iWant message represents the list of message ids. When the total number of iWant messages
# in a single RPC message exceeds this threshold, a random sample of iWant messages will be taken and the RPC message will be truncated to this sample size.
# The sample size is equal to the configured message-count-threshold.
message-count-threshold: 1000
# The maximum allowed number of message ids in a single iWant message.
# Each iWant message represents the list of message ids for a specific topic, and this parameter controls the maximum number of message ids
# that can be included in a single iWant message. When the total number of message ids in a single iWant message exceeds this threshold,
# a random sample of message ids will be taken and the iWant message will be truncated to this sample size.
# The sample size is equal to the configured message-id-count-threshold.
message-id-count-threshold: 1000
# The allowed threshold of iWant messages received without a corresponding tracked iHave message that was sent.
# If the cache miss threshold is exceeded an invalid control message notification is disseminated and the sender will be penalized.
cache-miss-threshold: 500
# The max allowed number of duplicate message ids in a single iwant message.
# Note that ideally there should be no duplicate message ids in a single iwant message but
# we allow for some tolerance to avoid penalizing peers that are not malicious
duplicate-message-id-threshold: 100
cluster-prefixed-messages:
# Cluster prefixed control message validation configs
# The size of the cache used to track the amount of cluster prefixed topics received by peers
Expand Down
158 changes: 125 additions & 33 deletions fvm/evm/emulator/state/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,12 @@ func (v *BaseView) GetCode(addr gethCommon.Address) ([]byte, error) {

// GetCodeHash returns the code hash of an address
//
// for non-existent accounts or accounts without a code (e.g. EOAs) it returns default empty
// for non-existent accounts it returns gethCommon.Hash{}
// and for accounts without a code (e.g. EOAs) it returns default empty
// hash value (gethTypes.EmptyCodeHash)
func (v *BaseView) GetCodeHash(addr gethCommon.Address) (gethCommon.Hash, error) {
acc, err := v.getAccount(addr)
codeHash := gethTypes.EmptyCodeHash
codeHash := gethCommon.Hash{}
if acc != nil {
codeHash = acc.CodeHash
}
Expand Down Expand Up @@ -204,7 +205,7 @@ func (v *BaseView) CreateAccount(
var colID []byte
// if is an smart contract account
if len(code) > 0 {
err := v.storeCode(addr, code)
err := v.updateAccountCode(addr, code, codeHash)
if err != nil {
return err
}
Expand Down Expand Up @@ -235,17 +236,17 @@ func (v *BaseView) UpdateAccount(
if acc == nil {
return v.CreateAccount(addr, balance, nonce, code, codeHash)
}
// if it has a code change
if codeHash != acc.CodeHash {
err := v.storeCode(addr, code)
if err != nil {
return err
}
// TODO: maybe purge the state in the future as well
// currently the behaviour of stateDB doesn't purge the data
// We don't need to check if the code is empty and we purge the state
// this is not possible right now.

// update account code
err = v.updateAccountCode(addr, code, codeHash)
if err != nil {
return err
}
// TODO: maybe purge the state in the future as well
// currently the behaviour of stateDB doesn't purge the data
// We don't need to check if the code is empty and we purge the state
// this is not possible right now.

newAcc := NewAccount(addr, balance, nonce, codeHash, acc.CollectionID)
// no need to update the cache , storeAccount would update the cache
return v.storeAccount(newAcc)
Expand All @@ -263,23 +264,23 @@ func (v *BaseView) DeleteAccount(addr gethCommon.Address) error {
return fmt.Errorf("account doesn't exist to be deleted")
}

// 2. update the cache
// 2. remove the code
if acc.HasCode() {
err = v.updateAccountCode(addr, nil, gethTypes.EmptyCodeHash)
if err != nil {
return err
}
}

// 3. update the cache
delete(v.cachedAccounts, addr)

// 3. collections
// 4. collections
err = v.accounts.Remove(addr.Bytes())
if err != nil {
return err
}

// 4. remove the code
if acc.HasCode() {
err = v.storeCode(addr, nil)
if err != nil {
return err
}
}

// 5. remove storage slots
if len(acc.CollectionID) > 0 {
col, found := v.slots[addr]
Expand Down Expand Up @@ -338,6 +339,16 @@ func (v *BaseView) Commit() error {
return nil
}

// NumberOfContracts returns the number of unique contracts
func (v *BaseView) NumberOfContracts() uint64 {
return v.codes.Size()
}

// NumberOfContracts returns the number of accounts
func (v *BaseView) NumberOfAccounts() uint64 {
return v.accounts.Size()
}

func (v *BaseView) fetchOrCreateCollection(path string) (collection *Collection, created bool, error error) {
collectionID, err := v.ledger.GetValue(v.rootAddress[:], []byte(path))
if err != nil {
Expand Down Expand Up @@ -391,29 +402,110 @@ func (v *BaseView) getCode(addr gethCommon.Address) ([]byte, error) {
if found {
return code, nil
}
// check if account exist in cache and has codeHash
acc, found := v.cachedAccounts[addr]
if found && !acc.HasCode() {

// get account
acc, err := v.getAccount(addr)
if err != nil {
return nil, err
}

if acc == nil || !acc.HasCode() {
return nil, nil
}
// then collect it from the code collection
code, err := v.codes.Get(addr.Bytes())

// collect the container from the code collection by codeHash
encoded, err := v.codes.Get(acc.CodeHash.Bytes())
if err != nil {
return nil, err
}
if code != nil {
if len(encoded) == 0 {
return nil, nil
}

codeCont, err := CodeContainerFromEncoded(encoded)
if err != nil {
return nil, err
}
code = codeCont.Code()
if len(code) > 0 {
v.cachedCodes[addr] = code
}
return code, nil
}

func (v *BaseView) storeCode(addr gethCommon.Address, code []byte) error {
if len(code) == 0 {
func (v *BaseView) updateAccountCode(addr gethCommon.Address, code []byte, codeHash gethCommon.Hash) error {
// get account
acc, err := v.getAccount(addr)
if err != nil {
return err
}
// if is a new account
if acc == nil {
if len(code) == 0 {
return nil
}
v.cachedCodes[addr] = code
return v.addCode(code, codeHash)
}

// skip if is the same code
if acc.CodeHash == codeHash {
return nil
}

// clean old code first if exist
if acc.HasCode() {
delete(v.cachedCodes, addr)
return v.codes.Remove(addr.Bytes())
err = v.removeCode(acc.CodeHash)
if err != nil {
return err
}
}

// add new code
if len(code) == 0 {
return nil
}
v.cachedCodes[addr] = code
return v.codes.Set(addr.Bytes(), code)
return v.addCode(code, codeHash)
}

func (v *BaseView) removeCode(codeHash gethCommon.Hash) error {
encoded, err := v.codes.Get(codeHash.Bytes())
if err != nil {
return err
}
if len(encoded) == 0 {
return nil
}

cc, err := CodeContainerFromEncoded(encoded)
if err != nil {
return err
}
if cc.DecRefCount() {
return v.codes.Remove(codeHash.Bytes())
}
return v.codes.Set(codeHash.Bytes(), cc.Encode())
}

func (v *BaseView) addCode(code []byte, codeHash gethCommon.Hash) error {
encoded, err := v.codes.Get(codeHash.Bytes())
if err != nil {
return err
}
// if is the first time the code is getting deployed
if len(encoded) == 0 {
return v.codes.Set(codeHash.Bytes(), NewCodeContainer(code).Encode())
}

// otherwise update the cc
cc, err := CodeContainerFromEncoded(encoded)
if err != nil {
return err
}
cc.IncRefCount()
return v.codes.Set(codeHash.Bytes(), cc.Encode())
}

func (v *BaseView) getSlot(sk types.SlotAddress) (gethCommon.Hash, error) {
Expand Down
Loading

0 comments on commit 42e05c5

Please sign in to comment.