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

Fix signer registration via attestation #33

Merged
merged 3 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
46 changes: 32 additions & 14 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,39 @@ guard-%:

define abigen
echo "Generating bindings for $(1)"
jq -r '.bytecode.object' out/$(1).sol/$(1).json > out/$(1).sol/$(1).bin
cp out/$(1).sol/$(1).$(3).json out/$(1).sol/$(1).json 2>/dev/null || true
jq -r '.bytecode.object' out/$(1).sol/$(1).json > out/$(1).sol/$(1).bin
jq -r '.abi' out/$(1).sol/$(1).json > out/$(1).sol/$(1).abi
abigen --abi out/$(1).sol/$(1).abi --bin out/$(1).sol/$(1).bin --pkg bindings --type $(1) --out bindings/$(2).go
endef

define verify
deploy=$(1); \
version=$(2); \
addresses=$$(jq -r '.transactions[] | select(.transactionType=="CREATE" or .transactionType=="CREATE2") | .contractAddress' $$deploy); \
for address in $$addresses; do \
name=$$(jq -r --arg address "$$address" '.transactions[] | select((.transactionType=="CREATE" or .transactionType=="CREATE2") and .contractAddress==$$address) | .contractName' $$deploy); \
arguments=$$(jq -r --arg address "$$address" '.transactions[] | select((.transactionType=="CREATE" or .transactionType=="CREATE2") and .contractAddress==$$address) | .arguments // [] | join(" ")' $$deploy); \
namewithoutversion=$${name%.*.*.*}; \
constructor=$$(jq '.abi[] | select(.type=="constructor")' out/$$namewithoutversion.sol/$$name.json | jq -r '.inputs | map(.type) | join(",")'); \
echo; \
echo "Verifying $$namewithoutversion @ $$address using constructor($$constructor) $$arguments"; \
constructor_args=$$(cast abi-encode "constructor($$constructor)" $$arguments); \
forge verify-contract --compiler-version $$version --watch --verifier-url https://api-sepolia.basescan.org/api --constructor-args $$constructor_args $$address $$namewithoutversion ; \
done
endef

.PHONY: bindings
bindings:
go install github.com/ethereum/go-ethereum/cmd/[email protected]
forge build
mkdir -p bindings
@$(call abigen,"OutputOracle","output_oracle")
@$(call abigen,"Portal","portal")
@$(call abigen,"DeployChain","deploy_chain")
@$(call abigen,"OutputOracle","output_oracle","0.8.15")
@$(call abigen,"Portal","portal","0.8.15")
@$(call abigen,"DeployChain","deploy_chain","0.8.15")
@$(call abigen,"CertManager","cert_manager","0.8.15")
@$(call abigen,"SystemConfigGlobal","system_config_global","0.8.15")
@$(call abigen,"GnosisSafe","gnosis_safe","0.8.15")

.PHONY: deploy-cert-manager
deploy-cert-manager: guard-IMPL_SALT guard-DEPLOY_PRIVATE_KEY guard-RPC_URL
Expand All @@ -27,20 +47,18 @@ deploy: guard-IMPL_SALT guard-DEPLOY_CONFIG_PATH guard-DEPLOY_PRIVATE_KEY guard-
@forge script DeploySystem --sig deploy --rpc-url $(RPC_URL) \
--private-key $(DEPLOY_PRIVATE_KEY) --broadcast

.PHONY: deploy-deploy-chain
deploy-deploy-chain: guard-IMPL_SALT guard-DEPLOY_PRIVATE_KEY guard-RPC_URL
@forge script DeployDeployChain --rpc-url $(RPC_URL) \
--private-key $(DEPLOY_PRIVATE_KEY) --broadcast

.PHONY: testnet
testnet: guard-L1_URL guard-DEPLOY_PRIVATE_KEY
DEPLOY_CHAIN_ADDRESS=$${DEPLOY_CHAIN_ADDRESS:-$$(jq -r ".DeployChain" deployments/84532-deploy.json)} \
go run ./testnet

.PHONY: verify
verify:
deploy=broadcast/DeploySystem.s.sol/84532/run-1733867021.json; \
addresses=$$(jq -r '.transactions[] | select(.transactionType=="CREATE" or .transactionType=="CREATE2") | .contractAddress' $$deploy); \
for address in $$addresses; do \
name=$$(jq -r --arg address "$$address" '.transactions[] | select((.transactionType=="CREATE" or .transactionType=="CREATE2") and .contractAddress==$$address) | .contractName' $$deploy); \
arguments=$$(jq -r --arg address "$$address" '.transactions[] | select((.transactionType=="CREATE" or .transactionType=="CREATE2") and .contractAddress==$$address) | .arguments // [] | join(" ")' $$deploy); \
constructor=$$(jq '.abi[] | select(.type=="constructor")' out/$$name.sol/$$name.json | jq -r '.inputs | map(.type) | join(",")'); \
echo "Verifying $$name @ $$address using constructor($$constructor) $$arguments"; \
constructor_args=$$(cast abi-encode "constructor($$constructor)" $$arguments); \
forge verify-contract --watch --verifier-url https://api-sepolia.basescan.org/api --constructor-args $$constructor_args $$address $$name ; \
done
@$(call verify,"broadcast/DeployCertManager.s.sol/84532/run-1733890597.json","0.8.24")
@$(call verify,"broadcast/DeploySystem.s.sol/84532/run-1733867021.json","0.8.15")
@$(call verify,"broadcast/DeployDeployChain.s.sol/84532/run-1733884066.json","0.8.15")
595 changes: 595 additions & 0 deletions bindings/cert_manager.go

