-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: support for adding interop contracts to forked networks
- Loading branch information
1 parent
9528b8d
commit e37e0e6
Showing
9 changed files
with
176 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,127 @@ | ||
package genesis | ||
|
||
import ( | ||
"context" | ||
_ "embed" | ||
"encoding/json" | ||
"fmt" | ||
"math/big" | ||
"strings" | ||
"sync" | ||
|
||
"github.com/ethereum/go-ethereum/core" | ||
"github.com/ethereum-optimism/optimism/op-service/predeploys" | ||
|
||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/ethclient" | ||
) | ||
|
||
func ApplyChainID(genesisJson []byte, chainId *big.Int) ([]byte, error) { | ||
var genesis core.Genesis | ||
if err := json.Unmarshal(genesisJson, &genesis); err != nil { | ||
return nil, fmt.Errorf("unable to parse genesis json: %w", err) | ||
//go:embed generated/l2-allocs/901-l2-allocs.json | ||
var l2AllocsJSON []byte | ||
|
||
type alloc struct { | ||
Balance string `json:"balance"` | ||
Code string `json:"code"` | ||
Nonce string `json:"nonce"` | ||
Storage map[string]string `json:"storage"` | ||
} | ||
|
||
type allocs map[string]alloc | ||
|
||
type predeploy struct { | ||
proxy common.Address | ||
impl common.Address | ||
} | ||
|
||
var interopProxyPredeploys = []common.Address{ | ||
predeploys.CrossL2InboxAddr, | ||
predeploys.L2toL2CrossDomainMessengerAddr, | ||
predeploys.L1BlockAddr, | ||
} | ||
|
||
const ( | ||
emptyCode = "0x" | ||
) | ||
|
||
// Uses same logic as `predeployToCodeNamespace` in Predeploy.sol to determine impl address. | ||
func predeployToCodeNamespace(addr common.Address) common.Address { | ||
addrBigInt := new(big.Int).SetBytes(addr.Bytes()) | ||
|
||
namespaceBigInt := new(big.Int).SetBytes(common.FromHex("0xc0D3C0d3C0d3C0D3c0d3C0d3c0D3C0d3c0d30000")) | ||
resultBigInt := new(big.Int).Or(new(big.Int).And(addrBigInt, big.NewInt(0xffff)), namespaceBigInt) | ||
|
||
return common.BytesToAddress(resultBigInt.Bytes()) | ||
} | ||
|
||
func fetchAllocForAddr(addr common.Address, allocsJSON []byte) (*alloc, error) { | ||
var allocs allocs | ||
err := json.Unmarshal(allocsJSON, &allocs) | ||
if err != nil { | ||
return nil, fmt.Errorf("Failed to unmarshal allocs: %s", err) | ||
} | ||
|
||
alloc, exists := allocs[strings.ToLower(addr.String())] | ||
if !exists { | ||
return nil, fmt.Errorf("alloc not found: %s", addr) | ||
} | ||
|
||
if genesis.Config.ChainID.Cmp(chainId) != 0 { | ||
genesis.Config.ChainID = chainId | ||
return &alloc, nil | ||
} | ||
|
||
func applyAllocToAddress(ctx context.Context, rpcClient *ethclient.Client, alloc *alloc, address common.Address) error { | ||
if alloc.Code != emptyCode { | ||
err := rpcClient.Client().CallContext(ctx, nil, "anvil_setCode", address.Hex(), alloc.Code) | ||
if err != nil { | ||
return fmt.Errorf("failed to set code for %s: %w", address, err) | ||
} | ||
} | ||
if alloc.Storage != nil { | ||
for storageSlot, storageValue := range alloc.Storage { | ||
err := rpcClient.Client().CallContext(ctx, nil, "anvil_setStorageAt", address.Hex(), storageSlot, storageValue) | ||
if err != nil { | ||
return fmt.Errorf("failed to set storage for %s: %w", address, err) | ||
} | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func applyAllocForPredeploy(ctx context.Context, rpcClient *ethclient.Client, predeploy predeploy, allocsJSON []byte) error { | ||
implAlloc, err := fetchAllocForAddr(predeploy.impl, allocsJSON) | ||
if err != nil { | ||
return fmt.Errorf("failed to fetch alloc for %s: %w", predeploy.impl, err) | ||
} | ||
if err := applyAllocToAddress(ctx, rpcClient, implAlloc, predeploy.impl); err != nil { | ||
return fmt.Errorf("failed to apply alloc for %s: %w", predeploy.impl, err) | ||
} | ||
|
||
result, err := json.Marshal(genesis) | ||
proxyAlloc, err := fetchAllocForAddr(predeploy.proxy, allocsJSON) | ||
if err != nil { | ||
return nil, fmt.Errorf("error marshaling genesis: %w", err) | ||
return fmt.Errorf("failed to fetch alloc for %s: %w", predeploy.proxy, err) | ||
} | ||
if err := applyAllocToAddress(ctx, rpcClient, proxyAlloc, predeploy.proxy); err != nil { | ||
return fmt.Errorf("failed to apply alloc for %s: %w", predeploy.proxy, err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func ConfigureInteropForChain(ctx context.Context, rpcClient *ethclient.Client) { | ||
var interopPredeploys []predeploy | ||
for _, proxy := range interopProxyPredeploys { | ||
implContractAddress := predeployToCodeNamespace(proxy) | ||
interopPredeploys = append(interopPredeploys, predeploy{proxy: proxy, impl: implContractAddress}) | ||
} | ||
|
||
var wg sync.WaitGroup | ||
wg.Add(len(interopPredeploys)) | ||
for _, predeploy := range interopPredeploys { | ||
predeploy := predeploy | ||
go func() { | ||
defer wg.Done() | ||
applyAllocForPredeploy(ctx, rpcClient, predeploy, l2AllocsJSON) | ||
}() | ||
|
||
} | ||
|
||
return result, nil | ||
wg.Wait() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.