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

feat(geth): add ethereum support for the geth binary #1230

Merged
merged 51 commits into from
Aug 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
ffe6544
initial thorchain addition, configs setup, still need genesis update
misko9 Jul 19, 2024
9116cec
wip: thorchain genesis
misko9 Jul 23, 2024
ceba377
thorchain running
misko9 Jul 23, 2024
277335b
thorchain and bifrost working together
misko9 Jul 25, 2024
3e6981b
add savers, swaps, and saver eject example case for gaia
misko9 Jul 26, 2024
49eafc3
arb wip, all other sim tests passing
misko9 Jul 31, 2024
c0febe8
arb code in, needs testing with >1 pool
misko9 Jul 31, 2024
cbc6d2d
add ethereum to thorchain test and start cleaning up
misko9 Aug 2, 2024
50a6017
clean up savers/arb features
misko9 Aug 2, 2024
699ebf5
clean up swap feature
misko9 Aug 2, 2024
de5eb93
cleanup of saver eject and ragnarok features
misko9 Aug 2, 2024
2fcd796
fix: second+ saver eject now works
misko9 Aug 5, 2024
ac8aac9
Add back arbing and eth->gaia swap
misko9 Aug 5, 2024
cfc4091
wip, add utxo support, SendFundsWithNote() still needed
misko9 Aug 7, 2024
e1c5671
hardfork wip
agouin Aug 8, 2024
de8797a
start with genesis contents
agouin Aug 8, 2024
a166e88
progress further
agouin Aug 8, 2024
95520c5
wip: removed non-BTC chains temporarily, BTC's SendFundsWithNote succ…
misko9 Aug 8, 2024
69977a6
thorchain<->btc dual lp working
misko9 Aug 8, 2024
3fa9983
btc and bch looking good
misko9 Aug 9, 2024
ea0a2a0
ltc working, clean up logging, fix coins funded on each chain, and fi…
misko9 Aug 9, 2024
34f5287
utxo chains fully operational
misko9 Aug 10, 2024
4346aae
fix ether type
misko9 Aug 11, 2024
e39bd9a
add some protections around utxo node wallet usage
misko9 Aug 12, 2024
ad4a0a7
send utxo change back to sender instead of a change address
misko9 Aug 12, 2024
5daf638
Run tests in parallel
misko9 Aug 13, 2024
2dbbf78
clean up utxo test
misko9 Aug 13, 2024
f08f494
fmt/lint
misko9 Aug 13, 2024
7508c67
More cleanup
misko9 Aug 14, 2024
d1641df
increase time for bifrost to initialize
misko9 Aug 14, 2024
bcab349
Merge branch 'andrew/thorchain_hardfork' into steve/thorchain
misko9 Aug 14, 2024
a8b23da
Set bifrost envs at runtime
misko9 Aug 14, 2024
e8ae3a0
change wg to eg
misko9 Aug 15, 2024
7d72058
minor fmt
misko9 Aug 15, 2024
0545c5f
Merge branch 'main' into steve/thorchain
misko9 Aug 15, 2024
2a52c9c
add back mainnet-genesis.json
misko9 Aug 15, 2024
387828e
wip: add geth support for ethereum
misko9 Aug 19, 2024
2821052
geth: implement recover key
misko9 Aug 19, 2024
7c39732
deploy contract working on geth chain
misko9 Aug 20, 2024
fdd7731
clean up, making common code common
misko9 Aug 21, 2024
929a20d
fix geth example test
misko9 Aug 21, 2024
3609948
bsc working
misko9 Aug 22, 2024
a2a8ddd
fmt
misko9 Aug 22, 2024
84bd7d6
clean up comments and remove mainnet-genesis.json
misko9 Aug 23, 2024
77cad5d
Merge branch 'main' into steve/geth
misko9 Aug 23, 2024
ec0975c
remove transfer parameter from genesis state since ibc module was rem…
misko9 Aug 23, 2024
e63dc09
improve anvil errors
misko9 Aug 23, 2024
259d911
increase wait time for the first 100 gaia txs to reduce flakiness
misko9 Aug 23, 2024
bda4427
improve start up time
misko9 Aug 23, 2024
6fe2a1f
improve stdout sanitization
misko9 Aug 23, 2024
8f5152a
Improve send 100 gaia txs to be a little nicer on system resources an…
misko9 Aug 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
334 changes: 51 additions & 283 deletions chain/ethereum/ethererum_chain.go

Large diffs are not rendered by default.

228 changes: 228 additions & 0 deletions chain/ethereum/foundry/anvil_chain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
package foundry

import (
"context"
"encoding/json"
"fmt"
"os"
"path"
"path/filepath"
"strings"
"sync"

"github.com/docker/docker/api/types/mount"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/strangelove-ventures/interchaintest/v8/chain/ethereum"
"github.com/strangelove-ventures/interchaintest/v8/ibc"
"go.uber.org/zap"
)

