cleaning up

This commit is contained in:
Svyatoslav Nikolsky 2018-11-14 11:37:28 +03:00
parent 14df21533d
commit aa692d8a90
12 changed files with 83 additions and 488 deletions

View File

@ -23,8 +23,6 @@ pub struct ConsensusParams {
pub miner_confirmation_window: u32, pub miner_confirmation_window: u32,
/// BIP68, BIP112, BIP113 deployment /// BIP68, BIP112, BIP113 deployment
pub csv_deployment: Option<Deployment>, pub csv_deployment: Option<Deployment>,
/// BIP141, BIP143, BIP147 deployment
pub segwit_deployment: Option<Deployment>,
/// Interval (in blocks) to calculate average work. /// Interval (in blocks) to calculate average work.
pub pow_averaging_window: u32, pub pow_averaging_window: u32,
@ -45,7 +43,6 @@ impl ConsensusParams {
bip34_height: 1, bip34_height: 1,
bip65_height: 0, bip65_height: 0,
bip66_height: 0, bip66_height: 0,
segwit_deployment: None,
rule_change_activation_threshold: 1916, // 95% rule_change_activation_threshold: 1916, // 95%
miner_confirmation_window: 2016, miner_confirmation_window: 2016,
csv_deployment: None, csv_deployment: None,
@ -61,7 +58,6 @@ impl ConsensusParams {
bip34_height: 1, bip34_height: 1,
bip65_height: 0, bip65_height: 0,
bip66_height: 0, bip66_height: 0,
segwit_deployment: None,
rule_change_activation_threshold: 1512, // 75% rule_change_activation_threshold: 1512, // 75%
miner_confirmation_window: 2016, miner_confirmation_window: 2016,
csv_deployment: None, csv_deployment: None,
@ -77,7 +73,6 @@ impl ConsensusParams {
bip34_height: 100000000, bip34_height: 100000000,
bip65_height: 0, bip65_height: 0,
bip66_height: 0, bip66_height: 0,
segwit_deployment: None,
rule_change_activation_threshold: 108, // 75% rule_change_activation_threshold: 108, // 75%
miner_confirmation_window: 144, miner_confirmation_window: 144,
csv_deployment: None, csv_deployment: None,

View File

@ -87,8 +87,8 @@ impl BlockChainClientCoreApi for BlockChainClientCore {
VerboseBlock { VerboseBlock {
confirmations: confirmations, confirmations: confirmations,
size: block_size as u32, size: block_size as u32,
strippedsize: block_size as u32, // TODO: segwit strippedsize: block_size as u32,
weight: block_size as u32, // TODO: segwit weight: block_size as u32,
height: height, height: height,
mediantime: Some(median_time), mediantime: Some(median_time),
difficulty: block.header.raw.bits.to_f64(self.network.max_bits().into()), difficulty: block.header.raw.bits.to_f64(self.network.max_bits().into()),

View File

@ -11,8 +11,6 @@ pub enum ScriptType {
ScriptHash, ScriptHash,
Multisig, Multisig,
NullData, NullData,
WitnessScript,
WitnessKey,
} }
impl From<GlobalScriptType> for ScriptType { impl From<GlobalScriptType> for ScriptType {
@ -24,8 +22,6 @@ impl From<GlobalScriptType> for ScriptType {
GlobalScriptType::ScriptHash => ScriptType::ScriptHash, GlobalScriptType::ScriptHash => ScriptType::ScriptHash,
GlobalScriptType::Multisig => ScriptType::Multisig, GlobalScriptType::Multisig => ScriptType::Multisig,
GlobalScriptType::NullData => ScriptType::NullData, GlobalScriptType::NullData => ScriptType::NullData,
GlobalScriptType::WitnessScript => ScriptType::WitnessScript,
GlobalScriptType::WitnessKey => ScriptType::WitnessKey,
} }
} }
} }
@ -39,8 +35,6 @@ impl Serialize for ScriptType {
ScriptType::ScriptHash => "scripthash".serialize(serializer), ScriptType::ScriptHash => "scripthash".serialize(serializer),
ScriptType::Multisig => "multisig".serialize(serializer), ScriptType::Multisig => "multisig".serialize(serializer),
ScriptType::NullData => "nulldata".serialize(serializer), ScriptType::NullData => "nulldata".serialize(serializer),
ScriptType::WitnessScript => "witness_v0_scripthash".serialize(serializer),
ScriptType::WitnessKey => "witness_v0_keyhash".serialize(serializer),
} }
} }
} }
@ -66,8 +60,6 @@ impl<'a> Deserialize<'a> for ScriptType {
"scripthash" => Ok(ScriptType::ScriptHash), "scripthash" => Ok(ScriptType::ScriptHash),
"multisig" => Ok(ScriptType::Multisig), "multisig" => Ok(ScriptType::Multisig),
"nulldata" => Ok(ScriptType::NullData), "nulldata" => Ok(ScriptType::NullData),
"witness_v0_scripthash" => Ok(ScriptType::WitnessScript),
"witness_v0_keyhash" => Ok(ScriptType::WitnessKey),
_ => Err(E::invalid_value(Unexpected::Str(value), &self)), _ => Err(E::invalid_value(Unexpected::Str(value), &self)),
} }
} }
@ -90,8 +82,6 @@ mod tests {
assert_eq!(serde_json::to_string(&ScriptType::ScriptHash).unwrap(), r#""scripthash""#); assert_eq!(serde_json::to_string(&ScriptType::ScriptHash).unwrap(), r#""scripthash""#);
assert_eq!(serde_json::to_string(&ScriptType::Multisig).unwrap(), r#""multisig""#); assert_eq!(serde_json::to_string(&ScriptType::Multisig).unwrap(), r#""multisig""#);
assert_eq!(serde_json::to_string(&ScriptType::NullData).unwrap(), r#""nulldata""#); assert_eq!(serde_json::to_string(&ScriptType::NullData).unwrap(), r#""nulldata""#);
assert_eq!(serde_json::to_string(&ScriptType::WitnessScript).unwrap(), r#""witness_v0_scripthash""#);
assert_eq!(serde_json::to_string(&ScriptType::WitnessKey).unwrap(), r#""witness_v0_keyhash""#);
} }
#[test] #[test]
@ -102,7 +92,5 @@ mod tests {
assert_eq!(serde_json::from_str::<ScriptType>(r#""scripthash""#).unwrap(), ScriptType::ScriptHash); assert_eq!(serde_json::from_str::<ScriptType>(r#""scripthash""#).unwrap(), ScriptType::ScriptHash);
assert_eq!(serde_json::from_str::<ScriptType>(r#""multisig""#).unwrap(), ScriptType::Multisig); assert_eq!(serde_json::from_str::<ScriptType>(r#""multisig""#).unwrap(), ScriptType::Multisig);
assert_eq!(serde_json::from_str::<ScriptType>(r#""nulldata""#).unwrap(), ScriptType::NullData); assert_eq!(serde_json::from_str::<ScriptType>(r#""nulldata""#).unwrap(), ScriptType::NullData);
assert_eq!(serde_json::from_str::<ScriptType>(r#""witness_v0_scripthash""#).unwrap(), ScriptType::WitnessScript);
assert_eq!(serde_json::from_str::<ScriptType>(r#""witness_v0_keyhash""#).unwrap(), ScriptType::WitnessKey);
} }
} }

View File

@ -45,8 +45,6 @@ pub enum Error {
// BIP62 // BIP62
SignatureHashtype, SignatureHashtype,
SignatureDer, SignatureDer,
SignatureIllegalForkId,
SignatureMustUseForkId,
Minimaldata, Minimaldata,
SignaturePushOnly, SignaturePushOnly,
SignatureHighS, SignatureHighS,
@ -57,15 +55,6 @@ pub enum Error {
// Softfork safeness // Softfork safeness
DiscourageUpgradableNops, DiscourageUpgradableNops,
DiscourageUpgradableWitnessProgram, DiscourageUpgradableWitnessProgram,
// SegWit-related errors
WitnessProgramWrongLength,
WitnessProgramWitnessEmpty,
WitnessProgramMismatch,
WitnessMalleated,
WitnessMalleatedP2SH,
WitnessUnexpected,
WitnessPubKeyType,
} }
impl fmt::Display for Error { impl fmt::Display for Error {
@ -110,8 +99,6 @@ impl fmt::Display for Error {
// BIP62 // BIP62
Error::SignatureHashtype => "Invalid Signature Hashtype".fmt(f), Error::SignatureHashtype => "Invalid Signature Hashtype".fmt(f),
Error::SignatureDer => "Invalid Signature".fmt(f), Error::SignatureDer => "Invalid Signature".fmt(f),
Error::SignatureIllegalForkId => "Illegal use of SIGHASH_FORKID".fmt(f),
Error::SignatureMustUseForkId => "Signature must use SIGHASH_FORKID".fmt(f),
Error::Minimaldata => "Check minimaldata failed".fmt(f), Error::Minimaldata => "Check minimaldata failed".fmt(f),
Error::SignaturePushOnly => "Only push opcodes are allowed in this signature".fmt(f), Error::SignaturePushOnly => "Only push opcodes are allowed in this signature".fmt(f),
Error::SignatureHighS => "Invalid High S in Signature".fmt(f), Error::SignatureHighS => "Invalid High S in Signature".fmt(f),
@ -122,15 +109,6 @@ impl fmt::Display for Error {
// Softfork safeness // Softfork safeness
Error::DiscourageUpgradableNops => "Discourage Upgradable Nops".fmt(f), Error::DiscourageUpgradableNops => "Discourage Upgradable Nops".fmt(f),
Error::DiscourageUpgradableWitnessProgram => "Discourage Upgradable Witness Program".fmt(f), Error::DiscourageUpgradableWitnessProgram => "Discourage Upgradable Witness Program".fmt(f),
// SegWit-related errors
Error::WitnessProgramWrongLength => "Witness program has incorrect length".fmt(f),
Error::WitnessProgramWitnessEmpty => "Witness program was passed an empty witness".fmt(f),
Error::WitnessProgramMismatch => "Witness program hash mismatch".fmt(f),
Error::WitnessMalleated => "Witness requires empty scriptSig".fmt(f),
Error::WitnessMalleatedP2SH => "Witness requires only-redeemscript scriptSig".fmt(f),
Error::WitnessUnexpected => "Witness provided for non-witness script".fmt(f),
Error::WitnessPubKeyType => "Using non-compressed keys in segwit".fmt(f),
} }
} }
} }

View File

@ -3,10 +3,10 @@ use bytes::Bytes;
use keys::{Message, Signature, Public}; use keys::{Message, Signature, Public};
use chain::constants::SEQUENCE_LOCKTIME_DISABLE_FLAG; use chain::constants::SEQUENCE_LOCKTIME_DISABLE_FLAG;
use crypto::{sha1, sha256, dhash160, dhash256, ripemd160}; use crypto::{sha1, sha256, dhash160, dhash256, ripemd160};
use sign::{SignatureVersion, Sighash}; use sign::Sighash;
use script::MAX_SCRIPT_ELEMENT_SIZE; use script::MAX_SCRIPT_ELEMENT_SIZE;
use { use {
script, Builder, Script, ScriptWitness, Num, VerificationFlags, Opcode, Error, SignatureChecker, Stack script, Builder, Script, Num, VerificationFlags, Opcode, Error, SignatureChecker, Stack
}; };
/// Helper function. /// Helper function.
@ -15,7 +15,6 @@ fn check_signature(
mut script_sig: Vec<u8>, mut script_sig: Vec<u8>,
public: Vec<u8>, public: Vec<u8>,
script_code: &Script, script_code: &Script,
version: SignatureVersion
) -> bool { ) -> bool {
let public = match Public::from_slice(&public) { let public = match Public::from_slice(&public) {
Ok(public) => public, Ok(public) => public,
@ -29,7 +28,7 @@ fn check_signature(
let hash_type = script_sig.pop().unwrap() as u32; let hash_type = script_sig.pop().unwrap() as u32;
let signature = script_sig.into(); let signature = script_sig.into();
checker.check_signature(&signature, &public, script_code, hash_type, version) checker.check_signature(&signature, &public, script_code, hash_type)
} }
/// Helper function. /// Helper function.
@ -169,19 +168,15 @@ fn is_low_der_signature(sig: &[u8]) -> Result<(), Error> {
Ok(()) Ok(())
} }
fn is_defined_hashtype_signature(version: SignatureVersion, sig: &[u8]) -> bool { fn is_defined_hashtype_signature(sig: &[u8]) -> bool {
if sig.is_empty() { if sig.is_empty() {
return false; return false;
} }
Sighash::is_defined(version, sig[sig.len() - 1] as u32) Sighash::is_defined(sig[sig.len() - 1] as u32)
} }
fn parse_hash_type(version: SignatureVersion, sig: &[u8]) -> Sighash { fn check_signature_encoding(sig: &[u8], flags: &VerificationFlags) -> Result<(), Error> {
Sighash::from_u32(version, if sig.is_empty() { 0 } else { sig[sig.len() - 1] as u32 })
}
fn check_signature_encoding(sig: &[u8], flags: &VerificationFlags, version: SignatureVersion) -> Result<(), Error> {
// Empty signature. Not strictly DER encoded, but allowed to provide a // Empty signature. Not strictly DER encoded, but allowed to provide a
// compact way to provide an invalid signature for use with CHECK(MULTI)SIG // compact way to provide an invalid signature for use with CHECK(MULTI)SIG
@ -197,21 +192,10 @@ fn check_signature_encoding(sig: &[u8], flags: &VerificationFlags, version: Sign
is_low_der_signature(sig)?; is_low_der_signature(sig)?;
} }
if flags.verify_strictenc && !is_defined_hashtype_signature(version, sig) { if flags.verify_strictenc && !is_defined_hashtype_signature(sig) {
return Err(Error::SignatureHashtype) return Err(Error::SignatureHashtype)
} }
// verify_strictenc is currently enabled for BitcoinCash only
if flags.verify_strictenc {
let uses_fork_id = parse_hash_type(version, sig).fork_id;
let enabled_fork_id = version == SignatureVersion::ForkId;
if uses_fork_id && !enabled_fork_id {
return Err(Error::SignatureIllegalForkId)
} else if !uses_fork_id && enabled_fork_id {
return Err(Error::SignatureMustUseForkId);
}
}
Ok(()) Ok(())
} }
@ -264,10 +248,8 @@ fn cast_to_bool(data: &[u8]) -> bool {
pub fn verify_script( pub fn verify_script(
script_sig: &Script, script_sig: &Script,
script_pubkey: &Script, script_pubkey: &Script,
witness: &ScriptWitness,
flags: &VerificationFlags, flags: &VerificationFlags,
checker: &SignatureChecker, checker: &SignatureChecker,
version: SignatureVersion,
) -> Result<(), Error> { ) -> Result<(), Error> {
if flags.verify_sigpushonly && !script_sig.is_push_only() { if flags.verify_sigpushonly && !script_sig.is_push_only() {
return Err(Error::SignaturePushOnly); return Err(Error::SignaturePushOnly);
@ -275,35 +257,18 @@ pub fn verify_script(
let mut stack = Stack::new(); let mut stack = Stack::new();
let mut stack_copy = Stack::new(); let mut stack_copy = Stack::new();
let mut had_witness = false;
eval_script(&mut stack, script_sig, flags, checker, version)?; eval_script(&mut stack, script_sig, flags, checker)?;
if flags.verify_p2sh { if flags.verify_p2sh {
stack_copy = stack.clone(); stack_copy = stack.clone();
} }
let res = eval_script(&mut stack, script_pubkey, flags, checker, version)?; let res = eval_script(&mut stack, script_pubkey, flags, checker)?;
if !res { if !res {
return Err(Error::EvalFalse); return Err(Error::EvalFalse);
} }
// Verify witness program
let mut verify_cleanstack = flags.verify_cleanstack;
if flags.verify_witness {
if let Some((witness_version, witness_program)) = script_pubkey.parse_witness_program() {
if !script_sig.is_empty() {
return Err(Error::WitnessMalleated);
}
had_witness = true;
verify_cleanstack = false;
if !verify_witness_program(witness, witness_version, witness_program, flags, checker)? {
return Err(Error::EvalFalse);
}
}
}
// Additional validation for spend-to-script-hash transactions: // Additional validation for spend-to-script-hash transactions:
if flags.verify_p2sh && script_pubkey.is_pay_to_script_hash() { if flags.verify_p2sh && script_pubkey.is_pay_to_script_hash() {
if !script_sig.is_push_only() { if !script_sig.is_push_only() {
@ -319,118 +284,27 @@ pub fn verify_script(
let pubkey2: Script = stack.pop()?.into(); let pubkey2: Script = stack.pop()?.into();
let res = eval_script(&mut stack, &pubkey2, flags, checker, version)?; let res = eval_script(&mut stack, &pubkey2, flags, checker)?;
if !res { if !res {
return Err(Error::EvalFalse); return Err(Error::EvalFalse);
} }
if flags.verify_witness {
if let Some((witness_version, witness_program)) = pubkey2.parse_witness_program() {
if script_sig != &Builder::default().push_data(&pubkey2).into_script() {
return Err(Error::WitnessMalleatedP2SH);
}
had_witness = true;
verify_cleanstack = false;
if !verify_witness_program(witness, witness_version, witness_program, flags, checker)? {
return Err(Error::EvalFalse);
}
}
}
} }
// The CLEANSTACK check is only performed after potential P2SH evaluation, // The CLEANSTACK check is only performed after potential P2SH evaluation,
// as the non-P2SH evaluation of a P2SH script will obviously not result in // as the non-P2SH evaluation of a P2SH script will obviously not result in
// a clean stack (the P2SH inputs remain). The same holds for witness evaluation. // a clean stack (the P2SH inputs remain). The same holds for witness evaluation.
if verify_cleanstack { if flags.verify_cleanstack {
// Disallow CLEANSTACK without P2SH, as otherwise a switch CLEANSTACK->P2SH+CLEANSTACK // Disallow CLEANSTACK without P2SH, as otherwise a switch CLEANSTACK->P2SH+CLEANSTACK
// would be possible, which is not a softfork (and P2SH should be one). // would be possible, which is not a softfork (and P2SH should be one).
assert!(flags.verify_p2sh); assert!(flags.verify_p2sh);
if stack.len() != 1 { if stack.len() != 1 {
return Err(Error::Cleanstack); return Err(Error::Cleanstack);
} }
} }
if flags.verify_witness {
// We can't check for correct unexpected witness data if P2SH was off, so require
// that WITNESS implies P2SH. Otherwise, going from WITNESS->P2SH+WITNESS would be
// possible, which is not a softfork.
assert!(flags.verify_p2sh);
if !had_witness && !witness.is_empty() {
return Err(Error::WitnessUnexpected);
}
}
Ok(()) Ok(())
} }
fn verify_witness_program(
witness: &ScriptWitness,
witness_version: u8,
witness_program: &[u8],
flags: &VerificationFlags,
checker: &SignatureChecker,
) -> Result<bool, Error> {
if witness_version != 0 {
if flags.verify_discourage_upgradable_witness_program {
return Err(Error::DiscourageUpgradableWitnessProgram);
}
return Ok(true);
}
let witness_stack = witness;
let witness_stack_len = witness_stack.len();
let (mut stack, script_pubkey): (Stack<_>, Script) = match witness_program.len() {
32 => {
if witness_stack_len == 0 {
return Err(Error::WitnessProgramWitnessEmpty);
}
let script_pubkey = &witness_stack[witness_stack_len - 1];
let stack = &witness_stack[0..witness_stack_len - 1];
let script_pubkey_hash = sha256(script_pubkey);
if script_pubkey_hash != witness_program[0..32].into() {
return Err(Error::WitnessProgramMismatch);
}
(stack.iter().cloned().collect::<Vec<_>>().into(), Script::new(script_pubkey.clone()))
},
20 => {
if witness_stack_len != 2 {
return Err(Error::WitnessProgramMismatch);
}
let script_pubkey = Builder::default()
.push_opcode(Opcode::OP_DUP)
.push_opcode(Opcode::OP_HASH160)
.push_data(witness_program)
.push_opcode(Opcode::OP_EQUALVERIFY)
.push_opcode(Opcode::OP_CHECKSIG)
.into_script();
(witness_stack.clone().into(), script_pubkey)
},
_ => return Err(Error::WitnessProgramWrongLength),
};
if stack.iter().any(|s| s.len() > MAX_SCRIPT_ELEMENT_SIZE) {
return Err(Error::PushSize);
}
if !eval_script(&mut stack, &script_pubkey, flags, checker, SignatureVersion::WitnessV0)? {
return Ok(false);
}
if stack.len() != 1 {
return Err(Error::EvalFalse);
}
let success = cast_to_bool(stack.last().expect("stack.len() == 1; last() only returns errors when stack is empty; qed"));
Ok(success)
}
/// Evaluautes the script /// Evaluautes the script
#[cfg_attr(feature="cargo-clippy", allow(match_same_arms))] #[cfg_attr(feature="cargo-clippy", allow(match_same_arms))]
pub fn eval_script( pub fn eval_script(
@ -438,7 +312,6 @@ pub fn eval_script(
script: &Script, script: &Script,
flags: &VerificationFlags, flags: &VerificationFlags,
checker: &SignatureChecker, checker: &SignatureChecker,
version: SignatureVersion
) -> Result<bool, Error> { ) -> Result<bool, Error> {
if script.len() > script::MAX_SCRIPT_SIZE { if script.len() > script::MAX_SCRIPT_SIZE {
return Err(Error::ScriptSize); return Err(Error::ScriptSize);
@ -1024,21 +897,14 @@ pub fn eval_script(
Opcode::OP_CHECKSIG | Opcode::OP_CHECKSIGVERIFY => { Opcode::OP_CHECKSIG | Opcode::OP_CHECKSIGVERIFY => {
let pubkey = stack.pop()?; let pubkey = stack.pop()?;
let signature = stack.pop()?; let signature = stack.pop()?;
let sighash = parse_hash_type(version, &signature);
let mut subscript = script.subscript(begincode); let mut subscript = script.subscript(begincode);
match version { let signature_script = Builder::default().push_data(&*signature).into_script();
SignatureVersion::ForkId if sighash.fork_id => (), subscript = subscript.find_and_delete(&*signature_script);
SignatureVersion::WitnessV0 => (),
SignatureVersion::Base | SignatureVersion::ForkId => {
let signature_script = Builder::default().push_data(&*signature).into_script();
subscript = subscript.find_and_delete(&*signature_script);
},
}
check_signature_encoding(&signature, flags, version)?; check_signature_encoding(&signature, flags)?;
check_pubkey_encoding(&pubkey, flags)?; check_pubkey_encoding(&pubkey, flags)?;
let success = check_signature(checker, signature.into(), pubkey.into(), &subscript, version); let success = check_signature(checker, signature.into(), pubkey.into(), &subscript);
match opcode { match opcode {
Opcode::OP_CHECKSIG => { Opcode::OP_CHECKSIG => {
if success { if success {
@ -1071,17 +937,9 @@ pub fn eval_script(
let sigs = (0..sigs_count).into_iter().map(|_| stack.pop()).collect::<Result<Vec<_>, _>>()?; let sigs = (0..sigs_count).into_iter().map(|_| stack.pop()).collect::<Result<Vec<_>, _>>()?;
let mut subscript = script.subscript(begincode); let mut subscript = script.subscript(begincode);
for signature in &sigs { for signature in &sigs {
let sighash = parse_hash_type(version, &signature); let signature_script = Builder::default().push_data(&*signature).into_script();
match version { subscript = subscript.find_and_delete(&*signature_script);
SignatureVersion::ForkId if sighash.fork_id => (),
SignatureVersion::WitnessV0 => (),
SignatureVersion::Base | SignatureVersion::ForkId => {
let signature_script = Builder::default().push_data(&*signature).into_script();
subscript = subscript.find_and_delete(&*signature_script);
},
}
} }
let mut success = true; let mut success = true;
@ -1092,10 +950,10 @@ pub fn eval_script(
let key = keys[k].clone(); let key = keys[k].clone();
let sig = sigs[s].clone(); let sig = sigs[s].clone();
check_signature_encoding(&sig, flags, version)?; check_signature_encoding(&sig, flags)?;
check_pubkey_encoding(&key, flags)?; check_pubkey_encoding(&key, flags)?;
let ok = check_signature(checker, sig.into(), key.into(), &subscript, version); let ok = check_signature(checker, sig.into(), key.into(), &subscript);
if ok { if ok {
s += 1; s += 1;
} }
@ -1139,7 +997,7 @@ pub fn eval_script(
let message = stack.pop()?; let message = stack.pop()?;
let signature = stack.pop()?; let signature = stack.pop()?;
check_signature_encoding(&signature, flags, version)?; check_signature_encoding(&signature, flags)?;
check_pubkey_encoding(&pubkey, flags)?; check_pubkey_encoding(&pubkey, flags)?;
let signature: Vec<u8> = signature.into(); let signature: Vec<u8> = signature.into();
@ -1187,10 +1045,9 @@ mod tests {
use chain::Transaction; use chain::Transaction;
use crypto::sha256; use crypto::sha256;
use keys::{KeyPair, Private, Message, Network}; use keys::{KeyPair, Private, Message, Network};
use sign::SignatureVersion;
use script::MAX_SCRIPT_ELEMENT_SIZE; use script::MAX_SCRIPT_ELEMENT_SIZE;
use { use {
Opcode, Script, ScriptWitness, VerificationFlags, Builder, Error, Num, TransactionInputSigner, Opcode, Script, VerificationFlags, Builder, Error, Num, TransactionInputSigner,
NoopSignatureChecker, TransactionSignatureChecker, Stack NoopSignatureChecker, TransactionSignatureChecker, Stack
}; };
use super::{eval_script, verify_script, is_public_key}; use super::{eval_script, verify_script, is_public_key};
@ -1212,7 +1069,6 @@ mod tests {
let flags = VerificationFlags::default() let flags = VerificationFlags::default()
.verify_p2sh(true); .verify_p2sh(true);
let checker = NoopSignatureChecker; let checker = NoopSignatureChecker;
let version = SignatureVersion::Base;
let direct: Script = vec![Opcode::OP_PUSHBYTES_1 as u8, 0x5a].into(); let direct: Script = vec![Opcode::OP_PUSHBYTES_1 as u8, 0x5a].into();
let pushdata1: Script = vec![Opcode::OP_PUSHDATA1 as u8, 0x1, 0x5a].into(); let pushdata1: Script = vec![Opcode::OP_PUSHDATA1 as u8, 0x1, 0x5a].into();
let pushdata2: Script = vec![Opcode::OP_PUSHDATA2 as u8, 0x1, 0, 0x5a].into(); let pushdata2: Script = vec![Opcode::OP_PUSHDATA2 as u8, 0x1, 0, 0x5a].into();
@ -1222,10 +1078,10 @@ mod tests {
let mut pushdata1_stack = Stack::new(); let mut pushdata1_stack = Stack::new();
let mut pushdata2_stack = Stack::new(); let mut pushdata2_stack = Stack::new();
let mut pushdata4_stack = Stack::new(); let mut pushdata4_stack = Stack::new();
assert!(eval_script(&mut direct_stack, &direct, &flags, &checker, version).unwrap()); assert!(eval_script(&mut direct_stack, &direct, &flags, &checker).unwrap());
assert!(eval_script(&mut pushdata1_stack, &pushdata1, &flags, &checker, version).unwrap()); assert!(eval_script(&mut pushdata1_stack, &pushdata1, &flags, &checker).unwrap());
assert!(eval_script(&mut pushdata2_stack, &pushdata2, &flags, &checker, version).unwrap()); assert!(eval_script(&mut pushdata2_stack, &pushdata2, &flags, &checker).unwrap());
assert!(eval_script(&mut pushdata4_stack, &pushdata4, &flags, &checker, version).unwrap()); assert!(eval_script(&mut pushdata4_stack, &pushdata4, &flags, &checker).unwrap());
assert_eq!(direct_stack, expected); assert_eq!(direct_stack, expected);
assert_eq!(pushdata1_stack, expected); assert_eq!(pushdata1_stack, expected);
@ -1235,9 +1091,8 @@ mod tests {
fn basic_test_with_flags(script: &Script, flags: &VerificationFlags, expected: Result<bool, Error>, expected_stack: Stack<Bytes>) { fn basic_test_with_flags(script: &Script, flags: &VerificationFlags, expected: Result<bool, Error>, expected_stack: Stack<Bytes>) {
let checker = NoopSignatureChecker; let checker = NoopSignatureChecker;
let version = SignatureVersion::Base;
let mut stack = Stack::new(); let mut stack = Stack::new();
assert_eq!(eval_script(&mut stack, script, &flags, &checker, version), expected); assert_eq!(eval_script(&mut stack, script, &flags, &checker), expected);
if expected.is_ok() { if expected.is_ok() {
assert_eq!(stack, expected_stack); assert_eq!(stack, expected_stack);
} }
@ -2144,7 +1999,7 @@ mod tests {
let output: Script = "76a914df3bd30160e6c6145baaf2c88a8844c13a00d1d588ac".into(); let output: Script = "76a914df3bd30160e6c6145baaf2c88a8844c13a00d1d588ac".into();
let flags = VerificationFlags::default() let flags = VerificationFlags::default()
.verify_p2sh(true); .verify_p2sh(true);
assert_eq!(verify_script(&input, &output, &ScriptWitness::default(), &flags, &checker, SignatureVersion::Base), Ok(())); assert_eq!(verify_script(&input, &output, &flags, &checker), Ok(()));
} }
// https://blockchain.info/rawtx/02b082113e35d5386285094c2829e7e2963fa0b5369fb7f4b79c4c90877dcd3d // https://blockchain.info/rawtx/02b082113e35d5386285094c2829e7e2963fa0b5369fb7f4b79c4c90877dcd3d
@ -2161,7 +2016,7 @@ mod tests {
let output: Script = "a9141a8b0026343166625c7475f01e48b5ede8c0252e87".into(); let output: Script = "a9141a8b0026343166625c7475f01e48b5ede8c0252e87".into();
let flags = VerificationFlags::default() let flags = VerificationFlags::default()
.verify_p2sh(true); .verify_p2sh(true);
assert_eq!(verify_script(&input, &output, &ScriptWitness::default(), &flags, &checker, SignatureVersion::Base), Ok(())); assert_eq!(verify_script(&input, &output, &flags, &checker), Ok(()));
} }
// https://blockchain.info/en/tx/12b5633bad1f9c167d523ad1aa1947b2732a865bf5414eab2f9e5ae5d5c191ba?show_adv=true // https://blockchain.info/en/tx/12b5633bad1f9c167d523ad1aa1947b2732a865bf5414eab2f9e5ae5d5c191ba?show_adv=true
@ -2178,7 +2033,7 @@ mod tests {
let output: Script = "410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac".into(); let output: Script = "410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac".into();
let flags = VerificationFlags::default() let flags = VerificationFlags::default()
.verify_p2sh(true); .verify_p2sh(true);
assert_eq!(verify_script(&input, &output, &ScriptWitness::default(), &flags, &checker, SignatureVersion::Base), Ok(())); assert_eq!(verify_script(&input, &output, &flags, &checker), Ok(()));
} }
// https://blockchain.info/rawtx/fb0a1d8d34fa5537e461ac384bac761125e1bfa7fec286fa72511240fa66864d // https://blockchain.info/rawtx/fb0a1d8d34fa5537e461ac384bac761125e1bfa7fec286fa72511240fa66864d
@ -2195,7 +2050,7 @@ mod tests {
let output: Script = "76a9147a2a3b481ca80c4ba7939c54d9278e50189d94f988ac".into(); let output: Script = "76a9147a2a3b481ca80c4ba7939c54d9278e50189d94f988ac".into();
let flags = VerificationFlags::default() let flags = VerificationFlags::default()
.verify_p2sh(true); .verify_p2sh(true);
assert_eq!(verify_script(&input, &output, &ScriptWitness::default(), &flags, &checker, SignatureVersion::Base), Ok(())); assert_eq!(verify_script(&input, &output, &flags, &checker), Ok(()));
} }
// https://blockchain.info/rawtx/eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb // https://blockchain.info/rawtx/eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb
@ -2213,12 +2068,12 @@ mod tests {
let flags = VerificationFlags::default() let flags = VerificationFlags::default()
.verify_p2sh(true); .verify_p2sh(true);
assert_eq!(verify_script(&input, &output, &ScriptWitness::default(), &flags, &checker, SignatureVersion::Base), Ok(())); assert_eq!(verify_script(&input, &output, &flags, &checker), Ok(()));
let flags = VerificationFlags::default() let flags = VerificationFlags::default()
.verify_p2sh(true) .verify_p2sh(true)
.verify_locktime(true); .verify_locktime(true);
assert_eq!(verify_script(&input, &output, &ScriptWitness::default(), &flags, &checker, SignatureVersion::Base), Err(Error::NumberOverflow)); assert_eq!(verify_script(&input, &output, &flags, &checker), Err(Error::NumberOverflow));
} }
// https://blockchain.info/rawtx/54fabd73f1d20c980a0686bf0035078e07f69c58437e4d586fb29aa0bee9814f // https://blockchain.info/rawtx/54fabd73f1d20c980a0686bf0035078e07f69c58437e4d586fb29aa0bee9814f
@ -2234,7 +2089,7 @@ mod tests {
let input: Script = "483045022100d92e4b61452d91a473a43cde4b469a472467c0ba0cbd5ebba0834e4f4762810402204802b76b7783db57ac1f61d2992799810e173e91055938750815b6d8a675902e014f".into(); let input: Script = "483045022100d92e4b61452d91a473a43cde4b469a472467c0ba0cbd5ebba0834e4f4762810402204802b76b7783db57ac1f61d2992799810e173e91055938750815b6d8a675902e014f".into();
let output: Script = "76009f69905160a56b210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71ad6c".into(); let output: Script = "76009f69905160a56b210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71ad6c".into();
let flags = VerificationFlags::default(); let flags = VerificationFlags::default();
assert_eq!(verify_script(&input, &output, &ScriptWitness::default(), &flags, &checker, SignatureVersion::Base), Ok(())); assert_eq!(verify_script(&input, &output, &flags, &checker), Ok(()));
} }
#[test] #[test]
@ -2287,84 +2142,10 @@ mod tests {
let flags = VerificationFlags::default() let flags = VerificationFlags::default()
.verify_p2sh(true); .verify_p2sh(true);
assert_eq!(verify_script(&input, &output, &ScriptWitness::default(), &flags, &checker, SignatureVersion::Base), Ok(())); assert_eq!(verify_script(&input, &output, &flags, &checker), Ok(()));
} }
#[test]
fn test_script_with_forkid_signature() {
use sign::UnsignedTransactionInput;
use chain::{OutPoint, TransactionOutput};
let key_pair = KeyPair::from_private(Private { network: Network::Mainnet, secret: 1.into(), compressed: false, }).unwrap();
let redeem_script = Builder::default()
.push_data(key_pair.public())
.push_opcode(Opcode::OP_CHECKSIG)
.into_script();
let amount = 12345000000000;
let sighashtype = 0x41; // All + ForkId
let checker = TransactionSignatureChecker {
input_index: 0,
input_amount: amount,
signer: TransactionInputSigner {
version: 1,
inputs: vec![
UnsignedTransactionInput {
previous_output: OutPoint {
hash: 0u8.into(),
index: 0xffffffff,
},
sequence: 0xffffffff,
},
],
outputs: vec![
TransactionOutput {
value: amount,
script_pubkey: redeem_script.to_bytes(),
},
],
lock_time: 0,
},
};
let script_pubkey = redeem_script;
let flags = VerificationFlags::default();
// valid signature
{
let signed_input = checker.signer.signed_input(&key_pair, 0, amount, &script_pubkey, SignatureVersion::ForkId, sighashtype);
let script_sig = signed_input.script_sig.into();
assert_eq!(verify_script(&script_sig, &script_pubkey, &ScriptWitness::default(), &flags, &checker, SignatureVersion::ForkId), Ok(()));
}
// signature with wrong amount
{
let signed_input = checker.signer.signed_input(&key_pair, 0, amount + 1, &script_pubkey, SignatureVersion::ForkId, sighashtype);
let script_sig = signed_input.script_sig.into();
assert_eq!(verify_script(&script_sig, &script_pubkey, &ScriptWitness::default(), &flags, &checker, SignatureVersion::ForkId), Err(Error::EvalFalse));
}
// fork-id signature passed when not expected
{
let signed_input = checker.signer.signed_input(&key_pair, 0, amount + 1, &script_pubkey, SignatureVersion::ForkId, sighashtype);
let script_sig = signed_input.script_sig.into();
assert_eq!(verify_script(&script_sig, &script_pubkey, &ScriptWitness::default(), &flags, &checker, SignatureVersion::Base), Err(Error::EvalFalse));
}
// non-fork-id signature passed when expected
{
let signed_input = checker.signer.signed_input(&key_pair, 0, amount + 1, &script_pubkey, SignatureVersion::Base, 1);
let script_sig = signed_input.script_sig.into();
assert_eq!(verify_script(&script_sig, &script_pubkey, &ScriptWitness::default(), &flags.verify_strictenc(true), &checker, SignatureVersion::ForkId), Err(Error::SignatureMustUseForkId));
}
}
#[test] #[test]
fn op_cat_disabled_by_default() { fn op_cat_disabled_by_default() {
let script = Builder::default() let script = Builder::default()

View File

@ -25,7 +25,7 @@ pub use self::interpreter::{eval_script, verify_script};
pub use self::opcode::Opcode; pub use self::opcode::Opcode;
pub use self::num::Num; pub use self::num::Num;
pub use self::script::{Script, ScriptType, ScriptAddress, ScriptWitness, is_witness_commitment_script}; pub use self::script::{Script, ScriptType, ScriptAddress, ScriptWitness, is_witness_commitment_script};
pub use self::sign::{TransactionInputSigner, UnsignedTransactionInput, SignatureVersion}; pub use self::sign::{TransactionInputSigner, UnsignedTransactionInput};
pub use self::stack::Stack; pub use self::stack::Stack;
pub use self::verify::{SignatureChecker, NoopSignatureChecker, TransactionSignatureChecker}; pub use self::verify::{SignatureChecker, NoopSignatureChecker, TransactionSignatureChecker};

View File

@ -26,8 +26,6 @@ pub enum ScriptType {
ScriptHash, ScriptHash,
Multisig, Multisig,
NullData, NullData,
WitnessScript,
WitnessKey,
} }
/// Address from Script /// Address from Script
@ -350,10 +348,6 @@ impl Script {
ScriptType::Multisig ScriptType::Multisig
} else if self.is_null_data_script() { } else if self.is_null_data_script() {
ScriptType::NullData ScriptType::NullData
} else if self.is_pay_to_witness_key_hash() {
ScriptType::WitnessKey
} else if self.is_pay_to_witness_script_hash() {
ScriptType::WitnessScript
} else { } else {
ScriptType::NonStandard ScriptType::NonStandard
} }
@ -448,12 +442,6 @@ impl Script {
ScriptType::NullData => { ScriptType::NullData => {
Ok(vec![]) Ok(vec![])
}, },
ScriptType::WitnessScript => {
Ok(vec![]) // TODO
},
ScriptType::WitnessKey => {
Ok(vec![]) // TODO
},
} }
} }

View File

@ -8,13 +8,6 @@ use ser::Stream;
use chain::{Transaction, TransactionOutput, OutPoint, TransactionInput}; use chain::{Transaction, TransactionOutput, OutPoint, TransactionInput};
use {Script, Builder}; use {Script, Builder};
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum SignatureVersion {
Base,
WitnessV0,
ForkId,
}
#[derive(Debug, PartialEq, Clone, Copy)] #[derive(Debug, PartialEq, Clone, Copy)]
#[repr(u8)] #[repr(u8)]
pub enum SighashBase { pub enum SighashBase {
@ -65,12 +58,9 @@ impl Sighash {
} }
/// Used by SCRIPT_VERIFY_STRICTENC /// Used by SCRIPT_VERIFY_STRICTENC
pub fn is_defined(version: SignatureVersion, u: u32) -> bool { pub fn is_defined(u: u32) -> bool {
// reset anyone_can_pay && fork_id (if applicable) bits // reset anyone_can_pay && fork_id (if applicable) bits
let u = match version { let u = u & !(0x80);
SignatureVersion::ForkId => u & !(0x40 | 0x80),
_ => u & !(0x80),
};
// Only exact All | None | Single values are passing this check // Only exact All | None | Single values are passing this check
match u { match u {
@ -80,16 +70,15 @@ impl Sighash {
} }
/// Creates Sighash from any u, even if is_defined() == false /// Creates Sighash from any u, even if is_defined() == false
pub fn from_u32(version: SignatureVersion, u: u32) -> Self { pub fn from_u32(u: u32) -> Self {
let anyone_can_pay = (u & 0x80) == 0x80; let anyone_can_pay = (u & 0x80) == 0x80;
let fork_id = version == SignatureVersion::ForkId && (u & 0x40) == 0x40;
let base = match u & 0x1f { let base = match u & 0x1f {
2 => SighashBase::None, 2 => SighashBase::None,
3 => SighashBase::Single, 3 => SighashBase::Single,
1 | _ => SighashBase::All, 1 | _ => SighashBase::All,
}; };
Sighash::new(base, anyone_can_pay, fork_id) Sighash::new(base, anyone_can_pay, false)
} }
} }
@ -130,41 +119,9 @@ impl From<Transaction> for TransactionInputSigner {
} }
impl TransactionInputSigner { impl TransactionInputSigner {
pub fn signature_hash(&self, input_index: usize, input_amount: u64, script_pubkey: &Script, sigversion: SignatureVersion, sighashtype: u32) -> H256 { pub fn signature_hash(&self, input_index: usize, script_pubkey: &Script, sighashtype: u32) -> H256 {
let sighash = Sighash::from_u32(sigversion, sighashtype); let sighash = Sighash::from_u32(sighashtype);
match sigversion { self.signature_hash_original(input_index, script_pubkey, sighashtype, sighash)
SignatureVersion::ForkId if sighash.fork_id => self.signature_hash_fork_id(input_index, input_amount, script_pubkey, sighashtype, sighash),
SignatureVersion::Base | SignatureVersion::ForkId => self.signature_hash_original(input_index, script_pubkey, sighashtype, sighash),
SignatureVersion::WitnessV0 => self.signature_hash_witness0(input_index, input_amount, script_pubkey, sighashtype, sighash),
}
}
/// input_index - index of input to sign
/// script_pubkey - script_pubkey of input's previous_output pubkey
pub fn signed_input(
&self,
keypair: &KeyPair,
input_index: usize,
input_amount: u64,
script_pubkey: &Script,
sigversion: SignatureVersion,
sighash: u32,
) -> TransactionInput {
let hash = self.signature_hash(input_index, input_amount, script_pubkey, sigversion, sighash);
let mut signature: Vec<u8> = keypair.private().sign(&hash).unwrap().into();
signature.push(sighash as u8);
let script_sig = Builder::default()
.push_data(&signature)
//.push_data(keypair.public())
.into_script();
let unsigned_input = &self.inputs[input_index];
TransactionInput {
previous_output: unsigned_input.previous_output.clone(),
sequence: unsigned_input.sequence,
script_sig: script_sig.to_bytes(),
}
} }
pub fn signature_hash_original(&self, input_index: usize, script_pubkey: &Script, sighashtype: u32, sighash: Sighash) -> H256 { pub fn signature_hash_original(&self, input_index: usize, script_pubkey: &Script, sighashtype: u32, sighash: Sighash) -> H256 {
@ -232,80 +189,30 @@ impl TransactionInputSigner {
dhash256(&out) dhash256(&out)
} }
fn signature_hash_witness0(&self, input_index: usize, input_amount: u64, script_pubkey: &Script, sighashtype: u32, sighash: Sighash) -> H256 { /// input_index - index of input to sign
let hash_prevouts = compute_hash_prevouts(sighash, &self.inputs); /// script_pubkey - script_pubkey of input's previous_output pubkey
let hash_sequence = compute_hash_sequence(sighash, &self.inputs); pub fn signed_input(
let hash_outputs = compute_hash_outputs(sighash, input_index, &self.outputs); &self,
keypair: &KeyPair,
input_index: usize,
script_pubkey: &Script,
sighash: u32,
) -> TransactionInput {
let hash = self.signature_hash(input_index, script_pubkey, sighash);
let mut stream = Stream::default(); let mut signature: Vec<u8> = keypair.private().sign(&hash).unwrap().into();
stream.append(&self.version); signature.push(sighash as u8);
stream.append(&hash_prevouts); let script_sig = Builder::default()
stream.append(&hash_sequence); .push_data(&signature)
stream.append(&self.inputs[input_index].previous_output); //.push_data(keypair.public())
stream.append_list(&**script_pubkey); .into_script();
stream.append(&input_amount);
stream.append(&self.inputs[input_index].sequence);
stream.append(&hash_outputs);
stream.append(&self.lock_time);
stream.append(&sighashtype); // this also includes 24-bit fork id. which is 0 for BitcoinCash
let out = stream.out();
dhash256(&out)
}
fn signature_hash_fork_id(&self, input_index: usize, input_amount: u64, script_pubkey: &Script, sighashtype: u32, sighash: Sighash) -> H256 { let unsigned_input = &self.inputs[input_index];
if input_index >= self.inputs.len() { TransactionInput {
return 1u8.into(); previous_output: unsigned_input.previous_output.clone(),
sequence: unsigned_input.sequence,
script_sig: script_sig.to_bytes(),
} }
if sighash.base == SighashBase::Single && input_index >= self.outputs.len() {
return 1u8.into();
}
self.signature_hash_witness0(input_index, input_amount, script_pubkey, sighashtype, sighash)
}
}
fn compute_hash_prevouts(sighash: Sighash, inputs: &[UnsignedTransactionInput]) -> H256 {
match sighash.anyone_can_pay {
false => {
let mut stream = Stream::default();
for input in inputs {
stream.append(&input.previous_output);
}
dhash256(&stream.out())
},
true => 0u8.into(),
}
}
fn compute_hash_sequence(sighash: Sighash, inputs: &[UnsignedTransactionInput]) -> H256 {
match sighash.base {
SighashBase::All if !sighash.anyone_can_pay => {
let mut stream = Stream::default();
for input in inputs {
stream.append(&input.sequence);
}
dhash256(&stream.out())
},
_ => 0u8.into(),
}
}
fn compute_hash_outputs(sighash: Sighash, input_index: usize, outputs: &[TransactionOutput]) -> H256 {
match sighash.base {
SighashBase::All => {
let mut stream = Stream::default();
for output in outputs {
stream.append(output);
}
dhash256(&stream.out())
},
SighashBase::Single if input_index < outputs.len() => {
let mut stream = Stream::default();
stream.append(&outputs[input_index]);
dhash256(&stream.out())
},
_ => 0u8.into(),
} }
} }
@ -316,7 +223,7 @@ mod tests {
use keys::{KeyPair, Private, Address}; use keys::{KeyPair, Private, Address};
use chain::{OutPoint, TransactionOutput, Transaction}; use chain::{OutPoint, TransactionOutput, Transaction};
use script::Script; use script::Script;
use super::{Sighash, UnsignedTransactionInput, TransactionInputSigner, SighashBase, SignatureVersion}; use super::{Sighash, UnsignedTransactionInput, TransactionInputSigner, SighashBase};
// http://www.righto.com/2014/02/bitcoins-hard-way-using-raw-bitcoin.html // http://www.righto.com/2014/02/bitcoins-hard-way-using-raw-bitcoin.html
// https://blockchain.info/rawtx/81b4c832d70cb56ff957589752eb4125a4cab78a25a8fc52d6a09e5bd4404d48 // https://blockchain.info/rawtx/81b4c832d70cb56ff957589752eb4125a4cab78a25a8fc52d6a09e5bd4404d48
@ -358,7 +265,7 @@ mod tests {
outputs: vec![output], outputs: vec![output],
}; };
let hash = input_signer.signature_hash(0, 0, &previous_output, SignatureVersion::Base, SighashBase::All.into()); let hash = input_signer.signature_hash(0, &previous_output, SighashBase::All.into());
assert_eq!(hash, expected_signature_hash); assert_eq!(hash, expected_signature_hash);
} }
@ -374,7 +281,7 @@ mod tests {
let script: Script = script.into(); let script: Script = script.into();
let expected = H256::from_reversed_str(result); let expected = H256::from_reversed_str(result);
let sighash = Sighash::from_u32(SignatureVersion::Base, hash_type as u32); let sighash = Sighash::from_u32(hash_type as u32);
let hash = signer.signature_hash_original(input_index, &script, hash_type as u32, sighash); let hash = signer.signature_hash_original(input_index, &script, hash_type as u32, sighash);
assert_eq!(expected, hash); assert_eq!(expected, hash);
} }
@ -888,17 +795,11 @@ mod tests {
#[test] #[test]
fn test_sighash_forkid_from_u32() { fn test_sighash_forkid_from_u32() {
assert!(!Sighash::is_defined(SignatureVersion::Base, 0xFFFFFF82)); assert!(!Sighash::is_defined(0xFFFFFF82));
assert!(!Sighash::is_defined(SignatureVersion::Base, 0x00000182)); assert!(!Sighash::is_defined(0x00000182));
assert!(!Sighash::is_defined(SignatureVersion::Base, 0x00000080)); assert!(!Sighash::is_defined(0x00000080));
assert!( Sighash::is_defined(SignatureVersion::Base, 0x00000001)); assert!( Sighash::is_defined(0x00000001));
assert!( Sighash::is_defined(SignatureVersion::Base, 0x00000082)); assert!( Sighash::is_defined(0x00000082));
assert!( Sighash::is_defined(SignatureVersion::Base, 0x00000003)); assert!( Sighash::is_defined(0x00000003));
assert!(!Sighash::is_defined(SignatureVersion::ForkId, 0xFFFFFFC2));
assert!(!Sighash::is_defined(SignatureVersion::ForkId, 0x000001C2));
assert!( Sighash::is_defined(SignatureVersion::ForkId, 0x00000081));
assert!( Sighash::is_defined(SignatureVersion::ForkId, 0x000000C2));
assert!( Sighash::is_defined(SignatureVersion::ForkId, 0x00000043));
} }
} }

View File

@ -3,7 +3,6 @@ use chain::constants::{
SEQUENCE_FINAL, SEQUENCE_LOCKTIME_DISABLE_FLAG, SEQUENCE_FINAL, SEQUENCE_LOCKTIME_DISABLE_FLAG,
SEQUENCE_LOCKTIME_MASK, SEQUENCE_LOCKTIME_TYPE_FLAG, LOCKTIME_THRESHOLD SEQUENCE_LOCKTIME_MASK, SEQUENCE_LOCKTIME_TYPE_FLAG, LOCKTIME_THRESHOLD
}; };
use sign::SignatureVersion;
use {Script, TransactionInputSigner, Num}; use {Script, TransactionInputSigner, Num};
/// Checks transaction signature /// Checks transaction signature
@ -21,7 +20,6 @@ pub trait SignatureChecker {
public: &Public, public: &Public,
script_code: &Script, script_code: &Script,
sighashtype: u32, sighashtype: u32,
version: SignatureVersion
) -> bool; ) -> bool;
fn check_lock_time(&self, lock_time: Num) -> bool; fn check_lock_time(&self, lock_time: Num) -> bool;
@ -36,7 +34,7 @@ impl SignatureChecker for NoopSignatureChecker {
public.verify(hash, signature).unwrap_or(false) public.verify(hash, signature).unwrap_or(false)
} }
fn check_signature(&self, _: &Signature, _: &Public, _: &Script, _: u32, _: SignatureVersion) -> bool { fn check_signature(&self, _: &Signature, _: &Public, _: &Script, _: u32) -> bool {
false false
} }
@ -72,9 +70,8 @@ impl SignatureChecker for TransactionSignatureChecker {
public: &Public, public: &Public,
script_code: &Script, script_code: &Script,
sighashtype: u32, sighashtype: u32,
version: SignatureVersion
) -> bool { ) -> bool {
let hash = self.signer.signature_hash(self.input_index, self.input_amount, script_code, version, sighashtype); let hash = self.signer.signature_hash(self.input_index, script_code, sighashtype);
self.verify_signature(signature, public, &hash) self.verify_signature(signature, public, &hash)
} }

View File

@ -38,8 +38,6 @@ pub struct MerkleBlockArtefacts {
/// Connected peers /// Connected peers
pub trait Peers : Send + Sync + PeersContainer + PeersFilters + PeersOptions { pub trait Peers : Send + Sync + PeersContainer + PeersFilters + PeersOptions {
/// Require peers services.
fn require_peer_services(&self, services: Services);
/// Get peer connection /// Get peer connection
fn connection(&self, peer_index: PeerIndex) -> Option<OutboundSyncConnectionRef>; fn connection(&self, peer_index: PeerIndex) -> Option<OutboundSyncConnectionRef>;
} }
@ -123,19 +121,6 @@ impl Peer {
} }
impl Peers for PeersImpl { impl Peers for PeersImpl {
fn require_peer_services(&self, services: Services) {
// possible optimization: force p2p level to establish connections to SegWit-nodes only
// without it, all other nodes will be eventually banned (this could take some time, though)
let mut peers = self.peers.write();
for peer_index in peers.iter().filter(|&(_, p)| p.services.includes(&services)).map(|(p, _)| *p).collect::<Vec<_>>() {
let peer = peers.remove(&peer_index).expect("iterating peers keys; qed");
let expected_services: u64 = services.into();
let actual_services: u64 = peer.services.into();
warn!(target: "sync", "Disconnecting from peer#{} because of insufficient services. Expected {:x}, actual: {:x}", peer_index, expected_services, actual_services);
peer.connection.close();
}
}
fn connection(&self, peer_index: PeerIndex) -> Option<OutboundSyncConnectionRef> { fn connection(&self, peer_index: PeerIndex) -> Option<OutboundSyncConnectionRef> {
self.peers.read().get(&peer_index).map(|peer| peer.connection.clone()) self.peers.read().get(&peer_index).map(|peer| peer.connection.clone())
} }

View File

@ -1,6 +1,6 @@
use storage::{TransactionMetaProvider, TransactionOutputProvider}; use storage::{TransactionMetaProvider, TransactionOutputProvider};
use network::{ConsensusParams}; use network::{ConsensusParams};
use script::{Script, verify_script, VerificationFlags, TransactionSignatureChecker, TransactionInputSigner, SignatureVersion}; use script::{Script, verify_script, VerificationFlags, TransactionSignatureChecker, TransactionInputSigner};
use duplex_store::DuplexTransactionOutputProvider; use duplex_store::DuplexTransactionOutputProvider;
use deployments::BlockDeployments; use deployments::BlockDeployments;
use sigops::transaction_sigops; use sigops::transaction_sigops;
@ -275,7 +275,6 @@ pub struct TransactionEval<'a> {
verify_magnetic_anomaly_opcodes: bool, verify_magnetic_anomaly_opcodes: bool,
verify_sigpushonly: bool, verify_sigpushonly: bool,
verify_cleanstack: bool, verify_cleanstack: bool,
signature_version: SignatureVersion,
} }
impl<'a> TransactionEval<'a> { impl<'a> TransactionEval<'a> {
@ -294,7 +293,6 @@ impl<'a> TransactionEval<'a> {
let verify_dersig = height >= params.bip66_height; let verify_dersig = height >= params.bip66_height;
let verify_monolith_opcodes = false; let verify_monolith_opcodes = false;
let verify_magnetic_anomaly_opcodes = false; let verify_magnetic_anomaly_opcodes = false;
let signature_version = SignatureVersion::Base;
let verify_checksequence = deployments.csv(); let verify_checksequence = deployments.csv();
let verify_sigpushonly = verify_magnetic_anomaly_opcodes; let verify_sigpushonly = verify_magnetic_anomaly_opcodes;
@ -314,7 +312,6 @@ impl<'a> TransactionEval<'a> {
verify_magnetic_anomaly_opcodes: verify_magnetic_anomaly_opcodes, verify_magnetic_anomaly_opcodes: verify_magnetic_anomaly_opcodes,
verify_sigpushonly: verify_sigpushonly, verify_sigpushonly: verify_sigpushonly,
verify_cleanstack: verify_cleanstack, verify_cleanstack: verify_cleanstack,
signature_version: signature_version,
} }
} }
@ -366,7 +363,7 @@ impl<'a> TransactionEval<'a> {
.verify_sigpushonly(self.verify_sigpushonly) .verify_sigpushonly(self.verify_sigpushonly)
.verify_cleanstack(self.verify_cleanstack); .verify_cleanstack(self.verify_cleanstack);
try!(verify_script(&input, &output, &Default::default(), &flags, &checker, self.signature_version) try!(verify_script(&input, &output, &flags, &checker)
.map_err(|e| TransactionError::Signature(index, e))); .map_err(|e| TransactionError::Signature(index, e)));
} }

View File

@ -78,17 +78,6 @@ impl Deployments {
None => false None => false
} }
} }
/// Returns true if SegWit deployment is active
pub fn segwit(&self, number: u32, headers: &BlockHeaderProvider, consensus: &ConsensusParams) -> bool {
match consensus.segwit_deployment {
Some(segwit) => {
let mut cache = self.cache.lock();
threshold_state(&mut cache, segwit, number, headers, consensus.miner_confirmation_window, consensus.rule_change_activation_threshold).is_active()
},
None => false
}
}
} }
impl<'a> BlockDeployments<'a> { impl<'a> BlockDeployments<'a> {
@ -104,10 +93,6 @@ impl<'a> BlockDeployments<'a> {
pub fn csv(&self) -> bool { pub fn csv(&self) -> bool {
self.deployments.csv(self.number, self.headers, self.consensus) self.deployments.csv(self.number, self.headers, self.consensus)
} }
pub fn segwit(&self) -> bool {
self.deployments.segwit(self.number, self.headers, self.consensus)
}
} }
impl AsRef<Deployments> for Deployments { impl AsRef<Deployments> for Deployments {