Skip to content

Commit

Permalink
Merge pull request #299 from zeroqn/fix-cancel-polyjuice-tx-call-cont…
Browse files Browse the repository at this point in the history
…ract-challenge-failure-v2

fix(challenger): cancel polyjuice tx call contract challenge failure v2
  • Loading branch information
jjyr authored Aug 10, 2021
2 parents 439b332 + d6689b5 commit b44a582
Show file tree
Hide file tree
Showing 10 changed files with 287 additions and 69 deletions.
129 changes: 119 additions & 10 deletions crates/block-producer/src/challenger.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![allow(clippy::mutable_key_type)]

use crate::cleaner::{Cleaner, VerifierCell};
use crate::cleaner::{Cleaner, Verifier};
use crate::poa::{PoA, ShouldIssueBlock};
use crate::rpc_client::RPCClient;
use crate::test_mode_control::TestModeControl;
Expand All @@ -18,14 +18,14 @@ use gw_config::{BlockProducerConfig, DebugConfig};
use gw_generator::{ChallengeContext, RollupContext};
use gw_jsonrpc_types::test_mode::TestModePayload;
use gw_types::bytes::Bytes;
use gw_types::core::{ChallengeTargetType, Status};
use gw_types::core::{ChallengeTargetType, DepType, Status};
use gw_types::packed::{
CellDep, CellInput, CellOutput, GlobalState, OutPoint, Script, Transaction, WitnessArgs,
};
use gw_types::prelude::{Pack, Unpack};
use smol::lock::Mutex;

