diff --git a/arbitrator/prover/src/kzgbn254.rs b/arbitrator/prover/src/kzgbn254.rs index a488ad1a2..47bdc3d47 100644 --- a/arbitrator/prover/src/kzgbn254.rs +++ b/arbitrator/prover/src/kzgbn254.rs @@ -8,24 +8,42 @@ use kzgbn254::{blob::Blob, kzg::Kzg, polynomial::PolynomialFormat}; use num::BigUint; use sha2::{Digest, Sha256}; use sha3::Keccak256; +use std::env; use std::io::Write; +use std::path::PathBuf; lazy_static::lazy_static! { - - // note that we are loading 3000 for testing purposes atm, but for production use these values: - // g1 and g2 points from the operator setup guide - // srs_order = 268435456 // srs_points_to_load = 131072 (65536 is enough) - pub static ref KZG: Kzg = Kzg::setup( - "./arbitrator/prover/src/mainnet-files/g1.point.65536", - "./arbitrator/prover/src/mainnet-files/g2.point.65536", - "./arbitrator/prover/src/mainnet-files/g2.point.powerOf2", + pub static ref KZG_BN254_SETTINGS: Kzg = Kzg::setup( + &load_directory_with_prefix("src/mainnet-files/g1.point.65536"), + &load_directory_with_prefix("src/mainnet-files/g2.point.65536"), + &load_directory_with_prefix("src/mainnet-files/g2.point.powerOf2"), 268435456, 65536 ).unwrap(); } +// Necessary helper function for understanding if srs is being loaded for normal node operation +// or for challenge testing. +fn load_directory_with_prefix(directory_name: &str) -> String { + let cwd = env::current_dir().expect("Failed to get current directory"); + return match cwd { + cwd if cwd.ends_with("system_tests") => { + return PathBuf::from("../arbitrator/prover/") + .join(directory_name) + .to_string_lossy() + .into_owned(); + } + _ => { + return PathBuf::from("./arbitrator/prover/") + .join(directory_name) + .to_string_lossy() + .into_owned(); + } + }; +} + /// Creates a KZG preimage proof consumable by the point evaluation precompile. pub fn prove_kzg_preimage_bn254( hash: Bytes32, @@ -33,8 +51,7 @@ pub fn prove_kzg_preimage_bn254( offset: u32, out: &mut impl Write, ) -> Result<()> { - let mut kzg = KZG.clone(); - + let mut kzg = KZG_BN254_SETTINGS.clone(); // expand roots of unity kzg.calculate_roots_of_unity(preimage.len() as u64)?; diff --git a/arbitrator/prover/src/machine.rs b/arbitrator/prover/src/machine.rs index 6efabc027..2da5d25e6 100644 --- a/arbitrator/prover/src/machine.rs +++ b/arbitrator/prover/src/machine.rs @@ -2448,7 +2448,7 @@ impl Machine { hash.red(), ); self.print_backtrace(true); - bail!("missing requested preimage for hash when stepping machine forward {}", hash); + bail!("missing requested preimage for hash {}", hash); }; if preimage_ty == PreimageType::EthVersionedHash diff --git a/arbitrator/prover/src/utils.rs b/arbitrator/prover/src/utils.rs index 7d9b6d3fb..cddbc2e12 100644 --- a/arbitrator/prover/src/utils.rs +++ b/arbitrator/prover/src/utils.rs @@ -3,13 +3,14 @@ #[cfg(feature = "native")] use crate::kzg::ETHEREUM_KZG_SETTINGS; +use crate::kzgbn254::KZG_BN254_SETTINGS; use arbutil::PreimageType; use ark_serialize::CanonicalSerialize; #[cfg(feature = "native")] use c_kzg::{Blob, KzgCommitment}; use digest::Digest; use eyre::{eyre, Result}; -use kzgbn254::{blob::Blob as EigenDABlob, kzg::Kzg as KzgBN254, polynomial::PolynomialFormat}; +use kzgbn254::{blob::Blob as EigenDABlob, polynomial::PolynomialFormat}; use num::BigUint; use serde::{Deserialize, Serialize}; use sha2::Sha256; @@ -201,6 +202,33 @@ pub fn append_left_padded_biguint_be(vec: &mut Vec, biguint: &BigUint) { vec.extend_from_slice(&bytes); } +pub fn append_left_padded_uint32_be(vec: &mut Vec, uint32: &u32) { + let bytes = uint32.to_be_bytes(); + vec.extend_from_slice(&bytes); +} + +pub fn hash_eigenda_preimage(preimage: &[u8]) -> Result<[u8; 32]> { + let blob = EigenDABlob::from_padded_bytes_unchecked(preimage); + + let blob_polynomial = blob.to_polynomial(PolynomialFormat::InCoefficientForm)?; + let blob_commitment = KZG_BN254_SETTINGS.commit(&blob_polynomial)?; + + let commitment_x_bigint: BigUint = blob_commitment.x.into(); + let commitment_y_bigint: BigUint = blob_commitment.y.into(); + let length_uint32: u32 = blob.len() as u32; + + let mut commitment_length_encoded_bytes = Vec::with_capacity(68); + append_left_padded_biguint_be(&mut commitment_length_encoded_bytes, &commitment_x_bigint); + append_left_padded_biguint_be(&mut commitment_length_encoded_bytes, &commitment_y_bigint); + append_left_padded_uint32_be(&mut commitment_length_encoded_bytes, &length_uint32); + + let mut keccak256_hasher = Keccak256::new(); + keccak256_hasher.update(&commitment_length_encoded_bytes); + let commitment_hash: [u8; 32] = keccak256_hasher.finalize().into(); + + Ok(commitment_hash) +} + #[cfg(feature = "native")] pub fn hash_preimage(preimage: &[u8], ty: PreimageType) -> Result<[u8; 32]> { match ty { @@ -216,42 +244,9 @@ pub fn hash_preimage(preimage: &[u8], ty: PreimageType) -> Result<[u8; 32]> { Ok(commitment_hash) } PreimageType::EigenDAHash => { - let kzg_bn254: KzgBN254 = KzgBN254::setup( - "./arbitrator/prover/src/mainnet-files/g1.point.65536", - "./arbitrator/prover/src/mainnet-files/g2.point.65536", - "./arbitrator/prover/src/mainnet-files/g2.point.powerOf2", - 268435456, - 65536, - ) - .unwrap(); - - let blob = EigenDABlob::from_padded_bytes_unchecked(preimage); - - let blob_polynomial = blob.to_polynomial(PolynomialFormat::InCoefficientForm)?; - let blob_commitment = kzg_bn254.commit(&blob_polynomial)?; - - let commitment_x_bigint: BigUint = blob_commitment.x.into(); - let commitment_y_bigint: BigUint = blob_commitment.y.into(); - let length_bigint: BigUint = blob.len().into(); - // 32 bytes per each commitment coordinate (64 bytes) - // 25 bits for length considering 32mb blobs padded to nearest power of 2 (2^25) - // pad to 32 bits or 4 bytes so 68 bytes total - let mut commitment_length_encoded_bytes = Vec::with_capacity(68); - append_left_padded_biguint_be( - &mut commitment_length_encoded_bytes, - &commitment_x_bigint, - ); - append_left_padded_biguint_be( - &mut commitment_length_encoded_bytes, - &commitment_y_bigint, - ); - append_left_padded_biguint_be(&mut commitment_length_encoded_bytes, &length_bigint); - - let mut keccak256_hasher = Keccak256::new(); - keccak256_hasher.update(&commitment_length_encoded_bytes); - let commitment_hash: [u8; 32] = keccak256_hasher.finalize().into(); + let hash = hash_eigenda_preimage(preimage)?; - Ok(commitment_hash) + Ok(hash) } } } diff --git a/arbnode/batch_poster.go b/arbnode/batch_poster.go index 8a7f4f8d9..5273a6cd2 100644 --- a/arbnode/batch_poster.go +++ b/arbnode/batch_poster.go @@ -955,10 +955,10 @@ func (b *BatchPoster) encodeAddBatch( methodName := sequencerBatchPostMethodName if use4844 { methodName = sequencerBatchPostWithBlobsMethodName - } - if useEigenDA { + } else if useEigenDA { methodName = sequencerBatchPostWithEigendaMethodName } + method, ok := b.seqInboxABI.Methods[methodName] if !ok { return nil, nil, errors.New("failed to find add batch method") @@ -981,54 +981,6 @@ func (b *BatchPoster) encodeAddBatch( ) } else if useEigenDA { - blobVerificationProofType, err := abi.NewType("tuple", "", []abi.ArgumentMarshaling{ - {Name: "batchID", Type: "uint32"}, - {Name: "blobIndex", Type: "uint32"}, - {Name: "batchMetadata", Type: "tuple", - Components: []abi.ArgumentMarshaling{ - {Name: "batchHeader", Type: "tuple", - Components: []abi.ArgumentMarshaling{ - {Name: "blobHeadersRoot", Type: "bytes32"}, - {Name: "quorumNumbers", Type: "bytes"}, - {Name: "signedStakeForQuorums", Type: "bytes"}, - {Name: "referenceBlockNumber", Type: "uint32"}, - }, - }, - {Name: "signatoryRecordHash", Type: "bytes32"}, - {Name: "confirmationBlockNumber", Type: "uint32"}, - }, - }, - { - Name: "inclusionProof", - Type: "bytes", - }, - { - Name: "quorumIndices", - Type: "bytes", - }, - }) - - if err != nil { - return nil, nil, err - } - - blobHeaderType, err := abi.NewType("tuple", "", []abi.ArgumentMarshaling{ - {Name: "commitment", Type: "tuple", Components: []abi.ArgumentMarshaling{ - {Name: "X", Type: "uint256"}, - {Name: "Y", Type: "uint256"}, - }}, - {Name: "dataLength", Type: "uint32"}, - {Name: "quorumBlobParams", Type: "tuple[]", Components: []abi.ArgumentMarshaling{ - {Name: "quorumNumber", Type: "uint8"}, - {Name: "adversaryThresholdPercentage", Type: "uint8"}, - {Name: "confirmationThresholdPercentage", Type: "uint8"}, - {Name: "chunkLength", Type: "uint32"}, - }}, - }) - if err != nil { - return nil, nil, err - } - addressType, err := abi.NewType("address", "", nil) if err != nil { return nil, nil, err @@ -1042,23 +994,20 @@ func (b *BatchPoster) encodeAddBatch( // Create ABI arguments arguments := abi.Arguments{ {Type: uint256Type}, - {Type: blobVerificationProofType}, - {Type: blobHeaderType}, + {Type: eigenda.DACertTypeABI}, {Type: addressType}, {Type: uint256Type}, {Type: uint256Type}, {Type: uint256Type}, } - // define values array - values := make([]interface{}, 7) + values := make([]interface{}, 6) values[0] = seqNum - values[1] = eigenDaBlobInfo.BlobVerificationProof - values[2] = eigenDaBlobInfo.BlobHeader - values[3] = b.config().gasRefunder - values[4] = new(big.Int).SetUint64(delayedMsg) - values[5] = new(big.Int).SetUint64(uint64(prevMsgNum)) - values[6] = new(big.Int).SetUint64(uint64(newMsgNum)) + values[1] = eigenDaBlobInfo + values[2] = b.config().gasRefunder + values[3] = new(big.Int).SetUint64(delayedMsg) + values[4] = new(big.Int).SetUint64(uint64(prevMsgNum)) + values[5] = new(big.Int).SetUint64(uint64(newMsgNum)) calldata, err = arguments.PackValues(values) diff --git a/arbnode/sequencer_inbox.go b/arbnode/sequencer_inbox.go index 6af0eb310..946896c75 100644 --- a/arbnode/sequencer_inbox.go +++ b/arbnode/sequencer_inbox.go @@ -6,6 +6,7 @@ package arbnode import ( "context" "encoding/binary" + "encoding/json" "errors" "fmt" "math/big" @@ -17,6 +18,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/offchainlabs/nitro/arbstate/daprovider" "github.com/offchainlabs/nitro/arbutil" + "github.com/offchainlabs/nitro/eigenda" "github.com/offchainlabs/nitro/solgen/go/bridgegen" ) @@ -25,6 +27,7 @@ var sequencerBridgeABI *abi.ABI var batchDeliveredID common.Hash var addSequencerL2BatchFromOriginCallABI abi.Method var sequencerBatchDataABI abi.Event +var addSequencerBatchFromEigenDACallABI abi.Method const sequencerBatchDataEvent = "SequencerBatchData" @@ -46,6 +49,7 @@ func init() { } batchDeliveredID = sequencerBridgeABI.Events["SequencerBatchDelivered"].ID sequencerBatchDataABI = sequencerBridgeABI.Events[sequencerBatchDataEvent] + addSequencerBatchFromEigenDACallABI = sequencerBridgeABI.Methods["addSequencerL2BatchFromEigenDA"] addSequencerL2BatchFromOriginCallABI = sequencerBridgeABI.Methods["addSequencerL2BatchFromOrigin0"] } @@ -174,15 +178,50 @@ func (m *SequencerInboxBatch) getSequencerData(ctx context.Context, client arbut } calldata := tx.Data() - data := []byte{daprovider.EigenDAMessageHeaderFlag} - data = append(data, calldata...) - return data, nil + args := make(map[string]interface{}) + err = addSequencerBatchFromEigenDACallABI.Inputs.UnpackIntoMap(args, calldata[4:]) + if err != nil { + return nil, err + } + + certBytes, err := interfaceToBytesJSON(args["cert"]) + if err != nil { + return nil, err + } + + var blobInfo eigenda.EigenDABlobInfo + err = json.Unmarshal(certBytes, &blobInfo) + if err != nil { + return nil, err + } + + arguments := abi.Arguments{ + {Type: eigenda.DACertTypeABI}, + } + + b, err := arguments.Pack(blobInfo) + if err != nil { + return nil, err + } + + msgData := []byte{daprovider.EigenDAMessageHeaderFlag} + msgData = append(msgData, b...) + + return msgData, nil default: return nil, fmt.Errorf("batch has invalid data location %v", m.dataLocation) } } +func interfaceToBytesJSON(data interface{}) ([]byte, error) { + bytes, err := json.Marshal(data) + if err != nil { + return nil, err + } + return bytes, nil +} + func (m *SequencerInboxBatch) Serialize(ctx context.Context, client arbutil.L1Interface) ([]byte, error) { if m.serialized != nil { return m.serialized, nil diff --git a/contracts b/contracts index 5965f44e5..cd08265c9 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 5965f44e581a31e1d54cefb365c2c8b517109209 +Subproject commit cd08265c98035a49d5d11d7e167232139e73a773 diff --git a/eigenda/eigenda.go b/eigenda/eigenda.go index 4218617c9..85acb5edb 100644 --- a/eigenda/eigenda.go +++ b/eigenda/eigenda.go @@ -1,28 +1,14 @@ package eigenda import ( - "bytes" "context" "errors" - "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" "github.com/offchainlabs/nitro/arbstate/daprovider" ) -var sequencerInboxABI abi.ABI - -func init() { - var err error - rawABI := `[{"type":"constructor","inputs":[{"name":"_maxDataSize","type":"uint256","internalType":"uint256"},{"name":"reader4844_","type":"address","internalType":"contract IReader4844"},{"name":"eigenDAServiceManager_","type":"address","internalType":"contract IEigenDAServiceManager"},{"name":"eigenDARollupManager_","type":"address","internalType":"contract IRollupManager"},{"name":"_isUsingFeeToken","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"type":"function","name":"BROTLI_MESSAGE_HEADER_FLAG","inputs":[],"outputs":[{"name":"","type":"bytes1","internalType":"bytes1"}],"stateMutability":"view"},{"type":"function","name":"DAS_MESSAGE_HEADER_FLAG","inputs":[],"outputs":[{"name":"","type":"bytes1","internalType":"bytes1"}],"stateMutability":"view"},{"type":"function","name":"DATA_AUTHENTICATED_FLAG","inputs":[],"outputs":[{"name":"","type":"bytes1","internalType":"bytes1"}],"stateMutability":"view"},{"type":"function","name":"DATA_BLOB_HEADER_FLAG","inputs":[],"outputs":[{"name":"","type":"bytes1","internalType":"bytes1"}],"stateMutability":"view"},{"type":"function","name":"EIGENDA_MESSAGE_HEADER_FLAG","inputs":[],"outputs":[{"name":"","type":"bytes1","internalType":"bytes1"}],"stateMutability":"view"},{"type":"function","name":"HEADER_LENGTH","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"TREE_DAS_MESSAGE_HEADER_FLAG","inputs":[],"outputs":[{"name":"","type":"bytes1","internalType":"bytes1"}],"stateMutability":"view"},{"type":"function","name":"ZERO_HEAVY_MESSAGE_HEADER_FLAG","inputs":[],"outputs":[{"name":"","type":"bytes1","internalType":"bytes1"}],"stateMutability":"view"},{"type":"function","name":"addSequencerL2Batch","inputs":[{"name":"sequenceNumber","type":"uint256","internalType":"uint256"},{"name":"data","type":"bytes","internalType":"bytes"},{"name":"afterDelayedMessagesRead","type":"uint256","internalType":"uint256"},{"name":"gasRefunder","type":"address","internalType":"contract IGasRefunder"},{"name":"prevMessageCount","type":"uint256","internalType":"uint256"},{"name":"newMessageCount","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"addSequencerL2BatchFromBlobs","inputs":[{"name":"sequenceNumber","type":"uint256","internalType":"uint256"},{"name":"afterDelayedMessagesRead","type":"uint256","internalType":"uint256"},{"name":"gasRefunder","type":"address","internalType":"contract IGasRefunder"},{"name":"prevMessageCount","type":"uint256","internalType":"uint256"},{"name":"newMessageCount","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"addSequencerL2BatchFromEigenDA","inputs":[{"name":"sequenceNumber","type":"uint256","internalType":"uint256"},{"name":"blobVerificationProof","type":"tuple","internalType":"struct EigenDARollupUtils.BlobVerificationProof","components":[{"name":"batchId","type":"uint32","internalType":"uint32"},{"name":"blobIndex","type":"uint32","internalType":"uint32"},{"name":"batchMetadata","type":"tuple","internalType":"struct IEigenDAServiceManager.BatchMetadata","components":[{"name":"batchHeader","type":"tuple","internalType":"struct IEigenDAServiceManager.BatchHeader","components":[{"name":"blobHeadersRoot","type":"bytes32","internalType":"bytes32"},{"name":"quorumNumbers","type":"bytes","internalType":"bytes"},{"name":"signedStakeForQuorums","type":"bytes","internalType":"bytes"},{"name":"referenceBlockNumber","type":"uint32","internalType":"uint32"}]},{"name":"signatoryRecordHash","type":"bytes32","internalType":"bytes32"},{"name":"confirmationBlockNumber","type":"uint32","internalType":"uint32"}]},{"name":"inclusionProof","type":"bytes","internalType":"bytes"},{"name":"quorumIndices","type":"bytes","internalType":"bytes"}]},{"name":"blobHeader","type":"tuple","internalType":"struct IEigenDAServiceManager.BlobHeader","components":[{"name":"commitment","type":"tuple","internalType":"struct BN254.G1Point","components":[{"name":"X","type":"uint256","internalType":"uint256"},{"name":"Y","type":"uint256","internalType":"uint256"}]},{"name":"dataLength","type":"uint32","internalType":"uint32"},{"name":"quorumBlobParams","type":"tuple[]","internalType":"struct IEigenDAServiceManager.QuorumBlobParam[]","components":[{"name":"quorumNumber","type":"uint8","internalType":"uint8"},{"name":"adversaryThresholdPercentage","type":"uint8","internalType":"uint8"},{"name":"confirmationThresholdPercentage","type":"uint8","internalType":"uint8"},{"name":"chunkLength","type":"uint32","internalType":"uint32"}]}]},{"name":"gasRefunder","type":"address","internalType":"contract IGasRefunder"},{"name":"afterDelayedMessagesRead","type":"uint256","internalType":"uint256"},{"name":"prevMessageCount","type":"uint256","internalType":"uint256"},{"name":"newMessageCount","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"addSequencerL2BatchFromOrigin","inputs":[{"name":"","type":"uint256","internalType":"uint256"},{"name":"","type":"bytes","internalType":"bytes"},{"name":"","type":"uint256","internalType":"uint256"},{"name":"","type":"address","internalType":"contract IGasRefunder"}],"outputs":[],"stateMutability":"pure"},{"type":"function","name":"addSequencerL2BatchFromOrigin","inputs":[{"name":"sequenceNumber","type":"uint256","internalType":"uint256"},{"name":"data","type":"bytes","internalType":"bytes"},{"name":"afterDelayedMessagesRead","type":"uint256","internalType":"uint256"},{"name":"gasRefunder","type":"address","internalType":"contract IGasRefunder"},{"name":"prevMessageCount","type":"uint256","internalType":"uint256"},{"name":"newMessageCount","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"batchCount","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"batchPosterManager","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"bridge","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract IBridge"}],"stateMutability":"view"},{"type":"function","name":"dasKeySetInfo","inputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"isValidKeyset","type":"bool","internalType":"bool"},{"name":"creationBlock","type":"uint64","internalType":"uint64"}],"stateMutability":"view"},{"type":"function","name":"eigenDARollupManager","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract IRollupManager"}],"stateMutability":"view"},{"type":"function","name":"eigenDAServiceManager","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract IEigenDAServiceManager"}],"stateMutability":"view"},{"type":"function","name":"forceInclusion","inputs":[{"name":"_totalDelayedMessagesRead","type":"uint256","internalType":"uint256"},{"name":"kind","type":"uint8","internalType":"uint8"},{"name":"l1BlockAndTime","type":"uint64[2]","internalType":"uint64[2]"},{"name":"baseFeeL1","type":"uint256","internalType":"uint256"},{"name":"sender","type":"address","internalType":"address"},{"name":"messageDataHash","type":"bytes32","internalType":"bytes32"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"getKeysetCreationBlock","inputs":[{"name":"ksHash","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"inboxAccs","inputs":[{"name":"index","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"initialize","inputs":[{"name":"bridge_","type":"address","internalType":"contract IBridge"},{"name":"maxTimeVariation_","type":"tuple","internalType":"struct ISequencerInbox.MaxTimeVariation","components":[{"name":"delayBlocks","type":"uint256","internalType":"uint256"},{"name":"futureBlocks","type":"uint256","internalType":"uint256"},{"name":"delaySeconds","type":"uint256","internalType":"uint256"},{"name":"futureSeconds","type":"uint256","internalType":"uint256"}]}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"invalidateKeysetHash","inputs":[{"name":"ksHash","type":"bytes32","internalType":"bytes32"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"isBatchPoster","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"isSequencer","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"isUsingFeeToken","inputs":[],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"isValidKeysetHash","inputs":[{"name":"ksHash","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"maxDataSize","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"maxTimeVariation","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"},{"name":"","type":"uint256","internalType":"uint256"},{"name":"","type":"uint256","internalType":"uint256"},{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"postUpgradeInit","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"reader4844","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract IReader4844"}],"stateMutability":"view"},{"type":"function","name":"removeDelayAfterFork","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"rollup","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract IOwnable"}],"stateMutability":"view"},{"type":"function","name":"setBatchPosterManager","inputs":[{"name":"newBatchPosterManager","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setIsBatchPoster","inputs":[{"name":"addr","type":"address","internalType":"address"},{"name":"isBatchPoster_","type":"bool","internalType":"bool"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setIsSequencer","inputs":[{"name":"addr","type":"address","internalType":"address"},{"name":"isSequencer_","type":"bool","internalType":"bool"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setMaxTimeVariation","inputs":[{"name":"maxTimeVariation_","type":"tuple","internalType":"struct ISequencerInbox.MaxTimeVariation","components":[{"name":"delayBlocks","type":"uint256","internalType":"uint256"},{"name":"futureBlocks","type":"uint256","internalType":"uint256"},{"name":"delaySeconds","type":"uint256","internalType":"uint256"},{"name":"futureSeconds","type":"uint256","internalType":"uint256"}]}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setValidKeyset","inputs":[{"name":"keysetBytes","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"totalDelayedMessagesRead","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"event","name":"InboxMessageDelivered","inputs":[{"name":"messageNum","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"data","type":"bytes","indexed":false,"internalType":"bytes"}],"anonymous":false},{"type":"event","name":"InboxMessageDeliveredFromOrigin","inputs":[{"name":"messageNum","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"InvalidateKeyset","inputs":[{"name":"keysetHash","type":"bytes32","indexed":true,"internalType":"bytes32"}],"anonymous":false},{"type":"event","name":"OwnerFunctionCalled","inputs":[{"name":"id","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"SequencerBatchData","inputs":[{"name":"batchSequenceNumber","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"data","type":"bytes","indexed":false,"internalType":"bytes"}],"anonymous":false},{"type":"event","name":"SequencerBatchDelivered","inputs":[{"name":"batchSequenceNumber","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"beforeAcc","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"afterAcc","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"delayedAcc","type":"bytes32","indexed":false,"internalType":"bytes32"},{"name":"afterDelayedMessagesRead","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"timeBounds","type":"tuple","indexed":false,"internalType":"struct IBridge.TimeBounds","components":[{"name":"minTimestamp","type":"uint64","internalType":"uint64"},{"name":"maxTimestamp","type":"uint64","internalType":"uint64"},{"name":"minBlockNumber","type":"uint64","internalType":"uint64"},{"name":"maxBlockNumber","type":"uint64","internalType":"uint64"}]},{"name":"dataLocation","type":"uint8","indexed":false,"internalType":"enum IBridge.BatchDataLocation"}],"anonymous":false},{"type":"event","name":"SetValidKeyset","inputs":[{"name":"keysetHash","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"keysetBytes","type":"bytes","indexed":false,"internalType":"bytes"}],"anonymous":false},{"type":"error","name":"AlreadyInit","inputs":[]},{"type":"error","name":"AlreadyValidDASKeyset","inputs":[{"name":"","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"BadMaxTimeVariation","inputs":[]},{"type":"error","name":"BadPostUpgradeInit","inputs":[]},{"type":"error","name":"BadSequencerNumber","inputs":[{"name":"stored","type":"uint256","internalType":"uint256"},{"name":"received","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"DataBlobsNotSupported","inputs":[]},{"type":"error","name":"DataTooLarge","inputs":[{"name":"dataLength","type":"uint256","internalType":"uint256"},{"name":"maxDataLength","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"DelayedBackwards","inputs":[]},{"type":"error","name":"DelayedTooFar","inputs":[]},{"type":"error","name":"Deprecated","inputs":[]},{"type":"error","name":"ForceIncludeBlockTooSoon","inputs":[]},{"type":"error","name":"ForceIncludeTimeTooSoon","inputs":[]},{"type":"error","name":"HadZeroInit","inputs":[]},{"type":"error","name":"IncorrectMessagePreimage","inputs":[]},{"type":"error","name":"InitParamZero","inputs":[{"name":"name","type":"string","internalType":"string"}]},{"type":"error","name":"InvalidHeaderFlag","inputs":[{"name":"","type":"bytes1","internalType":"bytes1"}]},{"type":"error","name":"MissingDataHashes","inputs":[]},{"type":"error","name":"NativeTokenMismatch","inputs":[]},{"type":"error","name":"NoSuchKeyset","inputs":[{"name":"","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"NotBatchPoster","inputs":[]},{"type":"error","name":"NotBatchPosterManager","inputs":[{"name":"","type":"address","internalType":"address"}]},{"type":"error","name":"NotForked","inputs":[]},{"type":"error","name":"NotOrigin","inputs":[]},{"type":"error","name":"NotOwner","inputs":[{"name":"sender","type":"address","internalType":"address"},{"name":"owner","type":"address","internalType":"address"}]}]` - - sequencerInboxABI, err = abi.JSON(bytes.NewReader([]byte(rawABI))) - if err != nil { - panic(err) - } -} - const ( sequencerMsgOffset = 41 MaxBatchSize = 2_000_000 // 2MB diff --git a/eigenda/init.go b/eigenda/init.go new file mode 100644 index 000000000..604bbae54 --- /dev/null +++ b/eigenda/init.go @@ -0,0 +1,203 @@ +package eigenda + +import ( + "bytes" + + "github.com/ethereum/go-ethereum/accounts/abi" +) + +var DACertTypeABI abi.Type +var certDecodeABI abi.ABI + +func init() { + var err error + DACertTypeABI, err = abi.NewType("tuple", "", []abi.ArgumentMarshaling{ + {Name: "blobVerificationProof", Type: "tuple", Components: []abi.ArgumentMarshaling{ + {Name: "batchID", Type: "uint32"}, + {Name: "blobIndex", Type: "uint32"}, + {Name: "batchMetadata", Type: "tuple", + Components: []abi.ArgumentMarshaling{ + {Name: "batchHeader", Type: "tuple", + Components: []abi.ArgumentMarshaling{ + {Name: "blobHeadersRoot", Type: "bytes32"}, + {Name: "quorumNumbers", Type: "bytes"}, + {Name: "signedStakeForQuorums", Type: "bytes"}, + {Name: "referenceBlockNumber", Type: "uint32"}, + }, + }, + {Name: "signatoryRecordHash", Type: "bytes32"}, + {Name: "confirmationBlockNumber", Type: "uint32"}, + }, + }, + {Name: "inclusionProof", Type: "bytes"}, + {Name: "quorumIndices", Type: "bytes"}, + }}, + {Name: "blobHeader", Type: "tuple", Components: []abi.ArgumentMarshaling{ + {Name: "commitment", Type: "tuple", Components: []abi.ArgumentMarshaling{ + {Name: "X", Type: "uint256"}, + {Name: "Y", Type: "uint256"}, + }}, + {Name: "dataLength", Type: "uint32"}, + {Name: "quorumBlobParams", Type: "tuple[]", Components: []abi.ArgumentMarshaling{ + {Name: "quorumNumber", Type: "uint8"}, + {Name: "adversaryThresholdPercentage", Type: "uint8"}, + {Name: "confirmationThresholdPercentage", Type: "uint8"}, + {Name: "chunkLength", Type: "uint32"}, + }}, + }}, + }) + + if err != nil { + panic(err) + } + + certDecodeRawABI := `[ + { + "type": "function", + "name": "decodeCert", + "inputs": [ + { + "name": "cert", + "type": "tuple", + "internalType": "struct ISequencerInbox.DACert", + "components": [ + { + "name": "blobVerificationProof", + "type": "tuple", + "internalType": "struct EigenDARollupUtils.BlobVerificationProof", + "components": [ + { + "name": "batchId", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "blobIndex", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "batchMetadata", + "type": "tuple", + "internalType": "struct IEigenDAServiceManager.BatchMetadata", + "components": [ + { + "name": "batchHeader", + "type": "tuple", + "internalType": "struct IEigenDAServiceManager.BatchHeader", + "components": [ + { + "name": "blobHeadersRoot", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "quorumNumbers", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "signedStakeForQuorums", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "referenceBlockNumber", + "type": "uint32", + "internalType": "uint32" + } + ] + }, + { + "name": "signatoryRecordHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "confirmationBlockNumber", + "type": "uint32", + "internalType": "uint32" + } + ] + }, + { + "name": "inclusionProof", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "quorumIndices", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "blobHeader", + "type": "tuple", + "internalType": "struct IEigenDAServiceManager.BlobHeader", + "components": [ + { + "name": "commitment", + "type": "tuple", + "internalType": "struct BN254.G1Point", + "components": [ + { + "name": "X", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "Y", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "dataLength", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "quorumBlobParams", + "type": "tuple[]", + "internalType": "struct IEigenDAServiceManager.QuorumBlobParam[]", + "components": [ + { + "name": "quorumNumber", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "adversaryThresholdPercentage", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "confirmationThresholdPercentage", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "chunkLength", + "type": "uint32", + "internalType": "uint32" + } + ] + } + ] + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + } + ] + ` + certDecodeABI, err = abi.JSON(bytes.NewReader([]byte(certDecodeRawABI))) + if err != nil { + panic(err) + } +} diff --git a/eigenda/reader.go b/eigenda/reader.go index a5511ee03..9fa3877e9 100644 --- a/eigenda/reader.go +++ b/eigenda/reader.go @@ -3,7 +3,7 @@ package eigenda import ( "context" "encoding/binary" - "errors" + "encoding/json" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" @@ -53,7 +53,6 @@ func RecoverPayloadFromEigenDABatch(ctx context.Context, return nil, err } - println("Inserting data into preimage recorder") hash, err := blobInfo.PreimageHash() if err != nil { return nil, err @@ -70,35 +69,39 @@ func RecoverPayloadFromEigenDABatch(ctx context.Context, return data, nil } -// ParseSequencerMsg parses the inbox tx calldata into a structured EigenDABlobInfo +func interfaceToBytesJSON(data interface{}) ([]byte, error) { + bytes, err := json.Marshal(data) + if err != nil { + return nil, err + } + return bytes, nil +} + +// ParseSequencerMsg parses the certificate from the inbox message func ParseSequencerMsg(calldata []byte) (*EigenDABlobInfo, error) { - // this should never happen, but just in case - if len(calldata) < 4 { - return nil, errors.New("calldata is shorter than expected method signature length") - } + spoofedFunc := certDecodeABI.Methods["decodeCert"] - method, err := sequencerInboxABI.MethodById(calldata[0:4]) + m := make(map[string]interface{}) + err := spoofedFunc.Inputs.UnpackIntoMap(m, calldata) if err != nil { return nil, err } - callDataValues, err := method.Inputs.Unpack(calldata[4:]) + b, err := interfaceToBytesJSON(m["cert"]) if err != nil { return nil, err } - inboxPayload := &InboxPayload{} + // decode to EigenDABlobInfo + var blobInfo EigenDABlobInfo + err = json.Unmarshal(b, &blobInfo) - err = inboxPayload.Load(callDataValues) if err != nil { return nil, err } - return &EigenDABlobInfo{ - BlobVerificationProof: inboxPayload.BlobVerificationProof, - BlobHeader: inboxPayload.BlobHeader, - }, nil + return &blobInfo, nil } diff --git a/eigenda/types.go b/eigenda/types.go index 912c58fcc..12665e36c 100644 --- a/eigenda/types.go +++ b/eigenda/types.go @@ -1,7 +1,6 @@ package eigenda import ( - "errors" "math/big" "github.com/ethereum/go-ethereum/crypto" @@ -14,17 +13,19 @@ import ( /* Two rather redundant implementations of the same data structure exist: - - EigenDABlobInfo: represents the EigenDABlobInfo struct which is encoded in the calldata of the sequencer message for on-chain cert verification + - EigenDABlobInfo: represents the EigenDABlobInfo struct which is encoded in the calldata of the sequencer message for on-chain cert verification within the inbox - DisperserBlobInfo: represents the disperser.BlobInfo struct generated by the grpc disperser protobuf */ type EigenDABlobInfo struct { - BlobHeader BlobHeader `json:"blobHeader"` BlobVerificationProof BlobVerificationProof `json:"blobVerificationProof"` + BlobHeader BlobHeader `json:"blobHeader"` } /* -Unlike 4844 there's no need to inject a version byte into the 0th offset of the hash +Unlike 4844 there's no need to inject a version byte into the 0th offset of the hash. +Taking the hash of commitment + length is key to ensure no trust assumption on the data length +for one-step proving. */ func (e *EigenDABlobInfo) PreimageHash() (*common.Hash, error) { bytes, err := e.SerializeCommitment() @@ -301,7 +302,8 @@ func (e *EigenDABlobInfo) ToDisperserBlobInfo() (*DisperserBlobInfo, error) { } } - // set batchHeaderHash if not set + // set batchHeaderHash - this value is critical for indexing the blob but is lost + // when encoding the certificate to calldata for sequencer inbox submission from the BatchPoster batchHeaderHash, err := disperserBlobVerificationProof.BatchMetadata.BatchHeader.GetBatchHeaderHash() if err != nil { @@ -316,104 +318,6 @@ func (e *EigenDABlobInfo) ToDisperserBlobInfo() (*DisperserBlobInfo, error) { }, nil } -// InboxPayload is a structured representation of the calldata used for the EigenDA `addSequencerL2BatchFromEigenDA` method call -// for persisting certificates into the inbox sequence -type InboxPayload struct { - BlobVerificationProof BlobVerificationProof - BlobHeader BlobHeader -} - -// Load ingest loads calldata to a payload struct which explicitly defines the parsed -// calldata fields -func (ip *InboxPayload) Load(callDataValues []interface{}) error { - if len(callDataValues) != 7 { - return errors.New("calldata does not have the expected number of parameters") - } - - blobVerificationProof, passed := callDataValues[1].(struct { - BatchId uint32 `json:"batchId"` - BlobIndex uint32 `json:"blobIndex"` - BatchMetadata struct { - BatchHeader struct { - BlobHeadersRoot [32]uint8 `json:"blobHeadersRoot"` - QuorumNumbers []uint8 `json:"quorumNumbers"` - SignedStakeForQuorums []uint8 `json:"signedStakeForQuorums"` - ReferenceBlockNumber uint32 `json:"referenceBlockNumber"` - } `json:"batchHeader"` - SignatoryRecordHash [32]uint8 `json:"signatoryRecordHash"` - ConfirmationBlockNumber uint32 `json:"confirmationBlockNumber"` - } `json:"batchMetadata"` - InclusionProof []uint8 `json:"inclusionProof"` - QuorumIndices []uint8 `json:"quorumIndices"` - }) - - if !passed { - return errors.New("failed to parse blob verification proof") - } - - blobHeader, passed := callDataValues[2].(struct { - Commitment struct { - X *big.Int `json:"X"` - Y *big.Int `json:"Y"` - } `json:"commitment"` - DataLength uint32 `json:"dataLength"` - QuorumBlobParams []struct { - QuorumNumber uint8 `json:"quorumNumber"` - AdversaryThresholdPercentage uint8 `json:"adversaryThresholdPercentage"` - ConfirmationThresholdPercentage uint8 `json:"confirmationThresholdPercentage"` - ChunkLength uint32 `json:"chunkLength"` - } `json:"quorumBlobParams"` - }) - - if !passed { - return errors.New("failed to parse blob header") - } - - payload := InboxPayload{ - BlobVerificationProof: BlobVerificationProof{ - BatchID: blobVerificationProof.BatchId, - BlobIndex: blobVerificationProof.BlobIndex, - BatchMetadata: BatchMetadata{ - BatchHeader: BatchHeader{ - BlobHeadersRoot: blobVerificationProof.BatchMetadata.BatchHeader.BlobHeadersRoot, - QuorumNumbers: blobVerificationProof.BatchMetadata.BatchHeader.QuorumNumbers, - SignedStakeForQuorums: blobVerificationProof.BatchMetadata.BatchHeader.SignedStakeForQuorums, - ReferenceBlockNumber: blobVerificationProof.BatchMetadata.BatchHeader.ReferenceBlockNumber, - }, - Fee: []byte{}, - BatchHeaderHash: []byte{}, - - SignatoryRecordHash: blobVerificationProof.BatchMetadata.SignatoryRecordHash, - ConfirmationBlockNumber: blobVerificationProof.BatchMetadata.ConfirmationBlockNumber, - }, - InclusionProof: blobVerificationProof.InclusionProof, - QuorumIndices: blobVerificationProof.QuorumIndices, - }, - BlobHeader: BlobHeader{ - Commitment: G1Point{ - X: blobHeader.Commitment.X, - Y: blobHeader.Commitment.Y, - }, - DataLength: blobHeader.DataLength, - QuorumBlobParams: func() []QuorumBlobParams { - params := make([]QuorumBlobParams, len(blobHeader.QuorumBlobParams)) - for i, p := range blobHeader.QuorumBlobParams { - params[i] = QuorumBlobParams{ - QuorumNumber: p.QuorumNumber, - AdversaryThresholdPercentage: p.AdversaryThresholdPercentage, - ConfirmationThresholdPercentage: p.ConfirmationThresholdPercentage, - ChunkLength: p.ChunkLength, - } - } - return params - }(), - }, - } - - *ip = payload - return nil -} - // IsEmpty checks if BlobVerificationProof is effectively empty func (b BlobVerificationProof) IsEmpty() bool { return b.BatchID == 0 && diff --git a/staker/challenge_test.go b/staker/challenge_test.go index b86d37629..4534b04a2 100644 --- a/staker/challenge_test.go +++ b/staker/challenge_test.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/offchainlabs/nitro/solgen/go/mocksgen" "github.com/offchainlabs/nitro/solgen/go/ospgen" + "github.com/offchainlabs/nitro/validator" "github.com/offchainlabs/nitro/validator/server_arb" ) @@ -255,48 +256,48 @@ func createBaseMachine(t *testing.T, wasmname string, wasmModules []string) *ser return machine } -// func TestChallengeToOSP(t *testing.T) { -// machine := createBaseMachine(t, "global-state.wasm", []string{"global-state-wrapper.wasm"}) -// IncorrectMachine := server_arb.NewIncorrectMachine(machine, 200) -// runChallengeTest(t, machine, IncorrectMachine, false, false, 0) -// } - -// func TestChallengeToFailedOSP(t *testing.T) { -// machine := createBaseMachine(t, "global-state.wasm", []string{"global-state-wrapper.wasm"}) -// IncorrectMachine := server_arb.NewIncorrectMachine(machine, 200) -// runChallengeTest(t, machine, IncorrectMachine, true, false, 0) -// } - -// func TestChallengeToErroredOSP(t *testing.T) { -// machine := createBaseMachine(t, "const.wasm", nil) -// IncorrectMachine := server_arb.NewIncorrectMachine(machine, 10) -// runChallengeTest(t, machine, IncorrectMachine, false, false, 0) -// } - -// func TestChallengeToFailedErroredOSP(t *testing.T) { -// machine := createBaseMachine(t, "const.wasm", nil) -// IncorrectMachine := server_arb.NewIncorrectMachine(machine, 10) -// runChallengeTest(t, machine, IncorrectMachine, true, false, 0) -// } - -// func TestChallengeToTimeout(t *testing.T) { -// machine := createBaseMachine(t, "global-state.wasm", []string{"global-state-wrapper.wasm"}) -// IncorrectMachine := server_arb.NewIncorrectMachine(machine, 200) -// runChallengeTest(t, machine, IncorrectMachine, false, true, 0) -// } - -// func TestChallengeToTooFar(t *testing.T) { -// machine := createBaseMachine(t, "read-inboxmsg-10.wasm", []string{"global-state-wrapper.wasm"}) -// Require(t, machine.SetGlobalState(validator.GoGlobalState{PosInBatch: 10})) -// incorrectMachine := machine.Clone() -// Require(t, incorrectMachine.AddSequencerInboxMessage(10, []byte{0, 1, 2, 3})) -// runChallengeTest(t, machine, incorrectMachine, false, false, 9) -// } - -// func TestChallengeToFailedTooFar(t *testing.T) { -// machine := createBaseMachine(t, "read-inboxmsg-10.wasm", []string{"global-state-wrapper.wasm"}) -// Require(t, machine.SetGlobalState(validator.GoGlobalState{PosInBatch: 10})) -// incorrectMachine := machine.Clone() -// Require(t, machine.AddSequencerInboxMessage(10, []byte{0, 1, 2, 3})) -// runChallengeTest(t, machine, incorrectMachine, true, false, 11) -// } +func TestChallengeToOSP(t *testing.T) { + machine := createBaseMachine(t, "global-state.wasm", []string{"global-state-wrapper.wasm"}) + IncorrectMachine := server_arb.NewIncorrectMachine(machine, 200) + runChallengeTest(t, machine, IncorrectMachine, false, false, 0) +} + +func TestChallengeToFailedOSP(t *testing.T) { + machine := createBaseMachine(t, "global-state.wasm", []string{"global-state-wrapper.wasm"}) + IncorrectMachine := server_arb.NewIncorrectMachine(machine, 200) + runChallengeTest(t, machine, IncorrectMachine, true, false, 0) +} + +func TestChallengeToErroredOSP(t *testing.T) { + machine := createBaseMachine(t, "const.wasm", nil) + IncorrectMachine := server_arb.NewIncorrectMachine(machine, 10) + runChallengeTest(t, machine, IncorrectMachine, false, false, 0) +} + +func TestChallengeToFailedErroredOSP(t *testing.T) { + machine := createBaseMachine(t, "const.wasm", nil) + IncorrectMachine := server_arb.NewIncorrectMachine(machine, 10) + runChallengeTest(t, machine, IncorrectMachine, true, false, 0) +} + +func TestChallengeToTimeout(t *testing.T) { + machine := createBaseMachine(t, "global-state.wasm", []string{"global-state-wrapper.wasm"}) + IncorrectMachine := server_arb.NewIncorrectMachine(machine, 200) + runChallengeTest(t, machine, IncorrectMachine, false, true, 0) +} + +func TestChallengeToTooFar(t *testing.T) { + machine := createBaseMachine(t, "read-inboxmsg-10.wasm", []string{"global-state-wrapper.wasm"}) + Require(t, machine.SetGlobalState(validator.GoGlobalState{PosInBatch: 10})) + incorrectMachine := machine.Clone() + Require(t, incorrectMachine.AddSequencerInboxMessage(10, []byte{0, 1, 2, 3})) + runChallengeTest(t, machine, incorrectMachine, false, false, 9) +} + +func TestChallengeToFailedTooFar(t *testing.T) { + machine := createBaseMachine(t, "read-inboxmsg-10.wasm", []string{"global-state-wrapper.wasm"}) + Require(t, machine.SetGlobalState(validator.GoGlobalState{PosInBatch: 10})) + incorrectMachine := machine.Clone() + Require(t, machine.AddSequencerInboxMessage(10, []byte{0, 1, 2, 3})) + runChallengeTest(t, machine, incorrectMachine, true, false, 11) +} diff --git a/system_tests/full_challenge_impl_test.go b/system_tests/full_challenge_impl_test.go index ecae8ebdc..a2a05e824 100644 --- a/system_tests/full_challenge_impl_test.go +++ b/system_tests/full_challenge_impl_test.go @@ -27,6 +27,7 @@ import ( "github.com/offchainlabs/nitro/arbos" "github.com/offchainlabs/nitro/arbos/arbostypes" "github.com/offchainlabs/nitro/arbstate" + "github.com/offchainlabs/nitro/arbstate/daprovider" "github.com/offchainlabs/nitro/arbutil" "github.com/offchainlabs/nitro/cmd/chaininfo" "github.com/offchainlabs/nitro/eigenda" @@ -203,8 +204,7 @@ func makeBatchEigenDA(t *testing.T, l2Node *arbnode.Node, l2Info *BlockchainTest seqNum := new(big.Int).Lsh(common.Big1, 256) seqNum.Sub(seqNum, common.Big1) - - // disperse batch to eigenda-proxy + // disperse batch to eigenda-proxy eigenDA, err := eigenda.NewEigenDA(&eigenda.EigenDAConfig{ Enable: true, @@ -217,33 +217,33 @@ func makeBatchEigenDA(t *testing.T, l2Node *arbnode.Node, l2Info *BlockchainTest Require(t, err) bh := mocksgen.IEigenDAServiceManagerBatchHeader{ - BlobHeadersRoot: blobInfo.BlobVerificationProof.BatchMetadata.BatchHeader.BlobHeadersRoot, - QuorumNumbers: blobInfo.BlobVerificationProof.BatchMetadata.BatchHeader.QuorumNumbers, + BlobHeadersRoot: blobInfo.BlobVerificationProof.BatchMetadata.BatchHeader.BlobHeadersRoot, + QuorumNumbers: blobInfo.BlobVerificationProof.BatchMetadata.BatchHeader.QuorumNumbers, SignedStakeForQuorums: blobInfo.BlobVerificationProof.BatchMetadata.BatchHeader.SignedStakeForQuorums, - ReferenceBlockNumber: blobInfo.BlobVerificationProof.BatchMetadata.BatchHeader.ReferenceBlockNumber, + ReferenceBlockNumber: blobInfo.BlobVerificationProof.BatchMetadata.BatchHeader.ReferenceBlockNumber, } bm := mocksgen.IEigenDAServiceManagerBatchMetadata{ - BatchHeader: bh, - SignatoryRecordHash: blobInfo.BlobVerificationProof.BatchMetadata.SignatoryRecordHash, + BatchHeader: bh, + SignatoryRecordHash: blobInfo.BlobVerificationProof.BatchMetadata.SignatoryRecordHash, ConfirmationBlockNumber: blobInfo.BlobVerificationProof.BatchMetadata.ConfirmationBlockNumber, } bvp := mocksgen.EigenDARollupUtilsBlobVerificationProof{ - BatchId: blobInfo.BlobVerificationProof.BatchID, - BlobIndex: blobInfo.BlobVerificationProof.BlobIndex, - BatchMetadata: bm, + BatchId: blobInfo.BlobVerificationProof.BatchID, + BlobIndex: blobInfo.BlobVerificationProof.BlobIndex, + BatchMetadata: bm, InclusionProof: blobInfo.BlobVerificationProof.InclusionProof, - QuorumIndices: blobInfo.BlobVerificationProof.QuorumIndices, + QuorumIndices: blobInfo.BlobVerificationProof.QuorumIndices, } solQps := make([]mocksgen.IEigenDAServiceManagerQuorumBlobParam, len(blobInfo.BlobHeader.QuorumBlobParams)) for _, qp := range blobInfo.BlobHeader.QuorumBlobParams { solQps = append(solQps, mocksgen.IEigenDAServiceManagerQuorumBlobParam{ - QuorumNumber: qp.QuorumNumber, - AdversaryThresholdPercentage: qp.AdversaryThresholdPercentage, + QuorumNumber: qp.QuorumNumber, + AdversaryThresholdPercentage: qp.AdversaryThresholdPercentage, ConfirmationThresholdPercentage: qp.ConfirmationThresholdPercentage, - ChunkLength: qp.ChunkLength, + ChunkLength: qp.ChunkLength, }) } @@ -252,11 +252,16 @@ func makeBatchEigenDA(t *testing.T, l2Node *arbnode.Node, l2Info *BlockchainTest X: blobInfo.BlobHeader.Commitment.X, Y: blobInfo.BlobHeader.Commitment.Y, }, - DataLength: blobInfo.BlobHeader.DataLength, + DataLength: blobInfo.BlobHeader.DataLength, QuorumBlobParams: solQps, } - tx, err := seqInbox.AddSequencerL2BatchFromEigenDA(sequencer, seqNum, bvp, blobHeader, common.Address{}, big.NewInt(1), big.NewInt(0), big.NewInt(0)) + daCert := mocksgen.ISequencerInboxEigenDACert{ + BlobVerificationProof: bvp, + BlobHeader: blobHeader, + } + + tx, err := seqInbox.AddSequencerL2BatchFromEigenDA(sequencer, seqNum, daCert, common.Address{}, big.NewInt(1), big.NewInt(0), big.NewInt(0)) Require(t, err) receipt, err := EnsureTxSucceeded(ctx, backend, tx) Require(t, err) @@ -324,29 +329,11 @@ func setupSequencerInboxStub(ctx context.Context, t *testing.T, l1Info *Blockcha Require(t, err) _, err = EnsureTxSucceeded(ctx, l1Client, tx) - if chainConfig.ArbitrumChainParams.EigenDA { - println("Deploying RollupManagerStub") - - time.Sleep(5 * time.Second) - managerAddr, tx, _, err := mocksgen.DeployRollupManagerStub(&txOpts, l1Client) - Require(t, err) - _, err = EnsureTxSucceeded(ctx, l1Client, tx) - Require(t, err) - - - tx, err = seqInbox.AddInitMessage(&txOpts, chainConfig.ChainID, managerAddr) - Require(t, err) - _, err = EnsureTxSucceeded(ctx, l1Client, tx) - Require(t, err) - - } else { - Require(t, err) - tx, err = seqInbox.AddInitMessage(&txOpts, chainConfig.ChainID, common.Address{}) - Require(t, err) - _, err = EnsureTxSucceeded(ctx, l1Client, tx) - Require(t, err) - } - + Require(t, err) + tx, err = seqInbox.AddInitMessage(&txOpts, chainConfig.ChainID) + Require(t, err) + _, err = EnsureTxSucceeded(ctx, l1Client, tx) + Require(t, err) return bridgeAddr, seqInbox, seqInboxAddr } @@ -376,7 +363,7 @@ func RunChallengeTest(t *testing.T, asserterIsCorrect bool, useStubs bool, chall l1Info.GenerateGenesisAccount("asserter", initialBalance) l1Info.GenerateGenesisAccount("challenger", initialBalance) l1Info.GenerateGenesisAccount("sequencer", initialBalance) - + chainConfig := params.ArbitrumDevTestChainConfig() l1Info, l1Backend, _, _ := createTestL1BlockChain(t, l1Info) conf := arbnode.ConfigDefaultL1Test() @@ -448,7 +435,6 @@ func RunChallengeTest(t *testing.T, asserterIsCorrect bool, useStubs bool, chall makeBatchEigenDA(t, asserterL2, asserterL2Info, l1Backend, &sequencerTxOpts, asserterSeqInbox, asserterSeqInboxAddr, -1) makeBatchEigenDA(t, challengerL2, challengerL2Info, l1Backend, &sequencerTxOpts, challengerSeqInbox, challengerSeqInboxAddr, challengeMsgIdx-makeBatch_MsgsPerBatch*2-1) } else { - // seqNum := common.Big2 makeBatch(t, asserterL2, asserterL2Info, l1Backend, &sequencerTxOpts, asserterSeqInbox, asserterSeqInboxAddr, -1) makeBatch(t, challengerL2, challengerL2Info, l1Backend, &sequencerTxOpts, challengerSeqInbox, challengerSeqInboxAddr, challengeMsgIdx-1) @@ -527,7 +513,16 @@ func RunChallengeTest(t *testing.T, asserterIsCorrect bool, useStubs bool, chall confirmLatestBlock(ctx, t, l1Info, l1Backend) - asserterValidator, err := staker.NewStatelessBlockValidator(asserterL2.InboxReader, asserterL2.InboxTracker, asserterL2.TxStreamer, asserterExec.Recorder, asserterL2.ArbDB, nil, StaticFetcherFrom(t, &conf.BlockValidator), valStack) + readers := make([]daprovider.Reader, 1) + + if useEigenDA { + eigenDA, err := eigenda.NewEigenDA(&conf.EigenDA) + + Require(t, err) + readers[0] = eigenda.NewReaderForEigenDA(eigenDA) + } + + asserterValidator, err := staker.NewStatelessBlockValidator(asserterL2.InboxReader, asserterL2.InboxTracker, asserterL2.TxStreamer, asserterExec.Recorder, asserterL2.ArbDB, readers, StaticFetcherFrom(t, &conf.BlockValidator), valStack) if err != nil { Fatal(t, err) } @@ -544,7 +539,7 @@ func RunChallengeTest(t *testing.T, asserterIsCorrect bool, useStubs bool, chall if err != nil { Fatal(t, err) } - challengerValidator, err := staker.NewStatelessBlockValidator(challengerL2.InboxReader, challengerL2.InboxTracker, challengerL2.TxStreamer, challengerExec.Recorder, challengerL2.ArbDB, nil, StaticFetcherFrom(t, &conf.BlockValidator), valStack) + challengerValidator, err := staker.NewStatelessBlockValidator(challengerL2.InboxReader, challengerL2.InboxTracker, challengerL2.TxStreamer, challengerExec.Recorder, challengerL2.ArbDB, readers, StaticFetcherFrom(t, &conf.BlockValidator), valStack) if err != nil { Fatal(t, err) } diff --git a/system_tests/full_challenge_mock_test.go b/system_tests/full_challenge_mock_test.go index 66fd7ce2f..1076c731c 100644 --- a/system_tests/full_challenge_mock_test.go +++ b/system_tests/full_challenge_mock_test.go @@ -4,16 +4,20 @@ package arbtest -// func TestMockChallengeManagerAsserterIncorrect(t *testing.T) { -// t.Parallel() -// for i := int64(1); i <= makeBatch_MsgsPerBatch*3; i++ { -// RunChallengeTest(t, false, true, i) -// } -// } +import "testing" -// func TestMockChallengeManagerAsserterCorrect(t *testing.T) { -// t.Parallel() -// for i := int64(1); i <= makeBatch_MsgsPerBatch*3; i++ { -// RunChallengeTest(t, true, true, i) -// } -// } +func TestMockChallengeManagerAsserterIncorrect(t *testing.T) { + t.Parallel() + for i := int64(1); i <= makeBatch_MsgsPerBatch*3; i++ { + RunChallengeTest(t, false, true, i, false) + RunChallengeTest(t, false, true, i, true) + } +} + +func TestMockChallengeManagerAsserterCorrect(t *testing.T) { + t.Parallel() + for i := int64(1); i <= makeBatch_MsgsPerBatch*3; i++ { + RunChallengeTest(t, true, true, i, false) + RunChallengeTest(t, true, true, i, true) + } +} diff --git a/system_tests/full_challenge_test.go b/system_tests/full_challenge_test.go index bfc5f4d71..d8c3847cf 100644 --- a/system_tests/full_challenge_test.go +++ b/system_tests/full_challenge_test.go @@ -10,11 +10,17 @@ import "testing" func TestChallengeManagerFullAsserterIncorrect(t *testing.T) { t.Parallel() - // RunChallengeTest(t, false, false, makeBatch_MsgsPerBatch+1) + RunChallengeTest(t, false, false, makeBatch_MsgsPerBatch+1, false) + RunChallengeTest(t, false, false, makeBatch_MsgsPerBatch+1, false) + + // eigenda tests + RunChallengeTest(t, false, false, makeBatch_MsgsPerBatch+1, true) RunChallengeTest(t, false, false, makeBatch_MsgsPerBatch+1, true) } func TestChallengeManagerFullAsserterCorrect(t *testing.T) { t.Parallel() - // RunChallengeTest(t, true, false, makeBatch_MsgsPerBatch+2) + RunChallengeTest(t, true, false, makeBatch_MsgsPerBatch+2, false) + // eigenda test + RunChallengeTest(t, true, false, makeBatch_MsgsPerBatch+2, true) }