1- use std:: { collections:: HashMap } ;
2- use std:: sync:: Arc ;
31use anyhow:: { Context , anyhow} ;
2+ use std:: collections:: HashMap ;
3+ use std:: sync:: Arc ;
44
5- use wasmtime:: * ;
6- use wasmtime:: component:: { Component , Linker } ;
75use p3_field:: PrimeField64 ;
6+ use wasmtime:: component:: { Component , Linker } ;
7+ use wasmtime:: * ;
88
9- use crate :: utxo:: { UtxoId , UtxoInstance , UtxoRegistry } ;
109use crate :: utils:: hash:: poseidon2_hash_bytes;
10+ use crate :: utxo:: { UtxoId , UtxoInstance , UtxoRegistry } ;
1111
1212pub struct Chain {
1313 utxos : UtxoRegistry ,
@@ -17,76 +17,86 @@ pub struct Chain {
1717pub type WasmComponent = Vec < u8 > ;
1818
1919impl Chain {
20- pub fn new ( genesis_block : & Vec < WasmComponent > ) -> anyhow:: Result < Self > {
21- let mut utxos = HashMap :: new ( ) ;
20+ pub fn new ( genesis_block : & Vec < WasmComponent > ) -> anyhow:: Result < Self > {
21+ let mut utxos = HashMap :: new ( ) ;
22+
23+ let mut config = wasmtime:: Config :: default ( ) ;
24+ config. async_support ( true ) ;
25+ let engine = Engine :: new ( & config) ?;
2226
23- let mut config = wasmtime:: Config :: default ( ) ;
24- config. async_support ( true ) ;
25- let engine = Engine :: new ( & config) ?;
27+ // load genesis block
28+ {
29+ for component_bytes in genesis_block {
30+ let component = Component :: new ( & engine, component_bytes)
31+ . context ( "failed to parse component" ) ?;
2632
27- // load genesis block
28- {
29- for component_bytes in genesis_block {
30- let component = Component :: new ( & engine, component_bytes)
31- . context ( "failed to parse component" ) ?;
33+ // TODO: inject context imports into linker: inject_context_imports
34+ let linker = Linker :: new ( & engine) ;
35+ let instance_pre = linker. instantiate_pre ( & component) ?;
3236
33- // TODO: inject context imports into linker: inject_context_imports
34- let linker = Linker :: new ( & engine) ;
35- let instance_pre = linker. instantiate_pre ( & component) ?;
36-
37- let digest = poseidon2_hash_bytes ( component_bytes) ;
38- let contract_hash = format ! ( "0x{:016X}{:016X}{:016X}{:016X}" , digest[ 0 ] . as_canonical_u64( ) , digest[ 1 ] . as_canonical_u64( ) , digest[ 2 ] . as_canonical_u64( ) , digest[ 3 ] . as_canonical_u64( ) ) ;
37+ let digest = poseidon2_hash_bytes ( component_bytes) ;
38+ let contract_hash = format ! (
39+ "0x{:016X}{:016X}{:016X}{:016X}" ,
40+ digest[ 0 ] . as_canonical_u64( ) ,
41+ digest[ 1 ] . as_canonical_u64( ) ,
42+ digest[ 2 ] . as_canonical_u64( ) ,
43+ digest[ 3 ] . as_canonical_u64( )
44+ ) ;
3945
40- // Register the utxo
41- utxos. insert (
42- UtxoId :: new ( contract_hash, 0 ) ,
43- UtxoInstance {
44- wasm_instance : Arc :: new ( instance_pre) ,
45- datum : vec ! [ ] // TODO: maybe some genesis UTXOs require storage initialization
46- } ,
47- ) ;
46+ // Register the utxo
47+ utxos. insert (
48+ UtxoId :: new ( contract_hash, 0 ) ,
49+ UtxoInstance {
50+ wasm_instance : Arc :: new ( instance_pre) ,
51+ datum : vec ! [ ] , // TODO: maybe some genesis UTXOs require storage initialization
52+ } ,
53+ ) ;
54+ }
4855 }
49- }
5056
51- Ok ( Self {
52- engine : Arc :: new ( engine) ,
53- utxos : tokio:: sync:: RwLock :: new ( utxos) ,
54- } )
55- }
57+ Ok ( Self {
58+ engine : Arc :: new ( engine) ,
59+ utxos : tokio:: sync:: RwLock :: new ( utxos) ,
60+ } )
61+ }
5662
57- pub fn engine ( & self ) -> Arc < Engine > {
58- self . engine . clone ( )
59- }
63+ pub fn engine ( & self ) -> Arc < Engine > {
64+ self . engine . clone ( )
65+ }
6066
61- pub async fn get_utxo ( & self , contract_hash : String , serial : u64 ) -> anyhow:: Result < UtxoInstance > {
62- self . get_utxo_by_id ( & UtxoId :: new ( contract_hash, serial) ) . await
63- }
67+ pub async fn get_utxo (
68+ & self ,
69+ contract_hash : String ,
70+ serial : u64 ,
71+ ) -> anyhow:: Result < UtxoInstance > {
72+ self . get_utxo_by_id ( & UtxoId :: new ( contract_hash, serial) )
73+ . await
74+ }
6475
65- pub async fn get_utxo_by_id ( & self , id : & UtxoId ) -> anyhow:: Result < UtxoInstance > {
66- let utxos = self . utxos . read ( ) . await ;
67- let utxo = utxos
68- . get ( id)
69- . cloned ( )
70- . ok_or_else ( || anyhow ! ( "UTXO not found" ) ) ?;
71- Ok ( utxo)
72- }
76+ pub async fn get_utxo_by_id ( & self , id : & UtxoId ) -> anyhow:: Result < UtxoInstance > {
77+ let utxos = self . utxos . read ( ) . await ;
78+ let utxo = utxos
79+ . get ( id)
80+ . cloned ( )
81+ . ok_or_else ( || anyhow ! ( "UTXO not found" ) ) ?;
82+ Ok ( utxo)
83+ }
7384}
7485
75-
7686/// Host any context that can be fetched from Starstream contracts through an effect handler
7787///
7888/// Think of this similar to a React Context: Starstream programs can raise an effect to receive context from the runtime
7989/// This is represented as an interface (in the WIT definition of the word) that the host provides when it calls into the UTXO
8090/// (pseudocode as the Starstream syntax isn't decided yet): `raise Ctx.Caller()`
81- ///
91+ ///
8292/// Here, the ledger is the "host" in the WASM sense
8393/// and it exposes this data to guests via host functions added to the Linker
84- ///
94+ ///
8595/// Note: blockchain execution doesn't involve stateful handles like file descriptors or network connections
8696/// so it can be an interface, and not a "resource"
8797fn inject_context_imports ( ) {
88- // TODO: Add ledger context fields as needed:
89- // pub block_range: (u64, u64), // validity interval of tx
90- // pub timestamp_range: (u64, u64), // validity interval of tx
91- // pub caller_address: String
92- }
98+ // TODO: Add ledger context fields as needed:
99+ // pub block_range: (u64, u64), // validity interval of tx
100+ // pub timestamp_range: (u64, u64), // validity interval of tx
101+ // pub caller_address: String
102+ }
0 commit comments