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

Receipt #18

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
31 changes: 31 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ tree_hash = "0.7.0"
serde_with = { version = "3.4.0", features = ["hex"] }
cargo_metadata = "0.18"

# receipt
alloy-trie = "0.4"
nybbles = "0.2.1"

[patch.crates-io]
sha2-v0-9-9 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", package = "sha2", branch = "patch-sha2-v0.9.9" }
sha2-v0-10-8 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", package = "sha2", branch = "patch-sha2-v0.10.8" }
Expand Down
20 changes: 10 additions & 10 deletions contracts/genesis.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{
"executionStateRoot": "0xefd1e79b7ea23418b36c0d402940e82c2fa7c0eefb7ab6eba7d1bfed6ed3583b",
"genesisTime": 1655733600,
"genesisValidatorsRoot": "0xd8ea171f3c94aea21ebc42a1ed61052acf3f9209c00e4efbaaddac09ed9b8078",
"guardian": "0xded0000e32f8f40414d3ab3a830f735a3553e18e",
"head": 6258496,
"header": "0xc30412bbc474103121140c10705d608b72dd060794090e3a9fff2f0cc2204b5d",
"heliosProgramVkey": "0x0045a4708ac27a6e55aa8ac0269955904326abce5a5828d2ad91f5f3c0d89cdd",
"executionStateRoot": "0xd30d19d84c3c01bb7cd60393e227cd586d4996cdb5bd1a3fbe3c9845ad6f05e1",
"genesisTime": 1606824023,
"genesisValidatorsRoot": "0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95",
"guardian": "0xe6709a64cfa1d7d2d177a3b544b4fe3fc000bfa8",
"head": 10599264,
"header": "0xadcd83b153af90dcb6ce979b7bf3c486fcba79e5daf4dcf23c426bd96d27d84b",
"heliosProgramVkey": "0x008e014e12f07ad1ee7069351ac85c7f586ba89bb4792c20666c9f7a00af97aa",
"secondsPerSlot": 12,
"slotsPerEpoch": 32,
"slotsPerPeriod": 8192,
"sourceChainId": 11155111,
"syncCommitteeHash": "0xb997e17dda358926c21e29985b199afb5500fd4828a6c1a0455101cb1c514062",
"verifier": "0x3b6041173b80e77f038f3f2c0f9744f04837185e"
"sourceChainId": 1,
"syncCommitteeHash": "0xbe9b25fd743f094b6d302f4c1676d701ee22acc8cd979cf7fe0b577e8ba6dcec",
"verifier": "0x0000000000000000000000000000000000000000"
}
Binary file modified elf/riscv32im-succinct-zkvm-elf
Binary file not shown.
2 changes: 2 additions & 0 deletions script/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ cargo_metadata = { workspace = true }
reqwest = { workspace = true }
tree_hash = { workspace = true }
serde_json = { workspace = true }
alloy-trie = { workspace = true }
nybbles = { workspace = true }

