@@ -33,9 +33,11 @@ use aluvm::library::{CodeEofError, IsaSeg, LibSite, Read, Write};
33
33
use aluvm:: reg:: { CoreRegs , Reg , Reg16 , Reg32 , RegA , RegS } ;
34
34
use amplify:: num:: { u24, u3, u4} ;
35
35
use amplify:: Wrapper ;
36
+ use secp256k1:: { ecdsa, Message , PublicKey } ;
36
37
37
38
use super :: opcodes:: * ;
38
39
use super :: { ContractStateAccess , VmContext } ;
40
+ use crate :: vm:: OrdOpRef ;
39
41
use crate :: { Assign , AssignmentType , GlobalStateType , MetaType , TypedAssigns } ;
40
42
41
43
#[ derive( Copy , Clone , Ord , PartialOrd , Eq , PartialEq , Hash , Debug , Display ) ]
@@ -170,6 +172,14 @@ pub enum ContractOp<S: ContractStateAccess> {
170
172
#[ display( "sps {0}" ) ]
171
173
Sps ( /** owned state type */ AssignmentType ) ,
172
174
175
+ /// Verifies the signature of a transition against the pubkey in the first argument.
176
+ ///
177
+ /// If the register doesn't contain a valid public key or the operation
178
+ /// signature is missing or invalid, sets `st0` to fail state and terminates
179
+ /// the program.
180
+ #[ display( "vts {0}" ) ]
181
+ Vts ( RegS ) ,
182
+
173
183
/// All other future unsupported operations, which must set `st0` to
174
184
/// `false` and stop the execution.
175
185
#[ display( "fail {0}" ) ]
@@ -196,6 +206,9 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> {
196
206
| ContractOp :: LdM ( _, _) => bset ! [ ] ,
197
207
ContractOp :: Svs ( _) => bset ! [ ] ,
198
208
ContractOp :: Sas ( _) | ContractOp :: Sps ( _) => bset ! [ Reg :: A ( RegA :: A64 , Reg32 :: Reg0 ) ] ,
209
+
210
+ ContractOp :: Vts ( _) => bset ! [ ] ,
211
+
199
212
ContractOp :: Fail ( _, _) => bset ! [ ] ,
200
213
}
201
214
}
@@ -221,6 +234,7 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> {
221
234
ContractOp :: Svs ( _) | ContractOp :: Sas ( _) | ContractOp :: Sps ( _) => {
222
235
bset ! [ ]
223
236
}
237
+ ContractOp :: Vts ( reg) => bset ! [ Reg :: S ( * reg) ] ,
224
238
ContractOp :: Fail ( _, _) => bset ! [ ] ,
225
239
}
226
240
}
@@ -238,6 +252,7 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> {
238
252
| ContractOp :: LdC ( _, _, _) => 8 ,
239
253
ContractOp :: LdM ( _, _) => 6 ,
240
254
ContractOp :: Svs ( _) | ContractOp :: Sas ( _) | ContractOp :: Sps ( _) => 20 ,
255
+ ContractOp :: Vts ( _) => 512 ,
241
256
ContractOp :: Fail ( _, _) => u64:: MAX ,
242
257
}
243
258
}
@@ -268,7 +283,7 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> {
268
283
}
269
284
macro_rules! load_revealed_outputs {
270
285
( $state_type: ident) => { {
271
- let Some ( new_state) = context. op_info. owned_state. get( * $state_type) else {
286
+ let Some ( new_state) = context. op_info. owned_state( ) . get( * $state_type) else {
272
287
fail!( )
273
288
} ;
274
289
match new_state {
@@ -302,7 +317,7 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> {
302
317
* reg,
303
318
context
304
319
. op_info
305
- . owned_state
320
+ . owned_state ( )
306
321
. get ( * state_type)
307
322
. map ( |a| a. len_u16 ( ) ) ,
308
323
) ;
@@ -311,7 +326,11 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> {
311
326
regs. set_n (
312
327
RegA :: A8 ,
313
328
* reg,
314
- context. op_info . global . get ( state_type) . map ( |a| a. len_u16 ( ) ) ,
329
+ context
330
+ . op_info
331
+ . global ( )
332
+ . get ( state_type)
333
+ . map ( |a| a. len_u16 ( ) ) ,
315
334
) ;
316
335
}
317
336
ContractOp :: CnC ( state_type, reg) => {
@@ -347,7 +366,7 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> {
347
366
348
367
let Some ( Ok ( state) ) = context
349
368
. op_info
350
- . owned_state
369
+ . owned_state ( )
351
370
. get ( * state_type)
352
371
. map ( |a| a. into_structured_state_at ( index) )
353
372
else {
@@ -364,7 +383,7 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> {
364
383
365
384
let Some ( Ok ( state) ) = context
366
385
. op_info
367
- . owned_state
386
+ . owned_state ( )
368
387
. get ( * state_type)
369
388
. map ( |a| a. into_fungible_state_at ( index) )
370
389
else {
@@ -380,7 +399,7 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> {
380
399
381
400
let Some ( state) = context
382
401
. op_info
383
- . global
402
+ . global ( )
384
403
. get ( state_type)
385
404
. and_then ( |a| a. get ( index as usize ) )
386
405
else {
@@ -407,7 +426,7 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> {
407
426
regs. set_s16 ( * reg_s, state. borrow ( ) . as_inner ( ) ) ;
408
427
}
409
428
ContractOp :: LdM ( type_id, reg) => {
410
- let Some ( meta) = context. op_info . metadata . get ( type_id) else {
429
+ let Some ( meta) = context. op_info . metadata ( ) . get ( type_id) else {
411
430
fail ! ( )
412
431
} ;
413
432
regs. set_s16 ( * reg, meta. to_inner ( ) ) ;
@@ -463,6 +482,31 @@ impl<S: ContractStateAccess> InstructionSet for ContractOp<S> {
463
482
fail ! ( )
464
483
}
465
484
}
485
+ ContractOp :: Vts ( reg_s) => match context. op_info . op {
486
+ OrdOpRef :: Genesis ( _) => fail ! ( ) ,
487
+ OrdOpRef :: Transition ( transition, _, _, _) => {
488
+ let Some ( pubkey) = regs. s16 ( * reg_s) else {
489
+ fail ! ( )
490
+ } ;
491
+ let Ok ( pubkey) = PublicKey :: from_slice ( & pubkey. to_vec ( ) ) else {
492
+ fail ! ( )
493
+ } ;
494
+ let Some ( ref witness) = transition. signature else {
495
+ fail ! ( )
496
+ } ;
497
+ let sig_bytes = witness. clone ( ) . into_inner ( ) . into_inner ( ) ;
498
+ let Ok ( sig) = ecdsa:: Signature :: from_compact ( & sig_bytes) else {
499
+ fail ! ( )
500
+ } ;
501
+
502
+ let transition_id = context. op_info . id . into_inner ( ) . into_inner ( ) ;
503
+ let msg = Message :: from_digest ( transition_id) ;
504
+
505
+ if sig. verify ( & msg, & pubkey) . is_err ( ) {
506
+ fail ! ( )
507
+ }
508
+ }
509
+ } ,
466
510
// All other future unsupported operations, which must set `st0` to `false`.
467
511
_ => fail ! ( ) ,
468
512
}
@@ -491,6 +535,8 @@ impl<S: ContractStateAccess> Bytecode for ContractOp<S> {
491
535
ContractOp :: Sas ( _) => INSTR_SAS ,
492
536
ContractOp :: Sps ( _) => INSTR_SPS ,
493
537
538
+ ContractOp :: Vts ( _) => INSTR_VTS ,
539
+
494
540
ContractOp :: Fail ( other, _) => * other,
495
541
}
496
542
}
@@ -553,6 +599,8 @@ impl<S: ContractStateAccess> Bytecode for ContractOp<S> {
553
599
ContractOp :: Sas ( owned_type) => writer. write_u16 ( * owned_type) ?,
554
600
ContractOp :: Sps ( owned_type) => writer. write_u16 ( * owned_type) ?,
555
601
602
+ ContractOp :: Vts ( reg_s) => writer. write_u4 ( * reg_s) ?,
603
+
556
604
ContractOp :: Fail ( _, _) => { }
557
605
}
558
606
Ok ( ( ) )
@@ -620,6 +668,8 @@ impl<S: ContractStateAccess> Bytecode for ContractOp<S> {
620
668
INSTR_SAS => Self :: Sas ( reader. read_u16 ( ) ?. into ( ) ) ,
621
669
INSTR_SPS => Self :: Sps ( reader. read_u16 ( ) ?. into ( ) ) ,
622
670
671
+ INSTR_VTS => Self :: Vts ( reader. read_u4 ( ) ?. into ( ) ) ,
672
+
623
673
x => Self :: Fail ( x, PhantomData ) ,
624
674
} )
625
675
}
0 commit comments