var _ ibc.Chain = &AnvilChain{}

type AnvilChain struct {
*ethereum.EthereumChain

keystoreMap map[string]*NodeWallet
}

func NewAnvilChain(testName string, chainConfig ibc.ChainConfig, log *zap.Logger) *AnvilChain {
return &AnvilChain{
EthereumChain: ethereum.NewEthereumChain(testName, chainConfig, log),
keystoreMap: make(map[string]*NodeWallet),
}
}

func (c *AnvilChain) KeystoreDir() string {
return path.Join(c.HomeDir(), ".foundry", "keystores")
}

func (c *AnvilChain) Start(testName string, ctx context.Context, additionalGenesisWallets ...ibc.WalletAmount) error {
cmd := []string{c.Config().Bin,
"--host", "0.0.0.0", // Anyone can call
"--no-cors",
"--gas-price", c.Config().GasPrices,
}

cmd = append(cmd, c.Config().AdditionalStartArgs...)

var mounts []mount.Mount
if loadState, ok := c.Config().ConfigFileOverrides["--load-state"].(string); ok {
pwd, err := os.Getwd()
if err != nil {
return err
}
localJsonFile := filepath.Join(pwd, loadState)
dockerJsonFile := path.Join(c.HomeDir(), path.Base(loadState))
mounts = []mount.Mount{
{
Type: mount.TypeBind,
Source: localJsonFile,
Target: dockerJsonFile,
},
}
cmd = append(cmd, "--load-state", dockerJsonFile)
}

return c.EthereumChain.Start(ctx, cmd, mounts)
}

type NewWalletOutput struct {
Address string `json:"address"`
Path string `json:"path"`
}

func (c *AnvilChain) MakeKeystoreDir(ctx context.Context) error {
cmd := []string{"mkdir", "-p", c.KeystoreDir()}
_, _, err := c.Exec(ctx, cmd, nil)
return err
}

func (c *AnvilChain) CreateKey(ctx context.Context, keyName string) error {
err := c.MakeKeystoreDir(ctx) // Ensure keystore directory is created
if err != nil {
return err
}

_, ok := c.keystoreMap[keyName]
if ok {
return fmt.Errorf("keyname (%s) already used", keyName)
}

cmd := []string{"cast", "wallet", "new", c.KeystoreDir(), "--unsafe-password", "", "--json"}
stdout, _, err := c.Exec(ctx, cmd, nil)
if err != nil {
return err
}

newWallet := []NewWalletOutput{}
err = json.Unmarshal(stdout, &newWallet)
if err != nil {
return err
}

c.keystoreMap[keyName] = &NodeWallet{
keystore: newWallet[0].Path,
}

return nil
}

func (c *AnvilChain) RecoverKey(ctx context.Context, keyName, mnemonic string) error {
err := c.MakeKeystoreDir(ctx) // Ensure keystore directory is created
if err != nil {
return err
}

cmd := []string{"cast", "wallet", "import", keyName, "--keystore-dir", c.KeystoreDir(), "--mnemonic", mnemonic, "--unsafe-password", ""}
_, _, err = c.Exec(ctx, cmd, nil)
if err != nil {
return err
}

// This is needed for CreateKey() since that keystore path does not use the keyname
c.keystoreMap[keyName] = &NodeWallet{
keystore: path.Join(c.KeystoreDir(), keyName),
}

return nil
}

// Get address of account, cast to a string to use
func (c *AnvilChain) GetAddress(ctx context.Context, keyName string) ([]byte, error) {
account, ok := c.keystoreMap[keyName]
if !ok {
return nil, fmt.Errorf("keyname (%s) not found", keyName)
}

if account.address != "" {
return hexutil.MustDecode(account.address), nil
}

cmd := []string{"cast", "wallet", "address", "--keystore", account.keystore, "--password", ""}
stdout, _, err := c.Exec(ctx, cmd, nil)
if err != nil {
return nil, err
}

addr := strings.TrimSpace(string(stdout))
account.address = addr
return hexutil.MustDecode(addr), nil
}

func (c *AnvilChain) SendFunds(ctx context.Context, keyName string, amount ibc.WalletAmount) error {
_, err := c.SendFundsWithNote(ctx, keyName, amount, "")
return err
}

type TransactionReceipt struct {
TxHash string `json:"transactionHash"`
}