[build-dependencies]
sp1-build = { workspace = true }
46 changes: 40 additions & 6 deletions script/bin/operator.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
/// Continuously generate proofs & keep light client updated with chain
use alloy::{
core::rlp::Encodable,
consensus::{Receipt, TxReceipt},
eips::BlockNumberOrTag,
network::{Ethereum, EthereumWallet},
primitives::Address,
primitives::{Address, Bloom, B256, Log, U256},
providers::{
fillers::{ChainIdFiller, FillProvider, GasFiller, JoinFill, NonceFiller, WalletFiller},
Identity, Provider, ProviderBuilder, RootProvider,
},
rpc::types::TransactionReceipt,
signers::local::PrivateKeySigner,
sol,
transports::http::{Client, Http},
transports::http::{Client, Http}
};
use alloy_primitives::{B256, U256};
// use alloy_merkle_tree::tree::MerkleTree;
use anyhow::Result;
use helios_consensus_core::consensus_spec::MainnetConsensusSpec;
use helios_consensus_core::{consensus_spec::MainnetConsensusSpec, types::{BeaconBlock, ExecutionPayload}};
use helios_ethereum::consensus::Inner;
use helios_ethereum::rpc::http_rpc::HttpRpc;
use helios_ethereum::rpc::ConsensusRpc;
use log::{error, info};
use sp1_helios_primitives::types::ProofInputs;
use sp1_helios_script::*;
use sp1_sdk::{ProverClient, SP1ProofWithPublicValues, SP1ProvingKey, SP1Stdin};
use sp1_helios_script::{*, receipt::*, trie::*};
use sp1_sdk::{network::proto::network::twirp::axum::extract::FromRef, ProverClient, SP1ProofWithPublicValues, SP1ProvingKey, SP1Stdin};
use ssz_rs::prelude::*;
use std::env;
use std::sync::Arc;
Expand Down Expand Up @@ -127,6 +131,9 @@ impl SP1LightClientOperator {
async fn request_update(
&self,
mut client: Inner<MainnetConsensusSpec, HttpRpc>,
// target_block: u64,
// contract_address,
// event
) -> Result<Option<SP1ProofWithPublicValues>> {
// Fetch required values.
let contract = SP1LightClient::new(self.contract_address, self.wallet_filler.clone());
Expand Down Expand Up @@ -161,11 +168,38 @@ impl SP1LightClientOperator {

// Check if contract is up to date
let latest_block = finality_update.finalized_header.beacon().slot;

if latest_block <= head {
info!("Contract is up to date. Nothing to update.");
return Ok(None);
}


// TODO: Hardcoded values for now
let target_block: u64 = 6000; // TODO move to argument

// Introspect target block
if latest_block < target_block {
info!("Target block not reached, yet.");
return Ok(None);
}

let consensus_block: BeaconBlock<MainnetConsensusSpec> = client.rpc.get_block(target_block).await.unwrap();
let execution_payload = consensus_block.body.execution_payload();

let block = BlockNumberOrTag::from(*execution_payload.block_number());
let receipts_root = execution_payload.receipts_root();
let receipts = self.wallet_filler.get_block_receipts(block).await.unwrap().unwrap();

let computed_receipts_root = ordered_trie_root_with_encoder(receipts, |r, buf| ReceiptWithBloomEncoder::new(&r).encode_inner(buf, false));

// for receipt in receipts {

// let encoder = ReceiptWithBloomEncoder::new(&receipt);
// encoder.encode(out);
// }


// Optimization:
// Skip processing update inside program if next_sync_committee is already stored in contract.
// We must still apply the update locally to "sync" the helios client, this is due to
Expand Down
3 changes: 3 additions & 0 deletions script/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ use ssz_rs::prelude::*;
use std::sync::Arc;
use tokio::sync::{mpsc::channel, watch};
use tree_hash::TreeHash;

pub mod receipt;
pub mod relay;
pub mod trie;

pub const MAX_REQUEST_LIGHT_CLIENT_UPDATES: u8 = 128;

Expand Down
166 changes: 166 additions & 0 deletions script/src/receipt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/// Adapted from reth: https://github.com/paradigmxyz/reth/blob/v1.0.1/crates/primitives/src/receipt.rs
use alloy::{
consensus::{ReceiptEnvelope, TxType},
core::rlp::{bytes::BufMut, length_of_length, Encodable, Header},
primitives::{Bytes, Log},
rpc::types::{Log as RpcLog, TransactionReceipt},
};

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ReceiptWithBloomEncoder<'a> {
// bloom: &'a Bloom,
receipt: &'a TransactionReceipt<ReceiptEnvelope<RpcLog>>,
}

impl<'a> ReceiptWithBloomEncoder<'a> {

/// Create new [`ReceiptWithBloom`]
pub const fn new(receipt: &'a TransactionReceipt<ReceiptEnvelope<RpcLog>>) -> Self {
Self { receipt }
}

/// Returns the enveloped encoded receipt.
///
/// See also [`ReceiptWithBloom::encode_enveloped`]
pub fn envelope_encoded(&self) -> Bytes {
let mut buf = Vec::new();
self.encode_enveloped(&mut buf);
buf.into()
}

/// Encodes the receipt into its "raw" format.
/// This format is also referred to as "binary" encoding.
///
/// For legacy receipts, it encodes the RLP of the receipt into the buffer:
/// `rlp([status, cumulativeGasUsed, logsBloom, logs])` as per EIP-2718.
/// For EIP-2718 typed transactions, it encodes the type of the transaction followed by the rlp
/// of the receipt:
/// - EIP-1559, 2930 and 4844 transactions: `tx-type || rlp([status, cumulativeGasUsed,
/// logsBloom, logs])`
pub fn encode_enveloped(&self, out: &mut dyn BufMut) {
self.encode_inner(out, false)
}

/// Encode receipt with or without the header data.
pub fn encode_inner(&self, out: &mut dyn BufMut, with_header: bool) {
self._encode_inner(out, with_header)
}

fn raw_receipt(&self) -> &ReceiptEnvelope<RpcLog> {
&self.receipt.inner
}

fn raw_tx_type(&self) -> TxType {
self.receipt.transaction_type()
}

fn raw_logs(&self) -> Vec<&Log> {
self.raw_receipt().logs().iter().map(|log| &log.inner).collect()
}

/// Returns the rlp header for the receipt payload.
fn receipt_rlp_header(&self) -> Header {
let mut rlp_head = Header { list: true, payload_length: 0 };

// rlp_head.payload_length += self.receipt.success.length();
rlp_head.payload_length += self.raw_receipt().cumulative_gas_used().length();
// rlp_head.payload_length += self.bloom.length();
rlp_head.payload_length += self.raw_receipt().logs_bloom().length();
rlp_head.payload_length += self.raw_logs().length();

// #[cfg(feature = "optimism")]
// if self.raw_tx_type() == TxType::Deposit {
// if let Some(deposit_nonce) = self.receipt.deposit_nonce {
// rlp_head.payload_length += deposit_nonce.length();
// }
// if let Some(deposit_receipt_version) = self.receipt.deposit_receipt_version {
// rlp_head.payload_length += deposit_receipt_version.length();
// }
// }

rlp_head
}

/// Encodes the receipt data.
fn encode_fields(&self, out: &mut dyn BufMut) {
self.receipt_rlp_header().encode(out);

// self.receipt.success.encode(out);
self.raw_receipt().status().encode(out);
self.raw_receipt().cumulative_gas_used().encode(out);
self.raw_receipt().logs_bloom().encode(out);
self.raw_logs().encode(out);

// #[cfg(feature = "optimism")]
// if self.raw_tx_type() == TxType::Deposit {
// if let Some(deposit_nonce) = self.receipt.deposit_nonce {
// deposit_nonce.encode(out)
// }
// if let Some(deposit_receipt_version) = self.receipt.deposit_receipt_version {
// deposit_receipt_version.encode(out)
// }
// }
}

/// Encode receipt with or without the header data.
fn _encode_inner(&self, out: &mut dyn BufMut, with_header: bool) {

if matches!(self.raw_tx_type(), TxType::Legacy) {
self.encode_fields(out);
return
}

let mut payload = Vec::new();
self.encode_fields(&mut payload);

if with_header {
let payload_length = payload.len() + 1;
let header = Header { list: false, payload_length };
header.encode(out);
}

match self.raw_tx_type() {
TxType::Legacy => unreachable!("legacy already handled"),

TxType::Eip2930 => {
out.put_u8(0x01);
}
TxType::Eip1559 => {
out.put_u8(0x02);
}
TxType::Eip4844 => {
out.put_u8(0x03);
}
// #[cfg(feature = "optimism")]
// TxType::Deposit => {
// out.put_u8(0x7E);
// }
}
out.put_slice(payload.as_ref());
}

/// Returns the length of the receipt data.
fn receipt_length(&self) -> usize {
let rlp_head = self.receipt_rlp_header();
length_of_length(rlp_head.payload_length) + rlp_head.payload_length
}
}

impl<'a> Encodable for ReceiptWithBloomEncoder<'a> {

fn encode(&self, out: &mut dyn BufMut) {
self.encode_inner(out, true)
}

fn length(&self) -> usize {
let mut payload_len = self.receipt_length();
// account for eip-2718 type prefix and set the list
if !matches!(self.raw_tx_type(), TxType::Legacy) {
payload_len += 1;
// we include a string header for typed receipts, so include the length here
payload_len += length_of_length(payload_len);
}

payload_len
}
}
Loading