proper tx sigopcounting
This commit is contained in:
parent
afd6c78e21
commit
3ad579ea29
|
@ -147,6 +147,7 @@ dependencies = [
|
|||
"chain 0.1.0",
|
||||
"elastic-array 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethcore-devtools 1.3.0",
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"primitives 0.1.0",
|
||||
"rocksdb 0.4.5 (git+https://github.com/ethcore/rust-rocksdb)",
|
||||
|
|
|
@ -14,6 +14,7 @@ serialization = { path = "../serialization" }
|
|||
parking_lot = "0.3"
|
||||
test-data = { path = "../test-data" }
|
||||
bit-vec = "0.4"
|
||||
log = "0.3"
|
||||
|
||||
[features]
|
||||
dev = []
|
||||
|
|
|
@ -8,6 +8,7 @@ extern crate byteorder;
|
|||
extern crate chain;
|
||||
extern crate serialization;
|
||||
extern crate bit_vec;
|
||||
#[macro_use] extern crate log;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate ethcore_devtools as devtools;
|
||||
|
|
|
@ -341,6 +341,8 @@ impl Storage {
|
|||
/// all transaction meta is removed
|
||||
/// DOES NOT update best block
|
||||
fn decanonize_block(&self, context: &mut UpdateContext, hash: &H256) -> Result<(), Error> {
|
||||
trace!(target: "reorg", "Decanonizing block {}", hash);
|
||||
|
||||
// ensure that block is of the main chain
|
||||
try!(self.block_number(hash).ok_or(Error::NotMain(hash.clone())));
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ impl ChainVerifier {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn verify_transaction(&self, block: &chain::Block, transaction: &chain::Transaction) -> Result<usize, TransactionError> {
|
||||
fn verify_transaction(&self, block: &chain::Block, transaction: &chain::Transaction) -> Result<(), TransactionError> {
|
||||
use script::{
|
||||
TransactionInputSigner,
|
||||
TransactionSignatureChecker,
|
||||
|
@ -103,7 +103,6 @@ impl ChainVerifier {
|
|||
verify_script,
|
||||
};
|
||||
|
||||
let mut sigops: usize = 0;
|
||||
for (input_index, input) in transaction.inputs().iter().enumerate() {
|
||||
let store_parent_transaction = self.store.transaction(&input.previous_output.hash);
|
||||
let parent_transaction = match store_parent_transaction {
|
||||
|
@ -129,15 +128,6 @@ impl ChainVerifier {
|
|||
let input: Script = input.script_sig().to_vec().into();
|
||||
let output: Script = paired_output.script_pubkey.to_vec().into();
|
||||
|
||||
sigops +=
|
||||
try!(output.sigop_count().map_err(|e| TransactionError::ReferenceSignatureMallformed(format!("{}", e)))) +
|
||||
try!(input.sigop_count().map_err(|e| TransactionError::SignatureMallformed(format!("{}", e))));
|
||||
|
||||
if sigops > MAX_BLOCK_SIGOPS {
|
||||
// already overflown
|
||||
return Err(TransactionError::SigopsAmount);
|
||||
}
|
||||
|
||||
let flags = VerificationFlags::default().verify_p2sh(true);
|
||||
|
||||
// for tests only, skips as late as possible
|
||||
|
@ -150,7 +140,7 @@ impl ChainVerifier {
|
|||
}
|
||||
}
|
||||
|
||||
Ok(sigops)
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,12 +176,18 @@ impl Verify for ChainVerifier {
|
|||
// verify transactions (except coinbase)
|
||||
let mut block_sigops = 0;
|
||||
for (idx, transaction) in block.transactions().iter().skip(1).enumerate() {
|
||||
let tx_sigops = try!(self.verify_transaction(block, transaction).map_err(|e| Error::Transaction(idx+1, e)));
|
||||
block_sigops += tx_sigops;
|
||||
|
||||
block_sigops += try!(
|
||||
utils::transaction_sigops(transaction)
|
||||
.map_err(|e| Error::Transaction(idx+1, TransactionError::SignatureMallformed(format!("{}", e))))
|
||||
);
|
||||
|
||||
if block_sigops >= MAX_BLOCK_SIGOPS {
|
||||
return Err(Error::MaximumSigops);
|
||||
}
|
||||
|
||||
try!(self.verify_transaction(block, transaction).map_err(|e| Error::Transaction(idx+1, e)));
|
||||
|
||||
}
|
||||
|
||||
trace!(target: "verification", "Block {} total sigops: {}", &hash, &block_sigops);
|
||||
|
@ -477,46 +473,6 @@ mod tests {
|
|||
assert_eq!(expected, verifier.verify(&block))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sigops_overflow_tx() {
|
||||
let path = RandomTempPath::create_dir();
|
||||
let storage = Storage::new(path.as_path()).unwrap();
|
||||
|
||||
let genesis = test_data::block_builder()
|
||||
.transaction()
|
||||
.coinbase()
|
||||
.build()
|
||||
.transaction()
|
||||
.output().value(50).build()
|
||||
.build()
|
||||
.merkled_header().build()
|
||||
.build();
|
||||
|
||||
storage.insert_block(&genesis).unwrap();
|
||||
let reference_tx = genesis.transactions()[1].hash();
|
||||
|
||||
let mut builder = script::Builder::default();
|
||||
for _ in 0..21000 {
|
||||
builder = builder.push_opcode(script::Opcode::OP_CHECKSIG)
|
||||
}
|
||||
|
||||
let block = test_data::block_builder()
|
||||
.transaction().coinbase().build()
|
||||
.transaction()
|
||||
.input()
|
||||
.hash(reference_tx)
|
||||
.signature_bytes(builder.into_script().to_bytes())
|
||||
.build()
|
||||
.build()
|
||||
.merkled_header().parent(genesis.hash()).build()
|
||||
.build();
|
||||
|
||||
let verifier = ChainVerifier::new(Arc::new(storage)).pow_skip();
|
||||
|
||||
let expected = Err(Error::Transaction(1, TransactionError::SigopsAmount));
|
||||
assert_eq!(expected, verifier.verify(&block));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sigops_overflow_block() {
|
||||
let path = RandomTempPath::create_dir();
|
||||
|
|
|
@ -69,10 +69,6 @@ pub enum TransactionError {
|
|||
Overspend,
|
||||
/// Signature script can't be properly parsed
|
||||
SignatureMallformed(String),
|
||||
/// Signature script in referenced transaction can't be properly parsed
|
||||
ReferenceSignatureMallformed(String),
|
||||
/// Too many sigops
|
||||
SigopsAmount,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
//! Verification utilities
|
||||
use primitives::hash::H256;
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
use chain;
|
||||
use script::{self, Script};
|
||||
|
||||
pub fn check_nbits(hash: &H256, n_bits: u32) -> bool {
|
||||
let hash_bytes: &[u8] = &**hash;
|
||||
|
@ -52,6 +54,22 @@ pub fn block_reward_satoshi(block_height: u32) -> u64 {
|
|||
res
|
||||
}
|
||||
|
||||
pub fn transaction_sigops(transaction: &chain::Transaction) -> Result<usize, script::Error> {
|
||||
let mut result = 0usize;
|
||||
|
||||
for input in transaction.inputs.iter() {
|
||||
let input_script: Script = input.script_sig().to_vec().into();
|
||||
result += try!(input_script.sigop_count());
|
||||
}
|
||||
|
||||
for output in transaction.outputs.iter() {
|
||||
let output_script: Script = output.script_pubkey.to_vec().into();
|
||||
result += try!(output_script.sigop_count());
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
|
|
Loading…
Reference in New Issue