func (c *AnvilChain) SendFundsWithNote(ctx context.Context, keyName string, amount ibc.WalletAmount, note string) (string, error) {
var cmd []string
if len(note) > 0 {
cmd = []string{"cast", "send", amount.Address, hexutil.Encode([]byte(note)), "--value", amount.Amount.String(), "--json"}
} else {
cmd = []string{"cast", "send", amount.Address, "--value", amount.Amount.String(), "--json"}
}

account, ok := c.keystoreMap[keyName]
if !ok {
return "", fmt.Errorf("keyname (%s) not found", keyName)
}
cmd = append(cmd,
"--keystore", account.keystore,
"--password", "",
"--rpc-url", c.GetRPCAddress(),
)

account.txLock.Lock()
defer account.txLock.Unlock()
stdout, _, err := c.Exec(ctx, cmd, nil)
if err != nil {
return "", fmt.Errorf("send funds, exec, %w", err)
}

var txReceipt TransactionReceipt
if err = json.Unmarshal([]byte(strings.TrimSpace(string(stdout))), &txReceipt); err != nil {
return "", fmt.Errorf("tx receipt unmarshal:\n %s\nerror: %w", string(stdout), err)
}

return txReceipt.TxHash, nil
}

func (c *AnvilChain) BuildWallet(ctx context.Context, keyName string, mnemonic string) (ibc.Wallet, error) {
if mnemonic != "" {
err := c.RecoverKey(ctx, keyName, mnemonic)
if err != nil {
return nil, err
}
} else {
// Use the genesis account
if keyName == "faucet" {
mnemonic = "test test test test test test test test test test test junk"
err := c.RecoverKey(ctx, keyName, mnemonic)
if err != nil {
return nil, err
}
} else {
// Create new account
err := c.CreateKey(ctx, keyName)
if err != nil {
return nil, err
}
}
}

address, err := c.GetAddress(ctx, keyName)
if err != nil {
return nil, err
}
return ethereum.NewWallet(keyName, address, mnemonic), nil
}

type NodeWallet struct {
address string
keystore string
txLock sync.Mutex
}
36 changes: 36 additions & 0 deletions chain/ethereum/foundry/default_configs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package foundry

import (
"github.com/strangelove-ventures/interchaintest/v8/ibc"
)

func DefaultEthereumAnvilChainConfig(
name string,
) ibc.ChainConfig {
return ibc.ChainConfig{
Type: "ethereum",
Name: name,
ChainID: "31337", // default anvil chain-id
Bech32Prefix: "n/a",
CoinType: "60",
Denom: "wei",
GasPrices: "20000000000", // 20 gwei
GasAdjustment: 0,
TrustingPeriod: "0",
NoHostMount: false,
Images: []ibc.DockerImage{
{
Repository: "ghcr.io/foundry-rs/foundry",
Version: "latest",
UidGid: "1000:1000",
},
},
Bin: "anvil",
AdditionalStartArgs: []string{
"--block-time", "2", // 2 second block times
"--accounts", "10", // We current only use the first account for the faucet, but tests may expect the default
"--balance", "10000000", // Genesis accounts loaded with 10mil ether, change as needed
"--block-base-fee-per-gas", "0",
},
}
}
33 changes: 18 additions & 15 deletions chain/ethereum/forge.go → chain/ethereum/foundry/forge.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package ethereum
package foundry

import (
"context"
"fmt"
"os"
"path"
"path/filepath"
Expand All @@ -21,19 +22,15 @@ type ForgeScriptOpts struct {
}

// Add private-key or keystore to cmd
func (c *EthereumChain) AddKey(cmd []string, keyName string) []string {
// choose whether to use private-key or keystore
if keyName == "faucet" {
cmd = append(cmd,
"--private-key", "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
)

} else {
cmd = append(cmd,
"--keystores", c.keystoreMap[keyName],
"--password", "",
)
func (c *AnvilChain) AddKey(cmd []string, keyName string) []string {
account, ok := c.keystoreMap[keyName]
if !ok {
panic(fmt.Sprintf("Keyname (%s) not found", keyName))
}
cmd = append(cmd,
"--keystores", account.keystore,
"--password", "",
)
return cmd
}

Expand Down Expand Up @@ -78,7 +75,13 @@ func WriteConfigFile(configFile string, localContractRootDir string, solidityCon

// Run "forge script"
// see: https://book.getfoundry.sh/reference/forge/forge-script
func (c *EthereumChain) ForgeScript(ctx context.Context, keyName string, opts ForgeScriptOpts) (stdout, stderr []byte, err error) {
func (c *AnvilChain) ForgeScript(ctx context.Context, keyName string, opts ForgeScriptOpts) (stdout, stderr []byte, err error) {
account, ok := c.keystoreMap[keyName]
if !ok {
return nil, nil, fmt.Errorf("keyname (%s) not found", keyName)
}
account.txLock.Lock()
defer account.txLock.Unlock()
pwd, err := os.Getwd()
if err != nil {
return nil, nil, err
Expand All @@ -96,7 +99,7 @@ func (c *EthereumChain) ForgeScript(ctx context.Context, keyName string, opts Fo
return nil, nil, err
}

job := dockerutil.NewImage(c.logger(), c.DockerClient, c.NetworkID, c.testName, c.cfg.Images[0].Repository, c.cfg.Images[0].Version)
job := c.NewJob()
containerOpts := dockerutil.ContainerOptions{
Binds: c.Bind(),
Mounts: []mount.Mount{
Expand Down
Loading
Loading