Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Atomic vm refactor #768

Open
wants to merge 48 commits into
base: seperate-atomic-pkg-base
Choose a base branch
from
Open

Conversation

ceyonur
Copy link
Collaborator

@ceyonur ceyonur commented Jan 28, 2025

Why this should be merged

This PR moves atomic logic to atomic pkg and adds atomic VM that wraps the evm/vm.

AvalancheGo PR: ava-labs/avalanchego#3702

How this works

Defines InnerVM/ExtensibleVM interfaces to extend and wrap plugin/vm with atomic logic and capabilities. Implement InnerVM/ExtensibleVM in evm/VM.

How this was tested

  • Extended unit tests
  • moved existing test to atomic pkg
  • e2e tests should cover
  • will bootstrap fuji/mainnet

Need to be documented?

No

Need to update RELEASES.md?

updated

ceyonur and others added 12 commits January 20, 2025 18:47
Co-authored-by: Quentin McGaw <quentin.mcgaw@avalabs.org>
Signed-off-by: Ceyhun Onur <ceyhunonur54@gmail.com>
Co-authored-by: Quentin McGaw <quentin.mcgaw@avalabs.org>
Signed-off-by: Ceyhun Onur <ceyhunonur54@gmail.com>
Co-authored-by: Quentin McGaw <quentin.mcgaw@avalabs.org>
Signed-off-by: Ceyhun Onur <ceyhunonur54@gmail.com>
Co-authored-by: Quentin McGaw <quentin.mcgaw@avalabs.org>
Signed-off-by: Ceyhun Onur <ceyhunonur54@gmail.com>
@ceyonur ceyonur changed the base branch from master to atomic-vm-wrapper January 28, 2025 16:07
@ceyonur ceyonur changed the base branch from atomic-vm-wrapper to seperate-atomic-pkg-base February 6, 2025 00:06
Comment on lines -35 to -37
for chainID, requests := range requests {
mergeAtomicOpsToMap(a.atomicOps, chainID, requests)
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines -37 to -45
blk := a.chain.GetBlockByNumber(height)
if blk == nil {
return nil, fmt.Errorf("block not found for height (%d)", height)
}

if !a.chain.HasState(blk.Root()) {
return nil, fmt.Errorf("block root does not exist for height (%d), root (%s)", height, blk.Root())
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to syncervm_server.go as this is a common check with state trie.

atomicTrie: atomicTrie,
stateSyncRequestSize: stateSyncRequestSize,
}
func (a *AtomicSyncExtender) Initialize(backend AtomicBackend, atomicTrie AtomicTrie, stateSyncRequestSize uint16) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be called after innervm initialize (so atomicbackend can be available)

Comment on lines +118 to +121
type Visitor interface {
ImportTx(*UnsignedImportTx) error
ExportTx(*UnsignedExportTx) error
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This worked like a charm

Comment on lines -25 to -27
atomicTrieDBPrefix = []byte("atomicTrieDB")
atomicTrieMetaDBPrefix = []byte("atomicTrieMetaDB")
appliedSharedMemoryCursorKey = []byte("atomicTrieLastAppliedToSharedMemory")
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved all these to repo as it seemed to me that it should be the one handling database operations.

@@ -165,13 +171,15 @@ func (client *stateSyncerClient) stateSync(ctx context.Context) error {
return err
}

// Sync the EVM trie and then the atomic trie. These steps could be done
// in parallel or in the opposite order. Keeping them serial for simplicity for now.
Copy link
Collaborator Author

@ceyonur ceyonur Feb 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmmmm looks like it's actually simpler so we can run them in parallel now.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

definetly not in the current scope though

Comment on lines +69 to +72
b, _ = cb58.Decode(key)
pk, _ := secp256k1.ToPrivateKey(b)
balance := new(big.Int).Mul(big.NewInt(params.Ether), big.NewInt(10))
g.Alloc[pk.EthAddress()] = types.GenesisAccount{Balance: balance}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test private keys are not init here yet. (we call this in a var block above)

*avalancheatomic.Memory,
*enginetest.Sender,
) {
vm := WrapVM(&evm.VM{})
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we import evm.VM here (only here)

}

// if the chainCtx.NetworkUpgrades is not empty, set the chain config
// normally it should not be empty, but some tests may not set it
if chainCtx.NetworkUpgrades != (upgrade.Config{}) {
g.Config = params.GetChainConfig(chainCtx.NetworkUpgrades, new(big.Int).Set(chainID))
g.Config.NetworkUpgrades = params.GetNetworkUpgrades(chainCtx.NetworkUpgrades)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably stop defaulting any part of genesis/chainConfig. This still modifies it but only the NetworkUpgrades.

we had few ugly cases in subnet-evm because we filled genesis/chainConfig and turned out that it was even more confusing to maintain.

}

// initialize peer network
if vm.p2pSender == nil {
Copy link
Collaborator Author

@ceyonur ceyonur Feb 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems this is unnecessary since we can directly pass appSender here.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was used in some testing, perhaps check with @joshua-kim

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not read anywhere in the repo, from what I can tell?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

even if this is being used anywhere, I think it was wrong.

@@ -185,93 +182,6 @@ func (utx *UnsignedImportTx) Burned(assetID ids.ID) (uint64, error) {
return math.Sub(input, spent)
}

// SemanticVerify this transaction is valid.
func (utx *UnsignedImportTx) SemanticVerify(
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to tx_semantic_verifier

@@ -178,75 +177,7 @@ func (utx *UnsignedExportTx) Burned(assetID ids.ID) (uint64, error) {
return math.Sub(input, spent)
}

// SemanticVerify this transaction is valid.
func (utx *UnsignedExportTx) SemanticVerify(
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to tx_semantic_verifier

@ceyonur ceyonur marked this pull request as ready for review February 7, 2025 20:28
@ceyonur ceyonur requested a review from darioush as a code owner February 7, 2025 20:28
@ceyonur ceyonur requested a review from a team as a code owner February 7, 2025 20:28
vmerrs/vmerrs.go Outdated
@@ -47,4 +47,7 @@ var (
ErrInvalidCode = errors.New("invalid code: must not begin with 0xef")
ErrNonceUintOverflow = errors.New("nonce uint64 overflow")
ErrAddrProhibited = errors.New("prohibited address cannot be sender or created contract address")
ErrGenerateBlockFailed = errors.New("failed to generate block")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm trying to get rid of this package. Could we move this to a new package under plugin/evm so we don't mix ETH errors with avalanche vm errors?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed this file to coreerrs (which IMO makes more sense) and moved this to plugin/evm/vmerrors

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree - very clear

Copy link
Collaborator

@darioush darioush left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change seems correct.
I think there is a lot of complexity in the initialize flow, which is a result of how we structured dependencies.

However, I think the tech debt of having two repositories is much greater than some added complexity to the VM initialization flow.

I will continue to look for some improvements but I think we should prioritize the repository merging then revisit cleaning up Initialize and improving the innerVM and wrapperVM abstractions.

In any case, in its current state, this would need a README.md that explains what's going on and which structs need to go through initialization prior to use and in which order.

)

/*
// All these methods assumes that VM is already initialized
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think we should move SetExtensionConfig above this comment.
Also not sure if you prefer the block comment /**/ here, seems we can just use //

}

// initialize peer network
if vm.p2pSender == nil {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was used in some testing, perhaps check with @joshua-kim

_ = atomicState.Reject() // ignore this error so we can return the original error instead.
}
if b.extension != nil && (err != nil || !writes) {
b.extension.OnError(b)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know I originally requested to call this OnError, but it's also called on !writes,
so perhaps a name like UnpinVerified() or something else is better.

I think it might make sense to move the call to SemanticVerify on extensions to this fn too (so all the extension calls are in a single place).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think unpinning is specific to atomic implementation. This should probably be called CleanupVerified (since we actually cleanup everytime if !writes regarding of error)

type uninitializedHandler struct{}

func (h *uninitializedHandler) OnLeafsRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, leafsRequest message.LeafsRequest) ([]byte, error) {
return nil, errUninitialized
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible for this code path to be called? if so we shouldn't return an error since it would be fatal

ceyonur and others added 6 commits February 12, 2025 23:13
Co-authored-by: Darioush Jalali <darioush.jalali@avalabs.org>
Signed-off-by: Ceyhun Onur <ceyhunonur54@gmail.com>
Co-authored-by: Darioush Jalali <darioush.jalali@avalabs.org>
Signed-off-by: Ceyhun Onur <ceyhunonur54@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants