Skip to content

Commit c3ef1e3

Browse files
committed
iface: make invoice state calculable with AluVM
1 parent 3bc3831 commit c3ef1e3

File tree

9 files changed

+303
-180
lines changed

9 files changed

+303
-180
lines changed

src/containers/file.rs

-2
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,6 @@ mod test {
273273
issuer: Default::default(),
274274
testnet: Default::default(),
275275
alt_layers1: Default::default(),
276-
asset_tags: Default::default(),
277276
metadata: Default::default(),
278277
globals: Default::default(),
279278
assignments: Default::default(),
@@ -371,7 +370,6 @@ mod test {
371370
issuer: Default::default(),
372371
testnet: Default::default(),
373372
alt_layers1: Default::default(),
374-
asset_tags: Default::default(),
375373
metadata: Default::default(),
376374
globals: Default::default(),
377375
assignments: Default::default(),

src/interface/builder.rs

+62-53
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,15 @@ use rgb::validation::Scripts;
2929
use rgb::{
3030
validation, AltLayer1, AltLayer1Set, AssignmentType, Assignments, ContractId, ExposedSeal,
3131
Genesis, GenesisSeal, GlobalState, GraphSeal, Identity, Input, Layer1, MetadataError, Opout,
32-
OwnedStateSchema, Schema, State, Transition, TransitionType, TypedAssigns, XChain, XOutpoint,
32+
Schema, State, Transition, TransitionType, TypedAssigns, XChain, XOutpoint,
3333
};
3434
use rgbcore::{GlobalStateSchema, GlobalStateType, MetaType, Metadata, ValencyType};
3535
use strict_encoding::{FieldName, SerializeError, StrictSerialize};
3636
use strict_types::{decode, SemId, TypeSystem};
3737

3838
use crate::containers::{BuilderSeal, ContainerVer, Contract, ValidConsignment};
3939
use crate::interface::resolver::DumbResolver;
40-
use crate::interface::{Iface, IfaceImpl, TransitionIface};
40+
use crate::interface::{Iface, IfaceImpl, StateCalc, StateCalcError, TransitionIface};
4141
use crate::Outpoint;
4242

4343
#[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)]
@@ -68,19 +68,7 @@ pub enum BuilderError {
6868
/// state `{0}` provided to the builder has invalid type.
6969
InvalidStateType(AssignmentType),
7070

71-
/// asset tag for state `{0}` must be added before any fungible state of
72-
/// the same type.
73-
AssetTagMissed(AssignmentType),
74-
75-
/// asset tag for state `{0}` was already automatically created. Please call
76-
/// `add_asset_tag` before adding any fungible state to the builder.
77-
AssetTagAutomatic(AssignmentType),
78-
79-
/// state data for state type `{0}` are invalid: asset tag doesn't match the
80-
/// tag defined by the contract.
81-
AssetTagInvalid(AssignmentType),
82-
83-
/// interface doesn't specifies default operation name, thus an explicit
71+
/// interface doesn't specify default operation name, thus an explicit
8472
/// operation type must be provided with `set_operation_type` method.
8573
NoOperationSubtype,
8674

@@ -90,6 +78,10 @@ pub enum BuilderError {
9078
/// {0} is not supported by the contract genesis.
9179
InvalidLayer1(Layer1),
9280

81+
#[from]
82+
#[display(inner)]
83+
Calc(StateCalcError),
84+
9385
#[from]
9486
#[display(inner)]
9587
StrictEncode(SerializeError),
@@ -226,13 +218,13 @@ impl ContractBuilder {
226218

227219
pub fn add_owned_state_raw(
228220
mut self,
229-
name: impl Into<FieldName>,
221+
type_id: AssignmentType,
230222
seal: impl Into<BuilderSeal<GenesisSeal>>,
231223
state: State,
232224
) -> Result<Self, BuilderError> {
233225
let seal = seal.into();
234226
self.check_layer1(seal.layer1())?;
235-
self.builder = self.builder.add_owned_state_raw(name, seal, state)?;
227+
self.builder = self.builder.add_owned_state_raw(type_id, seal, state)?;
236228
Ok(self)
237229
}
238230

@@ -306,13 +298,15 @@ impl ContractBuilder {
306298
}
307299
}
308300

309-
#[derive(Clone, Debug)]
301+
#[derive(Debug)]
310302
pub struct TransitionBuilder {
311303
contract_id: ContractId,
312304
builder: OperationBuilder<GraphSeal>,
313305
nonce: u64,
314306
transition_type: TransitionType,
315307
inputs: TinyOrdMap<Input, State>,
308+
// TODO: Remove option once we have blank builder
309+
calc: Option<StateCalc>,
316310
}
317311

318312
impl TransitionBuilder {
@@ -323,7 +317,7 @@ impl TransitionBuilder {
323317
iimpl: IfaceImpl,
324318
types: TypeSystem,
325319
) -> Self {
326-
Self::with(contract_id, iface, schema, iimpl, TransitionType::BLANK, types)
320+
Self::with(contract_id, iface, schema, iimpl, TransitionType::BLANK, types, None)
327321
}
328322

329323
pub fn default_transition(
@@ -332,13 +326,15 @@ impl TransitionBuilder {
332326
schema: Schema,
333327
iimpl: IfaceImpl,
334328
types: TypeSystem,
329+
scripts: Scripts,
335330
) -> Result<Self, BuilderError> {
336331
let transition_type = iface
337332
.default_operation
338333
.as_ref()
339334
.and_then(|name| iimpl.transition_type(name))
340335
.ok_or(BuilderError::NoOperationSubtype)?;
341-
Ok(Self::with(contract_id, iface, schema, iimpl, transition_type, types))
336+
let calc = StateCalc::new(scripts, iimpl.state_abi);
337+
Ok(Self::with(contract_id, iface, schema, iimpl, transition_type, types, Some(calc)))
342338
}
343339

344340
pub fn named_transition(
@@ -348,12 +344,14 @@ impl TransitionBuilder {
348344
iimpl: IfaceImpl,
349345
transition_name: impl Into<FieldName>,
350346
types: TypeSystem,
347+
scripts: Scripts,
351348
) -> Result<Self, BuilderError> {
352349
let transition_name = transition_name.into();
353350
let transition_type = iimpl
354351
.transition_type(&transition_name)
355352
.ok_or(BuilderError::TransitionNotFound(transition_name))?;
356-
Ok(Self::with(contract_id, iface, schema, iimpl, transition_type, types))
353+
let calc = StateCalc::new(scripts, iimpl.state_abi);
354+
Ok(Self::with(contract_id, iface, schema, iimpl, transition_type, types, Some(calc)))
357355
}
358356

359357
fn with(
@@ -363,13 +361,15 @@ impl TransitionBuilder {
363361
iimpl: IfaceImpl,
364362
transition_type: TransitionType,
365363
types: TypeSystem,
364+
calc: Option<StateCalc>,
366365
) -> Self {
367366
Self {
368367
contract_id,
369368
builder: OperationBuilder::with(iface, schema, iimpl, types),
370369
nonce: u64::MAX,
371370
transition_type,
372371
inputs: none!(),
372+
calc,
373373
}
374374
}
375375

@@ -403,6 +403,9 @@ impl TransitionBuilder {
403403
}
404404

405405
pub fn add_input(mut self, opout: Opout, state: State) -> Result<Self, BuilderError> {
406+
if let Some(calc) = &mut self.calc {
407+
calc.reg_input(opout.ty, &state)?;
408+
}
406409
self.inputs.insert(Input::with(opout), state)?;
407410
Ok(self)
408411
}
@@ -430,39 +433,54 @@ impl TransitionBuilder {
430433
self.builder.valency_type(name)
431434
}
432435

436+
#[inline]
433437
pub fn valency_name(&self, type_id: ValencyType) -> &FieldName {
434438
self.builder.valency_name(type_id)
435439
}
436440

437441
pub fn meta_name(&self, type_id: MetaType) -> &FieldName { self.builder.meta_name(type_id) }
438442

443+
/// NB: Doesn't process the state with VM
439444
pub fn add_owned_state_raw(
440445
mut self,
441-
name: impl Into<FieldName>,
446+
type_id: AssignmentType,
442447
seal: impl Into<BuilderSeal<GraphSeal>>,
443448
state: State,
444449
) -> Result<Self, BuilderError> {
445-
self.builder = self.builder.add_owned_state_raw(name, seal, state)?;
450+
self.builder = self.builder.add_owned_state_raw(type_id, seal, state)?;
446451
Ok(self)
447452
}
448453

449-
pub fn add_owned_state(
454+
pub fn fulfill_owned_state(
450455
mut self,
451-
name: impl Into<FieldName>,
456+
type_id: AssignmentType,
452457
seal: impl Into<BuilderSeal<GraphSeal>>,
453-
value: impl StrictSerialize,
454-
) -> Result<Self, BuilderError> {
455-
self.builder = self.builder.add_owned_state(name, seal, value)?;
456-
Ok(self)
457-
}
458-
459-
pub fn add_owned_state_default(
460-
self,
458+
state: State,
459+
) -> Result<(Self, Option<State>), BuilderError> {
460+
let calc = self
461+
.calc
462+
.as_mut()
463+
.expect("you must not call fulfill_owned_state for the blank transition builder");
464+
let state = calc.calc_output(type_id, &state)?;
465+
self.builder = self
466+
.builder
467+
.add_owned_state_raw(type_id, seal, state.sufficient)?;
468+
Ok((self, state.insufficient))
469+
}
470+
471+
pub fn add_owned_state_change(
472+
mut self,
473+
type_id: AssignmentType,
461474
seal: impl Into<BuilderSeal<GraphSeal>>,
462-
value: impl StrictSerialize,
463475
) -> Result<Self, BuilderError> {
464-
let assignment_name = self.default_assignment()?.clone();
465-
self.add_owned_state(assignment_name, seal.into(), value)
476+
let calc = self
477+
.calc
478+
.as_mut()
479+
.expect("you must not call add_owned_state_change for the blank transition builder");
480+
if let Some(state) = calc.calc_change(type_id)? {
481+
self.builder = self.builder.add_owned_state_raw(type_id, seal, state)?;
482+
}
483+
Ok(self)
466484
}
467485

468486
pub fn has_inputs(&self) -> bool { !self.inputs.is_empty() }
@@ -514,7 +532,6 @@ impl<Seal: ExposedSeal> OperationBuilder<Seal> {
514532
global: none!(),
515533
assignments: none!(),
516534
meta: none!(),
517-
518535
types,
519536
}
520537
}
@@ -551,14 +568,6 @@ impl<Seal: ExposedSeal> OperationBuilder<Seal> {
551568
self.iimpl.valency_name(ty).expect("internal inconsistency")
552569
}
553570

554-
#[inline]
555-
fn state_schema(&self, type_id: AssignmentType) -> &OwnedStateSchema {
556-
self.schema
557-
.owned_types
558-
.get(&type_id)
559-
.expect("schema should match interface: must be checked by the constructor")
560-
}
561-
562571
#[inline]
563572
fn meta_schema(&self, type_id: MetaType) -> &SemId {
564573
self.schema
@@ -615,16 +624,10 @@ impl<Seal: ExposedSeal> OperationBuilder<Seal> {
615624

616625
fn add_owned_state_raw(
617626
mut self,
618-
name: impl Into<FieldName>,
627+
type_id: AssignmentType,
619628
seal: impl Into<BuilderSeal<Seal>>,
620629
state: State,
621630
) -> Result<Self, BuilderError> {
622-
let name = name.into();
623-
624-
let type_id = self
625-
.assignments_type(&name)
626-
.ok_or(BuilderError::AssignmentNotFound(name))?;
627-
628631
let assignment = seal.into().assignment(state);
629632

630633
match self.assignments.entry(type_id)? {
@@ -644,7 +647,13 @@ impl<Seal: ExposedSeal> OperationBuilder<Seal> {
644647
seal: impl Into<BuilderSeal<Seal>>,
645648
value: impl StrictSerialize,
646649
) -> Result<Self, BuilderError> {
647-
self.add_owned_state_raw(name, seal, State::new(value))
650+
let name = name.into();
651+
652+
let type_id = self
653+
.assignments_type(&name)
654+
.ok_or(BuilderError::AssignmentNotFound(name))?;
655+
656+
self.add_owned_state_raw(type_id, seal, State::new(value))
648657
}
649658

650659
fn complete(self) -> (Schema, Iface, IfaceImpl, GlobalState, Assignments<Seal>, TypeSystem) {

0 commit comments

Comments
 (0)