mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2024-11-19 09:52:09 +01:00
Give ScriptInterpreter
functions to verify a transaction or single input (#1223)
* Add TxSigCompenent constuctor * Add verifyInputScript to ScriptInterpreter * Add tests
This commit is contained in:
parent
45e1a90fba
commit
f6515c6779
@ -8,6 +8,7 @@ import org.bitcoins.core.crypto.{
|
||||
import org.bitcoins.core.currency.CurrencyUnits
|
||||
import org.bitcoins.core.protocol.script._
|
||||
import org.bitcoins.core.protocol.transaction.{
|
||||
Transaction,
|
||||
TransactionOutput,
|
||||
WitnessTransaction
|
||||
}
|
||||
@ -108,4 +109,31 @@ class ScriptInterpreterTest extends BitcoinSUnitTest {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
it must "evaluate a p2sh witness transaction as valid" in {
|
||||
val p2shWitTx = Transaction(
|
||||
"02000000000101c29e1b0bc7d7eef558cab27731e68526c94a8ee30b5a8795674b39b25430dacd0000000017160014471b19074d141d11042cba016cd60d89caee0150feffffff02ee2916000000000017a91401d95721e723fb9d02fa7ae0d5a330925fa6f90187f0e864da0100000017a9149829ca82bf4d71daeffb14a6b96da4e621cccb31870247304402205406cf034993af5fc0dd9fcd96eafe04acedeb9d4d2a012aa539561cd50b6ce30220680079485226ee184c678da475e291e81ca8b83b5b973d0a8513a5b4a7e24c52012103c6350aad80873966c5a778bc3e019eef399d242ef386e21267652ca1f3e3a6ae087a1900")
|
||||
val prevOut = TransactionOutput(
|
||||
"48677bda0100000017a914885437151ad21f21c5c714ddffdf67e56fcd63ea87")
|
||||
|
||||
ScriptInterpreter.verifyTransaction(p2shWitTx, Vector(prevOut))
|
||||
}
|
||||
|
||||
it must "evaluate a witness transaction as valid" in {
|
||||
val wtx = Transaction(
|
||||
"02000000000101b62a936a1389f6f28a71f88be2703800e267bd0501e4fcd7c803a2eb2ca9d96f0000000000feffffff011027000000000000160014bb7e25b0e93a3d378b813e97d5d61efcfa69863e040047304402204e0401cf6bd54c3551a7534f9c04e30701da735693670028a5ccd5c99934df1a02200249b701467f461015bf6643bed692f911b6a43a05f1e18301e61ace743ba788014730440220385f39b54755df27ddc353b24dd83fd236e6ba0c39fefe2a41d2f0145498612b022036d0992f3245d4da79e0cc4562b8b40fb5325d8bc794cfa92d2bd36263fedcef014752210325815e1ecf3cdc683c16be773798b07ce3ca2af6969bb03975c5e0e0c06f7f0521031d8bcc3a6a7e93d904a89c20104f44b0bf6c157b6e761e20f2751381e8ba382452ae1f6d1900")
|
||||
val prevOut = TransactionOutput(
|
||||
"b82a0000000000002200202d501d0b2df21825d3dca7dc2bdaeea2c484c552b4ccbf687ffa887ae47e42c2")
|
||||
|
||||
ScriptInterpreter.verifyTransaction(wtx, Vector(prevOut))
|
||||
}
|
||||
|
||||
it must "evaluate a base transaction as valid" in {
|
||||
val tx = Transaction(
|
||||
"01000000010289c14b991dde643aca30b9010c9b37b8347f3984fa5c31e78adceeea4eefab000000006a47304402206d1ae877e2339ed74a1b203aacdb8e4dc6202f873a228d681d3075f7cd8ef95c022067383abdf0bc1839db0c26a0d77df097d815b4ef086da3872b4a928468b667f30121032fb875942a07a7606933e383c85d688b5fd3482c29035d4289638987582c3f2bffffffff02500e40a10b0000001976a9142301071cf4f2550a705c6348f33e6b33544b768488ac2752fb02000000001976a914741423cca440e7dc81d3468b832433e4db3c924288ac00000000")
|
||||
val prevOut = TransactionOutput(
|
||||
"37733ba40b0000001976a914741423cca440e7dc81d3468b832433e4db3c924288ac")
|
||||
|
||||
ScriptInterpreter.verifyTransaction(tx, Vector(prevOut))
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,43 @@ sealed abstract class TxSigComponent {
|
||||
def sigVersion: SignatureVersion
|
||||
}
|
||||
|
||||
object TxSigComponent {
|
||||
|
||||
def apply(
|
||||
transaction: Transaction,
|
||||
inputIndex: UInt32,
|
||||
output: TransactionOutput,
|
||||
flags: Seq[ScriptFlag]): TxSigComponent = {
|
||||
val scriptSig = transaction.inputs(inputIndex.toInt).scriptSignature
|
||||
output.scriptPubKey match {
|
||||
case _: WitnessScriptPubKey =>
|
||||
transaction match {
|
||||
case _: BaseTransaction =>
|
||||
throw new IllegalArgumentException(
|
||||
s"Cannot spend from segwit output ($output) with a base transaction ($transaction)")
|
||||
case wtx: WitnessTransaction =>
|
||||
WitnessTxSigComponent(wtx, inputIndex, output, flags)
|
||||
}
|
||||
case _: P2SHScriptPubKey =>
|
||||
val p2shScriptSig = scriptSig.asInstanceOf[P2SHScriptSignature]
|
||||
if (WitnessScriptPubKey.isWitnessScriptPubKey(
|
||||
p2shScriptSig.redeemScript.asm)) {
|
||||
transaction match {
|
||||
case _: BaseTransaction =>
|
||||
throw new IllegalArgumentException(
|
||||
s"Cannot spend from segwit output ($output) with a base transaction ($transaction)")
|
||||
case wtx: WitnessTransaction =>
|
||||
WitnessTxSigComponentP2SH(wtx, inputIndex, output, flags)
|
||||
}
|
||||
} else {
|
||||
P2SHTxSigComponent(transaction, inputIndex, output, flags)
|
||||
}
|
||||
case _: RawScriptPubKey =>
|
||||
BaseTxSigComponent(transaction, inputIndex, output, flags)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The [[org.bitcoins.core.crypto.TxSigComponent TxSigComponent]]
|
||||
* used to evaluate the the original Satoshi transaction digest algorithm.
|
||||
|
@ -3,6 +3,8 @@ package org.bitcoins.core.script.interpreter
|
||||
import org.bitcoins.core.consensus.Consensus
|
||||
import org.bitcoins.core.crypto._
|
||||
import org.bitcoins.core.currency.{CurrencyUnit, CurrencyUnits}
|
||||
import org.bitcoins.core.number.UInt32
|
||||
import org.bitcoins.core.policy.Policy
|
||||
import org.bitcoins.core.protocol.CompactSizeUInt
|
||||
import org.bitcoins.core.protocol.script._
|
||||
import org.bitcoins.core.protocol.transaction._
|
||||
@ -177,6 +179,32 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
|
||||
!programs.exists(p => ScriptInterpreter.run(p) != ScriptOk)
|
||||
}
|
||||
|
||||
def verifyInputScript(
|
||||
transaction: Transaction,
|
||||
inputIndex: Long,
|
||||
prevOut: TransactionOutput): Boolean = {
|
||||
val sigComponent = TxSigComponent(
|
||||
transaction,
|
||||
UInt32(inputIndex),
|
||||
prevOut,
|
||||
Policy.standardFlags
|
||||
)
|
||||
ScriptInterpreter.runVerify(PreExecutionScriptProgram(sigComponent))
|
||||
}
|
||||
|
||||
def verifyTransaction(
|
||||
transaction: Transaction,
|
||||
prevOuts: Vector[TransactionOutput]): Boolean = {
|
||||
require(
|
||||
transaction.inputs.size == prevOuts.size,
|
||||
s"There must be a prevOut for every input in the transaction, got ${prevOuts.size}")
|
||||
|
||||
prevOuts.zipWithIndex.forall {
|
||||
case (prevOut, index) =>
|
||||
verifyInputScript(transaction, index, prevOut)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* P2SH scripts are unique in their evaluation, first the scriptSignature must be added to the stack, next the
|
||||
* p2sh scriptPubKey must be run to make sure the serialized redeem script hashes to the value found in the p2sh
|
||||
|
Loading…
Reference in New Issue
Block a user