Large diffs are not rendered by default.

3,152 changes: 3,152 additions & 0 deletions bindings/gnosis_safe.go

Large diffs are not rendered by default.

1,295 changes: 1,295 additions & 0 deletions bindings/system_config_global.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion deployments/84532-certmanager.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"CertManager": "0x00a452e7B56052f0beC5EF863F77eDDfd81938C4"
"CertManager": "0xD42fd50A9A8eE3F127A11AEACD4ADAA67Da7FE3B"
}
4 changes: 2 additions & 2 deletions deployments/84532-deploy.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"AddressManager": "0xdcB1Ee2F0F35F8053C1EbD700c030180f7b2C14b",
"AnchorStateRegistryProxy": "0x0000000000000000000000000000000000000001",
"CertManager": "0x00a452e7B56052f0beC5EF863F77eDDfd81938C4",
"CertManager": "0xD42fd50A9A8eE3F127A11AEACD4ADAA67Da7FE3B",
"DelayedWETHProxy": "0x0000000000000000000000000000000000000001",
"DeployChain": "0x8B4dB9468126EA0AA6EC8f1FAEb32173de3A27c7",
"DisputeGameFactoryProxy": "0x0000000000000000000000000000000000000001",
Expand All @@ -27,7 +27,7 @@
"SuperchainConfig": "0xC77dB710C47b6e294D3d544572a10187e8Ef6b2C",
"SuperchainConfigProxy": "0xCf940f9c053092d07EB62DaB59D0AFddF426dE67",
"SystemConfig": "0x8aB8559E6C661eFEB0a44C0f08E180CEe344dABE",
"SystemConfigGlobal": "0x9C9a3B1c8676c1E0A6Ebb9402E7354930Bc52A59",
"SystemConfigGlobal": "0xc536C770BBEAfadb8dc8a0A1809A62cE96e7D822",
"SystemConfigGlobalProxy": "0x53200eC3d6E91E7Ba1fD1087D38430F43501C9Fb",
"SystemConfigProxy": "0x57708f73fF01e8697799B38f47Fbd65bDf9138Bc",
"SystemOwnerSafe": "0xFCD4AfF397A2F9D2a435B64AdA1A70efC59310aD"
Expand Down
2 changes: 1 addition & 1 deletion lib/nitro-validator
165 changes: 165 additions & 0 deletions register-signer/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package main

import (
"bytes"
"context"
"encoding/json"
"flag"
"fmt"
"os"
"time"

"github.com/base-org/op-enclave/bindings"
"github.com/base-org/op-enclave/op-withdrawer/withdrawals"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/hf/nitrite"
)

type deployment struct {
SystemConfigGlobalProxy common.Address `json:"SystemConfigGlobalProxy"`
}