use std::collections::HashSet;
use std::collections::{HashMap, HashSet};
use std::convert::TryFrom;
use std::sync::Arc;
use std::time::{Duration, Instant};
Expand All @@ -44,6 +44,7 @@ pub struct Challenger {
wallet: Wallet,
config: BlockProducerConfig,
ckb_genesis_info: CKBGenesisInfo,
builtin_load_data: HashMap<H256, CellDep>,
chain: Arc<parking_lot::Mutex<Chain>>,
poa: Arc<Mutex<PoA>>,
tests_control: Option<TestModeControl>,
Expand All @@ -59,6 +60,7 @@ impl Challenger {
wallet: Wallet,
config: BlockProducerConfig,
debug_config: DebugConfig,
builtin_load_data: HashMap<H256, CellDep>,
ckb_genesis_info: CKBGenesisInfo,
chain: Arc<parking_lot::Mutex<Chain>>,
poa: Arc<Mutex<PoA>>,
Expand All @@ -72,6 +74,7 @@ impl Challenger {
config,
debug_config,
ckb_genesis_info,
builtin_load_data,
poa,
chain,
tests_control,
Expand Down Expand Up @@ -259,7 +262,7 @@ impl Challenger {
let prev_state = rollup_state.get_state().to_owned();
let burn_lock = self.config.challenger_config.burn_lock.clone().into();
let owner_lock = self.wallet.lock_script().to_owned();
let cancel_output = cancel_challenge::build_output(
let mut cancel_output = cancel_challenge::build_output(
&self.rollup_context,
prev_state,
&challenge_cell,
Expand All @@ -270,7 +273,13 @@ impl Challenger {

// Build verifier transaction
let verifier_cell = cancel_output.verifier_cell.clone();
let tx = self.build_verifier_tx(verifier_cell).await?;
let load_data = {
let load = cancel_output.load_data_cells.take();
load.map(|ld| LoadData::new(ld, &self.builtin_load_data))
};
let tx = self
.build_verifier_tx(verifier_cell, load_data.clone())
.await?;
let verifier_spent_inputs = extract_inputs(&tx);
let verifier_tx_hash = self.rpc_client.send_transaction(tx).await?;
log::info!("Create verifier in tx {}", to_hex(&verifier_tx_hash));
Expand All @@ -283,7 +292,14 @@ impl Challenger {
let cell_dep = cancel_output.verifier_dep(&self.config)?;
let input = cancel_output.verifier_input(verifier_tx_hash, 0);
let witness = cancel_output.verifier_witness.clone();
VerifierContext::new(cell_dep, input, witness, Some(verifier_spent_inputs))
let load_data_context = load_data.map(|ld| ld.into_context(verifier_tx_hash, 0));
VerifierContext::new(
cell_dep,
input,
witness,
load_data_context,
Some(verifier_spent_inputs),
)
};

let tx = self
Expand All @@ -310,18 +326,20 @@ impl Challenger {
)
.await;

let verifier_cell = VerifierCell::new(
let load_data_inputs = verifier_context.load_data_context.map(|d| d.inputs);
let verifier = Verifier::new(
load_data_inputs.unwrap_or_default(),
verifier_context.cell_dep,
verifier_context.input,
verifier_context.witness,
);
match self.rpc_client.send_transaction(tx).await {
Ok(tx_hash) => {
self.cleaner.watch_verifier(verifier_cell, Some(tx_hash));
self.cleaner.watch_verifier(verifier, Some(tx_hash));
log::info!("Cancel challenge in tx {}", to_hex(&tx_hash));
}
Err(err) => {
self.cleaner.watch_verifier(verifier_cell, None);
self.cleaner.watch_verifier(verifier, None);
log::warn!("Cancel challenge failed {}", err);
}
}
Expand Down Expand Up @@ -468,10 +486,18 @@ impl Challenger {
Ok(())
}

async fn build_verifier_tx(&self, verifier: (CellOutput, Bytes)) -> Result<Transaction> {
async fn build_verifier_tx(
&self,
verifier: (CellOutput, Bytes),
load_data: Option<LoadData>,
) -> Result<Transaction> {
let mut tx_skeleton = TransactionSkeleton::default();
tx_skeleton.outputs_mut().push(verifier);

if let Some(load_data) = load_data {
tx_skeleton.outputs_mut().extend(load_data.cells);
}

let challenger_lock_dep = self.ckb_genesis_info.sighash_dep();
let challenger_lock = self.wallet.lock_script().to_owned();
tx_skeleton.cell_deps_mut().push(challenger_lock_dep);
Expand Down Expand Up @@ -516,6 +542,12 @@ impl Challenger {
// Verifier
let verifier_tx_hash = verifier_context.tx_hash();
tx_skeleton.cell_deps_mut().push(verifier_context.cell_dep);
if let Some(load_data_context) = verifier_context.load_data_context {
let builtin_cell_deps = load_data_context.builtin_cell_deps;
let cell_deps = load_data_context.cell_deps;
tx_skeleton.cell_deps_mut().extend(builtin_cell_deps);
tx_skeleton.cell_deps_mut().extend(cell_deps);
}
tx_skeleton.inputs_mut().push(verifier_context.input);
if let Some(verifier_witness) = cancel_output.verifier_witness {
tx_skeleton.witnesses_mut().push(verifier_witness);
Expand Down Expand Up @@ -648,11 +680,86 @@ impl RollupState {
}
}

#[derive(Clone)]
struct LoadData {
builtin: Vec<CellDep>,
cells: Vec<(CellOutput, Bytes)>,
}

#[derive(Clone)]
struct LoadDataContext {
builtin_cell_deps: Vec<CellDep>,
cell_deps: Vec<CellDep>,
inputs: Vec<InputCellInfo>,
}

impl LoadData {
fn new(
load_data_cells: HashMap<H256, (CellOutput, Bytes)>,
builtin: &HashMap<H256, CellDep>,
) -> Self {
let (load_builtin, load_data_cells): (HashMap<_, _>, HashMap<_, _>) = load_data_cells
.into_iter()
.partition(|(k, _v)| builtin.contains_key(k));

let cells = load_data_cells.values().map(|v| (*v).to_owned()).collect();
let builtin = {
let to_dep = |k| -> CellDep { builtin.get(k).cloned().expect("should exists") };
load_builtin.iter().map(|(k, _)| to_dep(k)).collect()
};

LoadData { builtin, cells }
}

fn into_context(self, verifier_tx_hash: H256, verifier_tx_index: u32) -> LoadDataContext {
assert_eq!(verifier_tx_index, 0, "verifier cell should be first one");

let to_context = |(idx, (output, data))| -> (CellDep, InputCellInfo) {
let out_point = OutPoint::new_builder()
.tx_hash(Into::<[u8; 32]>::into(verifier_tx_hash).pack())
.index((idx as u32).pack())
.build();

let cell_dep = CellDep::new_builder()
.out_point(out_point.clone())
.dep_type(DepType::Code.into())
.build();

let input = CellInput::new_builder()
.previous_output(out_point.clone())
.build();

let cell = CellInfo {
out_point,
output,
data,
};

let cell_info = InputCellInfo { input, cell };

(cell_dep, cell_info)
};

let (cell_deps, inputs) = {
let cells = self.cells.into_iter().enumerate();
let to_ctx = cells.map(|(idx, cell)| (idx + 1, cell)).map(to_context);
to_ctx.unzip()
};

LoadDataContext {
builtin_cell_deps: self.builtin,
cell_deps,
inputs,
}
}
}

#[derive(Clone)]
struct VerifierContext {
cell_dep: CellDep,
input: InputCellInfo,
witness: Option<WitnessArgs>,
load_data_context: Option<LoadDataContext>,
spent_inputs: Option<HashSet<OutPoint>>,
}

Expand All @@ -661,12 +768,14 @@ impl VerifierContext {
cell_dep: CellDep,
input: InputCellInfo,
witness: Option<WitnessArgs>,
load_data_context: Option<LoadDataContext>,
spent_inputs: Option<HashSet<OutPoint>>,
) -> Self {
VerifierContext {
cell_dep,
input,
witness,
load_data_context,
spent_inputs,
}
}
Expand Down
43 changes: 32 additions & 11 deletions crates/block-producer/src/challenger/cancel_challenge.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::HashMap;

use crate::types::{CellInfo, InputCellInfo};

use anyhow::{anyhow, Result};
Expand Down Expand Up @@ -29,6 +31,7 @@ pub struct CancelChallenge<'a, W: Entity> {
pub struct CancelChallengeOutput {
pub post_global_state: GlobalState,
pub verifier_cell: (CellOutput, Bytes),
pub load_data_cells: Option<HashMap<H256, (CellOutput, Bytes)>>, // Some for transaction execution verifiction, sys_load_data
pub burn_cells: Vec<(CellOutput, Bytes)>,
pub verifier_witness: Option<WitnessArgs>, // Some for signature verification
pub challenge_witness: WitnessArgs,
Expand Down Expand Up @@ -100,7 +103,7 @@ pub fn build_output(
);

let data = cancel.build_verifier_data();
Ok(cancel.build_output(data, Some(verifier_witness)))
Ok(cancel.build_output(data, Some(verifier_witness), None))
}
VerifyWitness::TxSignature(witness) => {
let verifier_lock = context.sender_script;
Expand All @@ -126,9 +129,9 @@ pub fn build_output(
);

let data = cancel.build_verifier_data(receiver_script.hash().into());
Ok(cancel.build_output(data, Some(verifier_witness)))
Ok(cancel.build_output(data, Some(verifier_witness), None))
}
VerifyWitness::TxExecution(witness) => {
VerifyWitness::TxExecution { witness, load_data } => {
let verifier_lock = context
.receiver_script
.ok_or_else(|| anyhow!("receiver script not found"))?;
Expand All @@ -144,7 +147,8 @@ pub fn build_output(
);

let data = cancel.build_verifier_data();
Ok(cancel.build_output(data, None))
let load_data = load_data.into_iter().map(|(k, v)| (k, v.unpack()));
Ok(cancel.build_output(data, None, Some(load_data.collect())))
}
}
}
Expand Down Expand Up @@ -178,15 +182,31 @@ impl<'a, W: Entity> CancelChallenge<'a, W> {
self,
verifier_data: Bytes,
verifier_witness: Option<WitnessArgs>,
load_data: Option<HashMap<H256, Bytes>>,
) -> CancelChallengeOutput {
let verifier_size = 8 + verifier_data.len() + self.verifier_lock.as_slice().len();
let verifier_capacity = verifier_size as u64 * 100_000_000;
let build_cell = |data: Bytes, lock: Script| -> (CellOutput, Bytes) {
let dummy_output = CellOutput::new_builder()
.capacity(100_000_000u64.pack())
.lock(lock)
.build();

let verifier = CellOutput::new_builder()
.capacity(verifier_capacity.pack())
.lock(self.verifier_lock)
.build();
let verifier_cell = (verifier, verifier_data);
let capacity = dummy_output
.occupied_capacity(data.len())
.expect("impossible cancel challenge verify cell overflow");

let output = dummy_output.as_builder().capacity(capacity.pack()).build();

(output, data)
};

let verifier_cell = build_cell(verifier_data, self.verifier_lock);

let owner_lock = self.owner_lock;
let load_data_cells = load_data.map(|data| {
data.into_iter()
.map(|(k, v)| (k, build_cell(v, owner_lock.clone())))
.collect()
});

let burn = Burn::new(self.challenge_cell, self.reward_burn_rate);
let burn_output = burn.build_output(self.burn_lock);
Expand All @@ -199,6 +219,7 @@ impl<'a, W: Entity> CancelChallenge<'a, W> {
CancelChallengeOutput {
post_global_state,
verifier_cell,
load_data_cells,
burn_cells: burn_output.burn_cells,
verifier_witness,
challenge_witness,
Expand Down
Loading

0 comments on commit b44a582

Please sign in to comment.