simplified iteration over script opcodes
This commit is contained in:
parent
ea409efccd
commit
601a8277a8
|
@ -1917,9 +1917,6 @@ mod tests {
|
||||||
// https://blockchain.info/rawtx/02b082113e35d5386285094c2829e7e2963fa0b5369fb7f4b79c4c90877dcd3d
|
// https://blockchain.info/rawtx/02b082113e35d5386285094c2829e7e2963fa0b5369fb7f4b79c4c90877dcd3d
|
||||||
#[test]
|
#[test]
|
||||||
fn test_check_transaction_multisig() {
|
fn test_check_transaction_multisig() {
|
||||||
let redeem: Script =
|
|
||||||
"524104a882d414e478039cd5b52a92ffb13dd5e6bd4515497439dffd691a0f12af9575fa349b5694ed3155b136f09e63975a1700c9f4d4df849323dac06cf3bd6458cd41046ce31db9bdd543e72fe3039a1f1c047dab87037c36a669ff90e28da1848f640de68c2fe913d363a51154a0c62d7adea1b822d05035077418267b1a1379790187410411ffd36c70776538d079fbae117dc38effafb33304af83ce4894589747aee1ef992f63280567f52f5ba870678b4ab4ff6c8ea600bd217870a8b4f1f09f3a8e8353ae".into();
|
|
||||||
|
|
||||||
let tx: Transaction = "01000000013dcd7d87904c9cb7f4b79f36b5a03f96e2e729284c09856238d5353e1182b00200000000fd5e0100483045022100deeb1f13b5927b5e32d877f3c42a4b028e2e0ce5010fdb4e7f7b5e2921c1dcd2022068631cb285e8c1be9f061d2968a18c3163b780656f30a049effee640e80d9bff01483045022100ee80e164622c64507d243bd949217d666d8b16486e153ac6a1f8e04c351b71a502203691bef46236ca2b4f5e60a82a853a33d6712d6a1e7bf9a65e575aeb7328db8c014cc9524104a882d414e478039cd5b52a92ffb13dd5e6bd4515497439dffd691a0f12af9575fa349b5694ed3155b136f09e63975a1700c9f4d4df849323dac06cf3bd6458cd41046ce31db9bdd543e72fe3039a1f1c047dab87037c36a669ff90e28da1848f640de68c2fe913d363a51154a0c62d7adea1b822d05035077418267b1a1379790187410411ffd36c70776538d079fbae117dc38effafb33304af83ce4894589747aee1ef992f63280567f52f5ba870678b4ab4ff6c8ea600bd217870a8b4f1f09f3a8e8353aeffffffff0130d90000000000001976a914569076ba39fc4ff6a2291d9ea9196d8c08f9c7ab88ac00000000".into();
|
let tx: Transaction = "01000000013dcd7d87904c9cb7f4b79f36b5a03f96e2e729284c09856238d5353e1182b00200000000fd5e0100483045022100deeb1f13b5927b5e32d877f3c42a4b028e2e0ce5010fdb4e7f7b5e2921c1dcd2022068631cb285e8c1be9f061d2968a18c3163b780656f30a049effee640e80d9bff01483045022100ee80e164622c64507d243bd949217d666d8b16486e153ac6a1f8e04c351b71a502203691bef46236ca2b4f5e60a82a853a33d6712d6a1e7bf9a65e575aeb7328db8c014cc9524104a882d414e478039cd5b52a92ffb13dd5e6bd4515497439dffd691a0f12af9575fa349b5694ed3155b136f09e63975a1700c9f4d4df849323dac06cf3bd6458cd41046ce31db9bdd543e72fe3039a1f1c047dab87037c36a669ff90e28da1848f640de68c2fe913d363a51154a0c62d7adea1b822d05035077418267b1a1379790187410411ffd36c70776538d079fbae117dc38effafb33304af83ce4894589747aee1ef992f63280567f52f5ba870678b4ab4ff6c8ea600bd217870a8b4f1f09f3a8e8353aeffffffff0130d90000000000001976a914569076ba39fc4ff6a2291d9ea9196d8c08f9c7ab88ac00000000".into();
|
||||||
let signer: TransactionInputSigner = tx.into();
|
let signer: TransactionInputSigner = tx.into();
|
||||||
let checker = TransactionSignatureChecker {
|
let checker = TransactionSignatureChecker {
|
||||||
|
|
|
@ -92,6 +92,45 @@ impl Script {
|
||||||
Opcode::from_u8(self.data[position]).ok_or(Error::BadOpcode)
|
Opcode::from_u8(self.data[position]).ok_or(Error::BadOpcode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_instruction(&self, position: usize) -> Result<Instruction, Error> {
|
||||||
|
let opcode = try!(self.get_opcode(position));
|
||||||
|
let instruction = match opcode {
|
||||||
|
Opcode::OP_PUSHDATA1 |
|
||||||
|
Opcode::OP_PUSHDATA2 |
|
||||||
|
Opcode::OP_PUSHDATA4 => {
|
||||||
|
let len = match opcode {
|
||||||
|
Opcode::OP_PUSHDATA1 => 1,
|
||||||
|
Opcode::OP_PUSHDATA2 => 2,
|
||||||
|
_ => 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
let slice = try!(self.take(position + 1, len));
|
||||||
|
let n = try!(read_usize(slice, len));
|
||||||
|
let bytes = try!(self.take_checked(position + 1 + len, n));
|
||||||
|
Instruction {
|
||||||
|
opcode: opcode,
|
||||||
|
step: len + n + 1,
|
||||||
|
data: Some(bytes),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
o if o >= Opcode::OP_0 && o <= Opcode::OP_PUSHBYTES_75 => {
|
||||||
|
let bytes = try!(self.take_checked(position+ 1, opcode as usize));
|
||||||
|
Instruction {
|
||||||
|
opcode: o,
|
||||||
|
step: opcode as usize + 1,
|
||||||
|
data: Some(bytes),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => Instruction {
|
||||||
|
opcode: opcode,
|
||||||
|
step: 1,
|
||||||
|
data: None,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(instruction)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn take(&self, offset: usize, len: usize) -> Result<&[u8], Error> {
|
pub fn take(&self, offset: usize, len: usize) -> Result<&[u8], Error> {
|
||||||
if offset + len > self.data.len() {
|
if offset + len > self.data.len() {
|
||||||
|
@ -114,37 +153,21 @@ impl Script {
|
||||||
pub fn without_separators(&self) -> Script {
|
pub fn without_separators(&self) -> Script {
|
||||||
let mut pc = 0;
|
let mut pc = 0;
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
|
|
||||||
while pc < self.len() {
|
while pc < self.len() {
|
||||||
match self.get_opcode(pc) {
|
match self.get_instruction(pc) {
|
||||||
Ok(opcode @ Opcode::OP_PUSHDATA1) |
|
Ok(instruction) => {
|
||||||
Ok(opcode @ Opcode::OP_PUSHDATA2) |
|
if instruction.opcode != Opcode::OP_CODESEPARATOR {
|
||||||
Ok(opcode @ Opcode::OP_PUSHDATA4) => {
|
result.extend_from_slice(&self[pc..pc + instruction.step]);
|
||||||
let len = match opcode {
|
}
|
||||||
Opcode::OP_PUSHDATA1 => 1,
|
|
||||||
Opcode::OP_PUSHDATA2 => 2,
|
|
||||||
_ => 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
let slice = match self.take(pc + 1, len) {
|
pc += instruction.step;
|
||||||
Ok(slice) => slice,
|
|
||||||
_ => {
|
|
||||||
result.extend_from_slice(&self[pc..]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let n = read_usize(slice, len).expect("slice.len() is equal len");
|
|
||||||
result.extend(&self[pc..pc + len + n + 1]);
|
|
||||||
pc += len + n;
|
|
||||||
},
|
},
|
||||||
Ok(o) if o >= Opcode::OP_0 && o <= Opcode::OP_PUSHBYTES_75 => {
|
_ => {
|
||||||
result.extend(&self[pc..pc + o as usize + 1]);
|
result.push(self[pc]);
|
||||||
pc += o as usize;
|
pc += 1;
|
||||||
},
|
}
|
||||||
Ok(Opcode::OP_CODESEPARATOR) => {},
|
|
||||||
_ => result.push(self[pc]),
|
|
||||||
}
|
}
|
||||||
pc += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Script::new(result)
|
Script::new(result)
|
||||||
|
@ -159,6 +182,12 @@ impl ops::Deref for Script {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Instruction<'a> {
|
||||||
|
opcode: Opcode,
|
||||||
|
step: usize,
|
||||||
|
data: Option<&'a [u8]>,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn read_usize(data: &[u8], size: usize) -> Result<usize, Error> {
|
pub fn read_usize(data: &[u8], size: usize) -> Result<usize, Error> {
|
||||||
if data.len() < size {
|
if data.len() < size {
|
||||||
return Err(Error::BadOpcode);
|
return Err(Error::BadOpcode);
|
||||||
|
@ -190,36 +219,18 @@ impl fmt::Debug for Script {
|
||||||
impl fmt::Display for Script {
|
impl fmt::Display for Script {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let mut pc = 0;
|
let mut pc = 0;
|
||||||
|
|
||||||
while pc < self.len() {
|
while pc < self.len() {
|
||||||
let opcode = try_or_fmt!(f, self.get_opcode(pc));
|
let instruction = try_or_fmt!(f, self.get_instruction(pc));
|
||||||
|
|
||||||
match opcode {
|
match instruction.data {
|
||||||
Opcode::OP_PUSHDATA1 |
|
Some(data) => try!(writeln!(f, "{:?} 0x{}", instruction.opcode, data.to_hex())),
|
||||||
Opcode::OP_PUSHDATA2 |
|
None => try!(writeln!(f, "{:?}", instruction.opcode)),
|
||||||
Opcode::OP_PUSHDATA4 => {
|
|
||||||
let len = match opcode {
|
|
||||||
Opcode::OP_PUSHDATA1 => 1,
|
|
||||||
Opcode::OP_PUSHDATA2 => 2,
|
|
||||||
_ => 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
let slice = try_or_fmt!(f, self.take(pc + 1, len));
|
|
||||||
let n = try_or_fmt!(f, read_usize(slice, len));
|
|
||||||
let bytes = try_or_fmt!(f, self.take_checked(pc + 1 + len, n));
|
|
||||||
pc += len + n;
|
|
||||||
try!(writeln!(f, "{:?} 0x{}", opcode, bytes.to_hex()));
|
|
||||||
},
|
|
||||||
o if o >= Opcode::OP_0 && o <= Opcode::OP_PUSHBYTES_75 => {
|
|
||||||
let bytes = try_or_fmt!(f, self.take_checked(pc + 1, opcode as usize));
|
|
||||||
pc += opcode as usize;
|
|
||||||
try!(writeln!(f, "{:?} 0x{}", opcode, bytes.to_hex()));
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
try!(writeln!(f, "{:?}", opcode));
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
pc += 1;
|
|
||||||
|
pc += instruction.step;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue