Skip to content

Commit 8158647

Browse files
committed
Add CurrInp to tx value introspection
1 parent 1fcc865 commit 8158647

File tree

4 files changed

+99
-30
lines changed

4 files changed

+99
-30
lines changed

src/extensions/arith.rs

Lines changed: 68 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ pub enum ExprInner {
3636
/// A constant i64 value
3737
/// Minimal push of this <i64>
3838
Const(i64),
39+
/// Value under the current executing input
40+
/// INSPECTCURRENTINPUTINDEX INPSECTINPUTVALUE <1> EQUALVERIFY
41+
CurrInputIdx,
3942
/// Explicit amount at the given input index
4043
/// i INPSECTINPUTVALUE <1> EQUALVERIFY
4144
Input(usize),
@@ -127,6 +130,7 @@ impl Expr {
127130
pub fn from_inner(inner: ExprInner) -> Self {
128131
let (script_size, depth) = match &inner {
129132
ExprInner::Const(_c) => (8 + 1, 0),
133+
ExprInner::CurrInputIdx => (4, 0), // INSPECTCURRENTINPUTINDEX INPSECTINPUTVALUE <1> EQUALVERIFY
130134
ExprInner::Input(i) => (
131135
script_num_size(*i) + 3, // i INPSECTINPUTVALUE <1> EQUALVERIFY
132136
0,
@@ -194,11 +198,22 @@ impl Expr {
194198
/// Evaluate this expression
195199
fn eval(
196200
&self,
201+
curr_ind: usize,
197202
tx: &elements::Transaction,
198203
utxos: &[elements::TxOut],
199204
) -> Result<i64, EvalError> {
200205
match &self.inner {
201206
ExprInner::Const(c) => Ok(*c),
207+
ExprInner::CurrInputIdx => {
208+
if curr_ind >= utxos.len() {
209+
return Err(EvalError::UtxoIndexOutOfBounds(curr_ind, utxos.len()));
210+
}
211+
utxos[curr_ind]
212+
.value
213+
.explicit()
214+
.map(|x| x as i64) // safe conversion bitcoin values from u64 to i64 because 21 mil
215+
.ok_or(EvalError::NonExplicitInput(curr_ind))
216+
}
202217
ExprInner::Input(i) => {
203218
if *i >= utxos.len() {
204219
return Err(EvalError::UtxoIndexOutOfBounds(*i, utxos.len()));
@@ -242,51 +257,51 @@ impl Expr {
242257
.ok_or(EvalError::NonExplicitInputReIssuance(*i))
243258
}
244259
ExprInner::Add(x, y) => {
245-
let x = x.eval(tx, utxos)?;
246-
let y = y.eval(tx, utxos)?;
260+
let x = x.eval(curr_ind, tx, utxos)?;
261+
let y = y.eval(curr_ind, tx, utxos)?;
247262
x.checked_add(y).ok_or(EvalError::AddOverflow(x, y))
248263
}
249264
ExprInner::Sub(x, y) => {
250-
let x = x.eval(tx, utxos)?;
251-
let y = y.eval(tx, utxos)?;
265+
let x = x.eval(curr_ind, tx, utxos)?;
266+
let y = y.eval(curr_ind, tx, utxos)?;
252267
x.checked_sub(y).ok_or(EvalError::SubOverflow(x, y))
253268
}
254269
ExprInner::Mul(x, y) => {
255-
let x = x.eval(tx, utxos)?;
256-
let y = y.eval(tx, utxos)?;
270+
let x = x.eval(curr_ind, tx, utxos)?;
271+
let y = y.eval(curr_ind, tx, utxos)?;
257272
x.checked_mul(y).ok_or(EvalError::MulOverflow(x, y))
258273
}
259274
ExprInner::Div(x, y) => {
260-
let x = x.eval(tx, utxos)?;
261-
let y = y.eval(tx, utxos)?;
275+
let x = x.eval(curr_ind, tx, utxos)?;
276+
let y = y.eval(curr_ind, tx, utxos)?;
262277
x.checked_div_euclid(y).ok_or(EvalError::DivOverflow(x, y))
263278
}
264279
ExprInner::Mod(x, y) => {
265-
let x = x.eval(tx, utxos)?;
266-
let y = y.eval(tx, utxos)?;
280+
let x = x.eval(curr_ind, tx, utxos)?;
281+
let y = y.eval(curr_ind, tx, utxos)?;
267282
x.checked_rem_euclid(y).ok_or(EvalError::ModOverflow(x, y))
268283
}
269284
ExprInner::BitAnd(x, y) => {
270-
let x = x.eval(tx, utxos)?;
271-
let y = y.eval(tx, utxos)?;
285+
let x = x.eval(curr_ind, tx, utxos)?;
286+
let y = y.eval(curr_ind, tx, utxos)?;
272287
Ok(x & y)
273288
}
274289
ExprInner::BitOr(x, y) => {
275-
let x = x.eval(tx, utxos)?;
276-
let y = y.eval(tx, utxos)?;
290+
let x = x.eval(curr_ind, tx, utxos)?;
291+
let y = y.eval(curr_ind, tx, utxos)?;
277292
Ok(x | y)
278293
}
279294
ExprInner::Xor(x, y) => {
280-
let x = x.eval(tx, utxos)?;
281-
let y = y.eval(tx, utxos)?;
295+
let x = x.eval(curr_ind, tx, utxos)?;
296+
let y = y.eval(curr_ind, tx, utxos)?;
282297
Ok(x ^ y)
283298
}
284299
ExprInner::Invert(x) => {
285-
let x = x.eval(tx, utxos)?;
300+
let x = x.eval(curr_ind, tx, utxos)?;
286301
Ok(!x)
287302
}
288303
ExprInner::Negate(x) => {
289-
let x = x.eval(tx, utxos)?;
304+
let x = x.eval(curr_ind, tx, utxos)?;
290305
x.checked_neg().ok_or(EvalError::NegOverflow(x))
291306
}
292307
}
@@ -296,6 +311,11 @@ impl Expr {
296311
fn push_to_builder(&self, builder: script::Builder) -> script::Builder {
297312
match &self.inner {
298313
ExprInner::Const(c) => builder.push_slice(&c.to_le_bytes()),
314+
ExprInner::CurrInputIdx => builder
315+
.push_opcode(OP_PUSHCURRENTINPUTINDEX)
316+
.push_opcode(OP_INSPECTINPUTVALUE)
317+
.push_int(1)
318+
.push_opcode(OP_EQUALVERIFY),
299319
ExprInner::Input(i) => builder
300320
.push_int(*i as i64)
301321
.push_opcode(OP_INSPECTINPUTVALUE)
@@ -453,6 +473,12 @@ impl Expr {
453473
let (x, end_pos) = Self::from_tokens(tokens, end_pos)?;
454474
let expr = Expr::from_inner(ExprInner::Mul(Box::new(x), Box::new(y)));
455475
Some((expr, end_pos))
476+
} else if let Some(&[Tk::CurrInp, Tk::InpValue, Tk::Num(1), Tk::Equal, Tk::Verify]) =
477+
tks.get(e.checked_sub(5)?..e)
478+
{
479+
let (x, end_pos) = Self::from_tokens(tokens, e - 5)?;
480+
let expr = Expr::from_inner(ExprInner::Negate(Box::new(x)));
481+
Some((expr, end_pos))
456482
} else if let Some(&[Tk::Div64, Tk::Num(1), Tk::Equal, Tk::Verify, Tk::Nip]) =
457483
tks.get(e.checked_sub(5)?..e)
458484
{
@@ -540,15 +566,16 @@ impl Arith {
540566
/// Evaluate this expression with context given transaction and spent utxos
541567
pub fn eval(
542568
&self,
569+
curr_ind: usize,
543570
tx: &elements::Transaction,
544571
utxos: &[elements::TxOut],
545572
) -> Result<bool, EvalError> {
546573
let res = match self {
547-
Arith::Eq(x, y) => x.eval(tx, utxos)? == y.eval(tx, utxos)?,
548-
Arith::Le(x, y) => x.eval(tx, utxos)? < y.eval(tx, utxos)?,
549-
Arith::Leq(x, y) => x.eval(tx, utxos)? <= y.eval(tx, utxos)?,
550-
Arith::Ge(x, y) => x.eval(tx, utxos)? > y.eval(tx, utxos)?,
551-
Arith::Geq(x, y) => x.eval(tx, utxos)? >= y.eval(tx, utxos)?,
574+
Arith::Eq(x, y) => x.eval(curr_ind, tx, utxos)? == y.eval(curr_ind, tx, utxos)?,
575+
Arith::Le(x, y) => x.eval(curr_ind, tx, utxos)? < y.eval(curr_ind, tx, utxos)?,
576+
Arith::Leq(x, y) => x.eval(curr_ind, tx, utxos)? <= y.eval(curr_ind, tx, utxos)?,
577+
Arith::Ge(x, y) => x.eval(curr_ind, tx, utxos)? > y.eval(curr_ind, tx, utxos)?,
578+
Arith::Geq(x, y) => x.eval(curr_ind, tx, utxos)? >= y.eval(curr_ind, tx, utxos)?,
552579
};
553580
Ok(res)
554581
}
@@ -609,6 +636,7 @@ impl fmt::Display for Expr {
609636
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
610637
match &self.inner {
611638
ExprInner::Const(c) => write!(f, "{}", c),
639+
ExprInner::CurrInputIdx => write!(f, "curr_inp_v"),
612640
ExprInner::Input(i) => write!(f, "inp_v({})", i),
613641
ExprInner::Output(i) => write!(f, "out_v({})", i),
614642
ExprInner::InputIssue(i) => write!(f, "inp_issue_v({})", i),
@@ -631,6 +659,7 @@ impl fmt::Debug for Expr {
631659
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
632660
match &self.inner {
633661
ExprInner::Const(c) => write!(f, "{:?}", c),
662+
ExprInner::CurrInputIdx => write!(f, "curr_inp_v"),
634663
ExprInner::Input(i) => write!(f, "inp_v({:?})", i),
635664
ExprInner::Output(i) => write!(f, "out_v({:?})", i),
636665
ExprInner::InputIssue(i) => write!(f, "inp_issue_v({:?})", i),
@@ -692,6 +721,7 @@ impl FromTree for Expr {
692721
}
693722
match (top.name, top.args.len()) {
694723
("inp_v", 1) => term(top, ExprInner::Input),
724+
("curr_inp_v", 0) => Ok(Expr::from_inner(ExprInner::CurrInputIdx)),
695725
("out_v", 1) => term(top, ExprInner::Output),
696726
("inp_issue_v", 1) => term(top, ExprInner::InputIssue),
697727
("inp_reissue_v", 1) => term(top, ExprInner::InputReIssue),
@@ -845,16 +875,20 @@ impl ParseableExt for Arith {
845875
Pk: ToPublicKey,
846876
S: Satisfier<Pk>,
847877
{
848-
let (tx, utxos) = match (sat.lookup_tx(), sat.lookup_spent_utxos()) {
849-
(Some(tx), Some(utxos)) => (tx, utxos),
878+
let (tx, utxos, curr_idx) = match (
879+
sat.lookup_tx(),
880+
sat.lookup_spent_utxos(),
881+
sat.lookup_curr_inp(),
882+
) {
883+
(Some(tx), Some(utxos), Some(curr_idx)) => (tx, utxos, curr_idx),
850884
_ => {
851885
return Satisfaction {
852886
stack: Witness::Impossible,
853887
has_sig: false,
854888
}
855889
}
856890
};
857-
let wit = match self.eval(tx, utxos) {
891+
let wit = match self.eval(curr_idx, tx, utxos) {
858892
Ok(false) => Witness::Unavailable,
859893
Ok(true) => Witness::empty(),
860894
Err(_e) => Witness::Impossible,
@@ -870,16 +904,20 @@ impl ParseableExt for Arith {
870904
Pk: ToPublicKey,
871905
S: Satisfier<Pk>,
872906
{
873-
let (tx, utxos) = match (sat.lookup_tx(), sat.lookup_spent_utxos()) {
874-
(Some(tx), Some(utxos)) => (tx, utxos),
907+
let (tx, utxos, curr_idx) = match (
908+
sat.lookup_tx(),
909+
sat.lookup_spent_utxos(),
910+
sat.lookup_curr_inp(),
911+
) {
912+
(Some(tx), Some(utxos), Some(curr_idx)) => (tx, utxos, curr_idx),
875913
_ => {
876914
return Satisfaction {
877915
stack: Witness::Impossible,
878916
has_sig: false,
879917
}
880918
}
881919
};
882-
let wit = match self.eval(tx, utxos) {
920+
let wit = match self.eval(curr_idx, tx, utxos) {
883921
Ok(false) => Witness::empty(),
884922
Ok(true) => Witness::Unavailable,
885923
Err(_e) => Witness::Impossible,
@@ -914,7 +952,7 @@ impl ParseableExt for Arith {
914952
.as_ref()
915953
.ok_or(interpreter::Error::ArithError(EvalError::TxEnvNotPresent))?;
916954

917-
match self.eval(txenv.tx(), txenv.spent_utxos()) {
955+
match self.eval(txenv.idx(), txenv.tx(), txenv.spent_utxos()) {
918956
Ok(true) => {
919957
stack.push(interpreter::Element::Satisfied);
920958
Ok(true)

src/extensions/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,4 +477,8 @@ impl<'tx, 'ptx, Pk: ToPublicKey> Satisfier<Pk> for TxEnv<'tx, 'ptx> {
477477
fn lookup_spent_utxos(&self) -> Option<&[elements::TxOut]> {
478478
Some(self.spent_utxos)
479479
}
480+
481+
fn lookup_curr_inp(&self) -> Option<usize> {
482+
Some(self.idx)
483+
}
480484
}

src/miniscript/lex.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ pub enum Token<'s> {
9090
Or,
9191
Xor,
9292
Invert,
93+
CurrInp,
9394
}
9495

9596
impl<'s> fmt::Display for Token<'s> {
@@ -245,6 +246,9 @@ pub fn lex(script: &script::Script) -> Result<Vec<Token<'_>>, Error> {
245246
script::Instruction::Op(opcodes::all::OP_INSPECTINPUTISSUANCE) => {
246247
ret.push(Token::InpIssue);
247248
}
249+
script::Instruction::Op(opcodes::all::OP_PUSHCURRENTINPUTINDEX) => {
250+
ret.push(Token::CurrInp);
251+
}
248252
script::Instruction::Op(opcodes::all::OP_ADD64) => {
249253
ret.push(Token::Add64);
250254
}

src/miniscript/satisfy.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,11 @@ pub trait Satisfier<Pk: MiniscriptKey + ToPublicKey> {
206206
None
207207
}
208208

209+
/// Lookup spent txouts. Required for introspection
210+
fn lookup_curr_inp(&self) -> Option<usize> {
211+
None
212+
}
213+
209214
/// Lookup (msg, sig) for CSFS fragment
210215
fn lookup_csfs_sig(&self, _pk: &XOnlyPublicKey, _msg: &CsfsMsg) -> Option<schnorr::Signature> {
211216
None
@@ -430,6 +435,10 @@ impl<'a, Pk: MiniscriptKey + ToPublicKey, S: Satisfier<Pk>> Satisfier<Pk> for &'
430435
(**self).lookup_tx()
431436
}
432437

438+
fn lookup_curr_inp(&self) -> Option<usize> {
439+
(**self).lookup_curr_inp()
440+
}
441+
433442
fn lookup_csfs_sig(&self, pk: &XOnlyPublicKey, msg: &CsfsMsg) -> Option<schnorr::Signature> {
434443
(**self).lookup_csfs_sig(pk, msg)
435444
}
@@ -545,6 +554,10 @@ impl<'a, Pk: MiniscriptKey + ToPublicKey, S: Satisfier<Pk>> Satisfier<Pk> for &'
545554
(**self).lookup_tx()
546555
}
547556

557+
fn lookup_curr_inp(&self) -> Option<usize> {
558+
(**self).lookup_curr_inp()
559+
}
560+
548561
fn lookup_csfs_sig(&self, pk: &XOnlyPublicKey, msg: &CsfsMsg) -> Option<schnorr::Signature> {
549562
(**self).lookup_csfs_sig(pk, msg)
550563
}
@@ -819,6 +832,16 @@ macro_rules! impl_tuple_satisfier {
819832
None
820833
}
821834

835+
fn lookup_curr_inp(&self) -> Option<usize> {
836+
let &($(ref $ty,)*) = self;
837+
$(
838+
if let Some(result) = $ty.lookup_curr_inp() {
839+
return Some(result);
840+
}
841+
)*
842+
None
843+
}
844+
822845
fn lookup_tx(&self) -> Option<&elements::Transaction> {
823846
let &($(ref $ty,)*) = self;
824847
$(

0 commit comments

Comments
 (0)