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

feat: verify tx cycles in relay protocol #341

Merged
merged 5 commits into from
Mar 20, 2019
Merged
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
23 changes: 20 additions & 3 deletions protocol/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ use crate::protocol_generated::ckb::protocol::{
ProposalShortId as FbsProposalShortId, RelayMessage, RelayMessageBuilder, RelayPayload,
Script as FbsScript, ScriptBuilder, SyncMessage, SyncMessageBuilder, SyncPayload,
Time as FbsTime, TimeBuilder, TimeMessage, TimeMessageBuilder, Transaction as FbsTransaction,
TransactionBuilder, UncleBlock as FbsUncleBlock, UncleBlockBuilder, H256 as FbsH256,
TransactionBuilder, UncleBlock as FbsUncleBlock, UncleBlockBuilder,
ValidTransaction as FbsValidTransaction, ValidTransactionBuilder, H256 as FbsH256,
};
use crate::{short_transaction_id, short_transaction_id_keys};
use ckb_core::block::Block;
use ckb_core::header::{BlockNumber, Header};
use ckb_core::script::Script;
use ckb_core::transaction::{CellInput, CellOutput, OutPoint, ProposalShortId, Transaction};
use ckb_core::uncle::UncleBlock;
use ckb_core::Cycle;
use ckb_merkle_tree::build_merkle_proof;
use flatbuffers::{FlatBufferBuilder, WIPOffset};
use numext_fixed_hash::H256;
Expand Down Expand Up @@ -114,6 +116,20 @@ impl<'a> FbsOutPoint<'a> {
}
}

impl<'a> FbsValidTransaction<'a> {
pub fn build<'b>(
fbb: &mut FlatBufferBuilder<'b>,
transaction: &Transaction,
cycles: Cycle,
) -> WIPOffset<FbsValidTransaction<'b>> {
let tx = FbsTransaction::build(fbb, transaction);
let mut builder = ValidTransactionBuilder::new(fbb);
builder.add_transaction(tx);
builder.add_cycles(cycles);
builder.finish()
}
}

impl<'a> FbsCellInput<'a> {
pub fn build<'b>(
fbb: &mut FlatBufferBuilder<'b>,
Expand Down Expand Up @@ -488,10 +504,11 @@ impl<'a> RelayMessage<'a> {
pub fn build_transaction<'b>(
fbb: &mut FlatBufferBuilder<'b>,
transaction: &Transaction,
cycles: Cycle,
) -> WIPOffset<RelayMessage<'b>> {
let fbs_transaction = FbsTransaction::build(fbb, transaction);
let fbs_transaction = FbsValidTransaction::build(fbb, transaction, cycles);
let mut builder = RelayMessageBuilder::new(fbb);
builder.add_payload_type(RelayPayload::Transaction);
builder.add_payload_type(RelayPayload::ValidTransaction);
builder.add_payload(fbs_transaction.as_union_value());
builder.finish()
}
Expand Down
9 changes: 9 additions & 0 deletions protocol/src/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,15 @@ impl<'a> From<ckb_protocol::Transaction<'a>> for ckb_core::transaction::Transact
}
}

impl<'a> From<ckb_protocol::ValidTransaction<'a>>
for (ckb_core::transaction::Transaction, ckb_core::Cycle)
{
fn from(tx: ckb_protocol::ValidTransaction<'a>) -> Self {
let cycles = tx.cycles();
(tx.transaction().unwrap().into(), cycles)
}
}