func main() {
var attestationHex string
var rpcUrl string
var privateKeyHex string
var deploymentFile string
flag.StringVar(&attestationHex, "attestation", "", "attestation hex")
flag.StringVar(&rpcUrl, "rpc", "https://sepolia.base.org", "rpc url")
flag.StringVar(&privateKeyHex, "private-key", "", "private key")
flag.StringVar(&deploymentFile, "deployment", "deployments/84532-deploy.json", "deployment file")
flag.Parse()

if attestationHex == "" || privateKeyHex == "" {
flag.Usage()
os.Exit(1)
}

attestation, err := hexutil.Decode(attestationHex)
if err != nil {
panic(err)
}
privateKey, err := hexutil.Decode(privateKeyHex)
if err != nil {
panic(err)
}

res, err := nitrite.Verify(attestation, nitrite.VerifyOptions{})
if err != nil {
panic(err)
}

ctx := context.Background()
client, err := ethclient.DialContext(ctx, rpcUrl)
if err != nil {
panic(err)
}

deploy, err := os.ReadFile(deploymentFile)
if err != nil {
panic(err)
}
var d deployment
err = json.Unmarshal(deploy, &d)
if err != nil {
panic(err)
}

if bytes.Equal(common.Address{}.Bytes(), d.SystemConfigGlobalProxy.Bytes()) {
panic("SystemConfigGlobalProxy address not found in deployment file")
}

key, err := crypto.ToECDSA(privateKey)
if err != nil {
panic(err)
}

chainId, err := client.ChainID(ctx)
if err != nil {
panic(err)
}
signer := types.LatestSignerForChainID(chainId)
auth := &bind.TransactOpts{
From: crypto.PubkeyToAddress(key.PublicKey),
Signer: func(_ common.Address, tx *types.Transaction) (*types.Transaction, error) {
return types.SignTx(tx, signer, key)
},
}

systemConfigGlobal, err := bindings.NewSystemConfigGlobal(d.SystemConfigGlobalProxy, client)
if err != nil {
panic(err)
}

certManagerAddr, err := systemConfigGlobal.CertManager(&bind.CallOpts{})
if err != nil {
panic(err)
}
certManager, err := bindings.NewCertManager(certManagerAddr, client)
if err != nil {
panic(err)
}

verifyCert := func(cert []byte, ca bool, parentCertHash common.Hash) common.Hash {
certHash := crypto.Keccak256Hash(cert)
verified, err := certManager.Verified(&bind.CallOpts{}, certHash)
if err != nil {
panic(err)
}
if len(verified) == 0 {
tx, err := certManager.VerifyCert(auth, cert, ca, parentCertHash)
if err != nil {
panic(err)
}
receipt, err := withdrawals.WaitForReceipt(ctx, client, tx.Hash(), 2*time.Second)
if err != nil {
panic(err)
}
fmt.Printf("Verified cert: %s, tx: %s\n", certHash.String(), receipt.TxHash.String())
} else {
fmt.Printf("Cert already verified: %s\n", certHash.String())
}
return certHash
}

parentCertHash := crypto.Keccak256Hash(res.Document.CABundle[0])
for i := 0; i < len(res.Document.CABundle); i++ {
cert := res.Document.CABundle[i]
parentCertHash = verifyCert(cert, true, parentCertHash)
}
verifyCert(res.Document.Certificate, false, parentCertHash)

pcr0Hash := crypto.Keccak256Hash(res.Document.PCRs[0])
valid, err := systemConfigGlobal.ValidPCR0s(&bind.CallOpts{}, pcr0Hash)
if err != nil {
panic(err)
}
if !valid {
tx, err := systemConfigGlobal.RegisterPCR0(auth, res.Document.PCRs[0])
if err != nil {
panic(err)
}
receipt, err := withdrawals.WaitForReceipt(ctx, client, tx.Hash(), 2*time.Second)
if err != nil {
panic(err)
}
fmt.Printf("Registered PCR0, tx: %s\n", receipt.TxHash.String())
} else {
fmt.Printf("PCR0 already registered: %s\n", pcr0Hash.String())
}

tx, err := systemConfigGlobal.RegisterSigner(auth, res.COSESign1, res.Signature)
if err != nil {
panic(err)
}
receipt, err := withdrawals.WaitForReceipt(ctx, client, tx.Hash(), 2*time.Second)
if err != nil {
panic(err)
}
fmt.Printf("Registered signer, tx: %s\n", receipt.TxHash.String())
}
47 changes: 47 additions & 0 deletions script/UpgradeSystemConfigGlobal.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import {Script} from "forge-std/Script.sol";
import {console2 as console} from "forge-std/console2.sol";
import {DeployChain} from "../src/DeployChain.sol";
import {Artifacts} from "@eth-optimism-bedrock/scripts/Artifacts.s.sol";
import {ProxyAdmin} from "@eth-optimism-bedrock/src/universal/ProxyAdmin.sol";
import {SystemConfigGlobal} from "../src/SystemConfigGlobal.sol";
import {ICertManager} from "@nitro-validator/ICertManager.sol";
import {IGnosisSafe, Enum} from "@eth-optimism-bedrock/scripts/interfaces/IGnosisSafe.sol";

contract UpgradeSystemConfigGlobal is Script, Artifacts {
function run() public {
_loadAddresses(deploymentOutfile);

bytes memory signature = abi.encodePacked(uint256(uint160(msg.sender)), bytes32(0), uint8(1));

console.log("Deploying SystemConfigGlobal implementation");
vm.startBroadcast();

address addr_ = address(new SystemConfigGlobal{salt: _implSalt()}(ICertManager(mustGetAddress("CertManager"))));
bytes memory data =
abi.encodeCall(ProxyAdmin.upgrade, (payable(mustGetAddress("SystemConfigGlobalProxy")), address(addr_)));
IGnosisSafe(mustGetAddress("SystemOwnerSafe")).execTransaction({
to: mustGetAddress("ProxyAdmin"),
value: 0,
data: data,
operation: Enum.Operation.Call,
safeTxGas: 0,
baseGas: 0,
gasPrice: 0,
gasToken: address(0),
refundReceiver: payable(address(0)),
signatures: signature
});

vm.stopBroadcast();

delete _namedDeployments["SystemConfigGlobal"];
save("SystemConfigGlobal", addr_);
}

function _implSalt() internal view returns (bytes32 _env) {
_env = keccak256(bytes(vm.envOr("IMPL_SALT", string("ethers phoenix"))));
}
}
Loading