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

Add input signature_script checking to submitTransaction RPC #479

Merged
merged 12 commits into from
Jul 26, 2024
1 change: 1 addition & 0 deletions Cargo.lock

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

11 changes: 7 additions & 4 deletions rpc/core/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use kaspa_consensus_core::{subnets::SubnetworkConversionError, tx::TransactionId};
use kaspa_consensus_core::{subnets::SubnetworkConversionError, tx::TransactionId};
use kaspa_utils::networking::IpAddress;
use std::{net::AddrParseError, num::TryFromIntError};
use thiserror::Error;
Expand Down Expand Up @@ -47,6 +47,9 @@ pub enum RpcError {
#[error("Rejected transaction {0}: {1}")]
RejectedTransaction(RpcTransactionId, String),

#[error("Transaction {0} has input with empty signature scripts at indices {1}.")]
EmptySignatureScript(RpcTransactionId, String),

#[error("Block {0} is invalid. No verbose data can be built.")]
InvalidBlock(RpcHash),

Expand Down Expand Up @@ -116,9 +119,9 @@ pub enum RpcError {
#[error("transaction query must either not filter transactions or include orphans")]
InconsistentMempoolTxQuery,

#[error(transparent)]
SubnetParsingError(#[from] SubnetworkConversionError),
#[error(transparent)]
SubnetParsingError(#[from] SubnetworkConversionError),

#[error(transparent)]
WasmError(#[from] workflow_wasm::error::Error),

Expand Down
1 change: 1 addition & 0 deletions rpc/service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,5 @@ async-trait.workspace = true
log.workspace = true
tokio.workspace = true
triggered.workspace = true
itertools.workspace = true
workflow-rpc.workspace = true
35 changes: 24 additions & 11 deletions rpc/service/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use super::collector::{CollectorFromConsensus, CollectorFromIndex};
use crate::converter::{consensus::ConsensusConverter, index::IndexConverter, protocol::ProtocolConverter};
use crate::service::NetworkType::{Mainnet, Testnet};
use async_trait::async_trait;
use itertools::Itertools;
use kaspa_consensus_core::api::counters::ProcessingCounters;
use kaspa_consensus_core::errors::block::RuleError;
use kaspa_consensus_core::{
Expand Down Expand Up @@ -64,6 +65,7 @@ use kaspa_txscript::{extract_script_pub_key_address, pay_to_address_script};
use kaspa_utils::{channel::Channel, triggers::SingleTrigger};
use kaspa_utils_tower::counters::TowerConnectionCounters;
use kaspa_utxoindex::api::UtxoIndexProxy;
use std::iter;
use std::{
collections::HashMap,
iter::once,
Expand Down Expand Up @@ -493,17 +495,28 @@ NOTE: This error usually indicates an RPC conversion error between the node and

let transaction: Transaction = (&request.transaction).try_into()?;
let transaction_id = transaction.id();
let session = self.consensus_manager.consensus().unguarded_session();
let orphan = match allow_orphan {
true => Orphan::Allowed,
false => Orphan::Forbidden,
};
self.flow_context.submit_rpc_transaction(&session, transaction, orphan).await.map_err(|err| {
let err = RpcError::RejectedTransaction(transaction_id, err.to_string());
debug!("{err}");
err
})?;
Ok(SubmitTransactionResponse::new(transaction_id))
let inputs = &transaction.inputs;

let mut empty_indices =
inputs.iter().enumerate().filter_map(|(index, input)| (input.signature_script.is_empty()).then_some(index.to_string()));
let first_empty = empty_indices.next();
if let Some(first_empty) = first_empty {
Err(RpcError::EmptySignatureScript(transaction_id, iter::once(first_empty).chain(empty_indices).join(", ")))
} else {
let session = self.consensus_manager.consensus().unguarded_session();
let orphan = match allow_orphan {
true => Orphan::Allowed,
false => Orphan::Forbidden,
};
self.flow_context
.submit_rpc_transaction(&session, transaction, orphan)
.await
.as_ref()
.map_err(ToString::to_string)
.map_err(|err| RpcError::RejectedTransaction(transaction_id, err))
.inspect_err(|err| debug!("{err}"))?;
Ok(SubmitTransactionResponse::new(transaction_id))
}
}

async fn get_current_network_call(&self, _: GetCurrentNetworkRequest) -> RpcResult<GetCurrentNetworkResponse> {
Expand Down
Loading