impl<'a> From<ckb_protocol::OutPoint<'a>> for ckb_core::transaction::OutPoint {
fn from(out_point: ckb_protocol::OutPoint<'a>) -> Self {
ckb_core::transaction::OutPoint {
Expand Down
7 changes: 6 additions & 1 deletion protocol/src/protocol.fbs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ root_type SyncMessage;

union RelayPayload {
CompactBlock,
Transaction,
ValidTransaction,
GetBlockTransactions,
BlockTransactions,
GetBlockProposal,
Expand All @@ -123,6 +123,11 @@ table IndexTransaction {
transaction: Transaction;
}

table ValidTransaction {
cycles: uint64;
transaction: Transaction;
}

table GetBlockTransactions {
hash: H256;
indexes: [uint32];
Expand Down
100 changes: 94 additions & 6 deletions protocol/src/protocol_generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ pub struct SyncPayloadUnionTableOffset {}
pub enum RelayPayload {
NONE = 0,
CompactBlock = 1,
Transaction = 2,
ValidTransaction = 2,
GetBlockTransactions = 3,
BlockTransactions = 4,
GetBlockProposal = 5,
Expand Down Expand Up @@ -158,7 +158,7 @@ impl flatbuffers::Push for RelayPayload {
const ENUM_VALUES_RELAY_PAYLOAD:[RelayPayload; 7] = [
RelayPayload::NONE,
RelayPayload::CompactBlock,
RelayPayload::Transaction,
RelayPayload::ValidTransaction,
RelayPayload::GetBlockTransactions,
RelayPayload::BlockTransactions,
RelayPayload::GetBlockProposal,
Expand All @@ -169,7 +169,7 @@ const ENUM_VALUES_RELAY_PAYLOAD:[RelayPayload; 7] = [
const ENUM_NAMES_RELAY_PAYLOAD:[&'static str; 7] = [
"NONE",
"CompactBlock",
"Transaction",
"ValidTransaction",
"GetBlockTransactions",
"BlockTransactions",
"GetBlockProposal",
Expand Down Expand Up @@ -2003,9 +2003,9 @@ impl<'a> RelayMessage<'a> {

#[inline]
#[allow(non_snake_case)]
pub fn payload_as_transaction(&'a self) -> Option<Transaction> {
if self.payload_type() == RelayPayload::Transaction {
self.payload().map(|u| Transaction::init_from_table(u))
pub fn payload_as_valid_transaction(&'a self) -> Option<ValidTransaction> {
if self.payload_type() == RelayPayload::ValidTransaction {
self.payload().map(|u| ValidTransaction::init_from_table(u))
} else {
None
}
Expand Down Expand Up @@ -2318,6 +2318,94 @@ impl<'a: 'b, 'b> IndexTransactionBuilder<'a, 'b> {
}
}

pub enum ValidTransactionOffset {}
#[derive(Copy, Clone, Debug, PartialEq)]

pub struct ValidTransaction<'a> {
pub _tab: flatbuffers::Table<'a>,
}

impl<'a> flatbuffers::Follow<'a> for ValidTransaction<'a> {
type Inner = ValidTransaction<'a>;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
Self {
_tab: flatbuffers::Table { buf: buf, loc: loc },
}
}
}

impl<'a> ValidTransaction<'a> {
#[inline]
pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
ValidTransaction {
_tab: table,
}
}
#[allow(unused_mut)]
pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(
_fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,
args: &'args ValidTransactionArgs<'args>) -> flatbuffers::WIPOffset<ValidTransaction<'bldr>> {
let mut builder = ValidTransactionBuilder::new(_fbb);
builder.add_cycles(args.cycles);
if let Some(x) = args.transaction { builder.add_transaction(x); }
builder.finish()
}

pub const VT_CYCLES: flatbuffers::VOffsetT = 4;
pub const VT_TRANSACTION: flatbuffers::VOffsetT = 6;

#[inline]
pub fn cycles(&self) -> u64 {
self._tab.get::<u64>(ValidTransaction::VT_CYCLES, Some(0)).unwrap()
}
#[inline]
pub fn transaction(&self) -> Option<Transaction<'a>> {
self._tab.get::<flatbuffers::ForwardsUOffset<Transaction<'a>>>(ValidTransaction::VT_TRANSACTION, None)
}
}

pub struct ValidTransactionArgs<'a> {
pub cycles: u64,
pub transaction: Option<flatbuffers::WIPOffset<Transaction<'a >>>,
}
impl<'a> Default for ValidTransactionArgs<'a> {
#[inline]
fn default() -> Self {
ValidTransactionArgs {
cycles: 0,
transaction: None,
}
}
}
pub struct ValidTransactionBuilder<'a: 'b, 'b> {
fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,
start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
}
impl<'a: 'b, 'b> ValidTransactionBuilder<'a, 'b> {
#[inline]
pub fn add_cycles(&mut self, cycles: u64) {
self.fbb_.push_slot::<u64>(ValidTransaction::VT_CYCLES, cycles, 0);
}
#[inline]
pub fn add_transaction(&mut self, transaction: flatbuffers::WIPOffset<Transaction<'b >>) {
self.fbb_.push_slot_always::<flatbuffers::WIPOffset<Transaction>>(ValidTransaction::VT_TRANSACTION, transaction);
}
#[inline]
pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> ValidTransactionBuilder<'a, 'b> {
let start = _fbb.start_table();
ValidTransactionBuilder {
fbb_: _fbb,
start_: start,
}
}
#[inline]
pub fn finish(self) -> flatbuffers::WIPOffset<ValidTransaction<'a>> {
let o = self.fbb_.end_table(self.start_);
flatbuffers::WIPOffset::new(o.value())
}
}

pub enum GetBlockTransactionsOffset {}
#[derive(Copy, Clone, Debug, PartialEq)]

Expand Down
17 changes: 17 additions & 0 deletions rpc/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use jsonrpc_core::{Error, ErrorCode};

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum RPCError {
Staging = -2,
Invalid = -3,
}

impl RPCError {
pub fn custom(err: RPCError, message: String) -> Error {
Error {
code: ErrorCode::ServerError(err as i64),
message,
data: None,
}
}
}
1 change: 1 addition & 0 deletions rpc/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod config;
mod error;
mod module;
mod server;

Expand Down
54 changes: 37 additions & 17 deletions rpc/src/module/pool.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use crate::error::RPCError;
use ckb_core::transaction::{ProposalShortId, Transaction as CoreTransaction};
use ckb_network::{NetworkService, ProtocolId};
use ckb_protocol::RelayMessage;
use ckb_shared::index::ChainIndex;
use ckb_shared::shared::Shared;
use ckb_shared::tx_pool::types::PoolEntry;
use ckb_sync::NetworkProtocol;
use ckb_traits::chain_provider::ChainProvider;
use ckb_verification::TransactionError;
use flatbuffers::FlatBufferBuilder;
use jsonrpc_core::Result;
use jsonrpc_derive::rpc;
Expand Down Expand Up @@ -32,25 +36,41 @@ impl<CI: ChainIndex + 'static> PoolRpc for PoolRpcImpl<CI> {
fn send_transaction(&self, tx: Transaction) -> Result<H256> {
let tx: CoreTransaction = tx.into();
let tx_hash = tx.hash().clone();
{
let cycles = {
let mut chain_state = self.shared.chain_state().lock();
let tx_pool = chain_state.mut_tx_pool();
let pool_result = tx_pool.enqueue_tx(tx.clone());
debug!(target: "rpc", "send_transaction add to pool result: {:?}", pool_result);
}

let fbb = &mut FlatBufferBuilder::new();
let message = RelayMessage::build_transaction(fbb, &tx);
fbb.finish(message, None);
let rtx = chain_state.resolve_tx_from_pool(&tx, &chain_state.tx_pool());
let tx_result =
chain_state.verify_rtx(&rtx, self.shared.consensus().max_block_cycles());
debug!(target: "rpc", "send_transaction add to pool result: {:?}", tx_result);
let cycles = match tx_result {
Err(TransactionError::UnknownInput) => None,
Err(err) => return Err(RPCError::custom(RPCError::Invalid, format!("{:?}", err))),
Ok(cycles) => Some(cycles),
};
let entry = PoolEntry::new(tx.clone(), 0, cycles);
chain_state.mut_tx_pool().enqueue_tx(entry);
cycles
};
match cycles {
Some(cycles) => {
let fbb = &mut FlatBufferBuilder::new();
let message = RelayMessage::build_transaction(fbb, &tx, cycles);
fbb.finish(message, None);

self.network
.with_protocol_context(NetworkProtocol::RELAY as ProtocolId, |nc| {
for peer in nc.connected_peers() {
debug!(target: "rpc", "relay transaction {} to peer#{}", tx_hash, peer);
let _ = nc.send(peer, fbb.finished_data().to_vec());
}
});
Ok(tx_hash)
self.network
.with_protocol_context(NetworkProtocol::RELAY as ProtocolId, |nc| {
for peer in nc.connected_peers() {
debug!(target: "rpc", "relay transaction {} to peer#{}", tx_hash, peer);
let _ = nc.send(peer, fbb.finished_data().to_vec());
}
});
Ok(tx_hash)
}
None => Err(RPCError::custom(
RPCError::Staging,
"tx missing inputs".to_string(),
)),
}
}

fn get_pool_transaction(&self, hash: H256) -> Result<Option<Transaction>> {
Expand Down
51 changes: 36 additions & 15 deletions rpc/src/module/trace.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
use crate::error::RPCError;
use ckb_core::transaction::Transaction as CoreTransaction;
use ckb_network::{NetworkService, ProtocolId};
use ckb_protocol::RelayMessage;
use ckb_shared::index::ChainIndex;
use ckb_shared::shared::Shared;
use ckb_shared::tx_pool::types::PoolEntry;
use ckb_shared::tx_pool::TxTrace;
use ckb_sync::NetworkProtocol;
use ckb_traits::chain_provider::ChainProvider;
use ckb_verification::TransactionError;
use flatbuffers::FlatBufferBuilder;
use jsonrpc_core::Result;
use jsonrpc_derive::rpc;
Expand All @@ -31,24 +35,41 @@ impl<CI: ChainIndex + 'static> TraceRpc for TraceRpcImpl<CI> {
fn trace_transaction(&self, tx: Transaction) -> Result<H256> {
let tx: CoreTransaction = tx.into();
let tx_hash = tx.hash().clone();
{
let cycles = {
let mut chain_state = self.shared.chain_state().lock();
let tx_pool = chain_state.mut_tx_pool();
tx_pool.trace_tx(tx.clone());
}
let rtx = chain_state.resolve_tx_from_pool(&tx, &chain_state.tx_pool());
let cycles = match chain_state
.verify_rtx(&rtx, self.shared.consensus().max_block_cycles())
{
Err(TransactionError::UnknownInput) => None,
Err(err) => return Err(RPCError::custom(RPCError::Invalid, format!("{:?}", err))),
Ok(cycles) => Some(cycles),
};
let entry = PoolEntry::new(tx.clone(), 0, cycles);
chain_state.mut_tx_pool().enqueue_tx(entry);
cycles
};

let fbb = &mut FlatBufferBuilder::new();
let message = RelayMessage::build_transaction(fbb, &tx);
fbb.finish(message, None);
match cycles {
Some(cycles) => {
let fbb = &mut FlatBufferBuilder::new();
let message = RelayMessage::build_transaction(fbb, &tx, cycles);
fbb.finish(message, None);

self.network
.with_protocol_context(NetworkProtocol::RELAY as ProtocolId, |nc| {
for peer in nc.connected_peers() {
debug!(target: "rpc", "relay transaction {} to peer#{}", tx_hash, peer);
let _ = nc.send(peer, fbb.finished_data().to_vec());
}
});
Ok(tx_hash)
self.network
.with_protocol_context(NetworkProtocol::RELAY as ProtocolId, |nc| {
for peer in nc.connected_peers() {
debug!(target: "rpc", "relay transaction {} to peer#{}", tx_hash, peer);
let _ = nc.send(peer, fbb.finished_data().to_vec());
}
});
Ok(tx_hash)
}
None => Err(RPCError::custom(
RPCError::Staging,
"tx missing inputs".to_string(),
)),
}
}

fn get_transaction_trace(&self, hash: H256) -> Result<Option<Vec<TxTrace>>> {
Expand Down
Loading