@@ -11,7 +11,7 @@ use indoc::indoc;
11
11
12
12
use crate :: common:: constants:: CREATE_COIN ;
13
13
use crate :: common:: standard_coin:: standard_solution;
14
- use crate :: common:: types:: { ErrToError , Error , Puzzle , Amount , Hash , CoinString , CoinID , PuzzleHash , PrivateKey , Aggsig , Node , SpecificTransactionBundle , AllocEncoder } ;
14
+ use crate :: common:: types:: { ErrToError , Error , Puzzle , Amount , Hash , CoinString , CoinID , PuzzleHash , PrivateKey , Aggsig , Node , SpecificTransactionBundle , AllocEncoder , TransactionBundle } ;
15
15
use crate :: common:: standard_coin:: ChiaIdentity ;
16
16
17
17
// Allow simulator from rust.
@@ -23,6 +23,9 @@ struct Simulator {
23
23
make_spend : PyObject ,
24
24
chia_rs_coin : PyObject ,
25
25
program : PyObject ,
26
+ spend_bundle : PyObject ,
27
+ g2_element : PyObject ,
28
+ coin_as_list : PyObject
26
29
}
27
30
28
31
#[ cfg( test) ]
@@ -53,14 +56,16 @@ impl Simulator {
53
56
import asyncio
54
57
import chia.clvm.spend_sim
55
58
from chia.types.coin_spend import make_spend
56
- from chia_rs import Coin
59
+ from chia_rs import Coin, G2Element
57
60
from chia.types.blockchain_format.program import Program
61
+ from chia.types.spend_bundle import SpendBundle
62
+ from chia.types.blockchain_format.coin import coin_as_list
58
63
59
64
def start():
60
65
evloop = asyncio.new_event_loop()
61
66
sac_gen = chia.clvm.spend_sim.sim_and_client()
62
67
(sim, client) = evloop.run_until_complete(sac_gen.__aenter__())
63
- return (evloop, sim, client, sac_gen, make_spend, Coin, Program)
68
+ return (evloop, sim, client, sac_gen, make_spend, Coin, Program, SpendBundle, G2Element, coin_as_list )
64
69
" } ,
65
70
"tmod.py" ,
66
71
"tmod" ,
@@ -74,6 +79,9 @@ impl Simulator {
74
79
make_spend : evloop. get_item ( 4 ) ?. extract ( ) ?,
75
80
chia_rs_coin : evloop. get_item ( 5 ) ?. extract ( ) ?,
76
81
program : evloop. get_item ( 6 ) ?. extract ( ) ?,
82
+ spend_bundle : evloop. get_item ( 7 ) ?. extract ( ) ?,
83
+ g2_element : evloop. get_item ( 8 ) ?. extract ( ) ?,
84
+ coin_as_list : evloop. get_item ( 9 ) ?. extract ( ) ?,
77
85
} )
78
86
} )
79
87
. expect ( "should work" )
@@ -88,17 +96,60 @@ impl Simulator {
88
96
Ok ( res. into ( ) )
89
97
}
90
98
91
- pub fn farm_block ( & self , private_key : & PrivateKey ) {
99
+ fn async_client < ArgT > ( & self , py : Python < ' _ > , name : & str , args : ArgT ) -> PyResult < PyObject >
100
+ where
101
+ ArgT : IntoPy < Py < PyTuple > >
102
+ {
103
+ let task = self . client . call_method1 ( py, name, args) ?;
104
+ let res = self . evloop . call_method1 ( py, "run_until_complete" , ( task, ) ) ?;
105
+ Ok ( res. into ( ) )
106
+ }
107
+
108
+ pub fn farm_block ( & self , puzzle_hash : & PuzzleHash ) {
92
109
Python :: with_gil ( |py| -> PyResult < _ > {
93
- let private_key_bytes = PyBytes :: new ( py, & private_key . bytes ( ) ) ;
94
- self . async_call ( py, "farm_block" , ( private_key_bytes , ) ) ?;
110
+ let puzzle_hash_bytes = PyBytes :: new ( py, & puzzle_hash . bytes ( ) ) ;
111
+ self . async_call ( py, "farm_block" , ( puzzle_hash_bytes , ) ) ?;
95
112
Ok ( ( ) )
96
113
} )
97
114
. expect ( "should farm" ) ;
98
115
}
99
116
100
- pub fn get_my_coins ( & self ) -> PyResult < Vec < CoinString > > {
101
- todo ! ( ) ;
117
+ pub fn get_my_coins ( & self , puzzle_hash : & PuzzleHash ) -> PyResult < Vec < CoinString > > {
118
+ Python :: with_gil ( |py| -> PyResult < _ > {
119
+ let hash_bytes = PyBytes :: new ( py, & puzzle_hash. bytes ( ) ) ;
120
+ let coins = self . async_client (
121
+ py,
122
+ "get_coin_records_by_puzzle_hash" ,
123
+ ( hash_bytes, false )
124
+ ) ?;
125
+ let items: Vec < PyObject > = coins. extract ( py) ?;
126
+ eprintln ! ( "num coins {}" , items. len( ) ) ;
127
+ let mut result_coins = Vec :: new ( ) ;
128
+ for i in items. iter ( ) {
129
+ let coin_of_item: PyObject = i. getattr ( py, "coin" ) ?. extract ( py) ?;
130
+ let as_list: Vec < PyObject > = self . coin_as_list . call1 ( py, ( coin_of_item, ) ) ?. extract ( py) ?;
131
+ let parent_coin_info: & PyBytes = as_list[ 0 ] . downcast ( py) ?;
132
+ let parent_coin_info_slice: & [ u8 ] = parent_coin_info. extract ( ) ?;
133
+ let puzzle_hash: & PyBytes = as_list[ 1 ] . downcast ( py) ?;
134
+ let puzzle_hash_slice: & [ u8 ] = puzzle_hash. extract ( ) ?;
135
+ let amount: u64 = as_list[ 2 ] . extract ( py) ?;
136
+ let parent_coin_hash = Hash :: from_slice ( parent_coin_info_slice) ;
137
+ let puzzle_hash = Hash :: from_slice ( puzzle_hash_slice) ;
138
+ result_coins. push ( CoinString :: from_parts (
139
+ & CoinID :: new ( parent_coin_hash) ,
140
+ & PuzzleHash :: from_hash ( puzzle_hash) ,
141
+ & Amount :: new ( amount)
142
+ ) ) ;
143
+ }
144
+ Ok ( result_coins)
145
+ } )
146
+ }
147
+
148
+ pub fn g2_element ( & self , aggsig : & Aggsig ) -> PyResult < PyObject > {
149
+ Python :: with_gil ( |py| -> PyResult < _ > {
150
+ let bytes = PyBytes :: new ( py, & aggsig. bytes ( ) ) ;
151
+ self . g2_element . call_method1 ( py, "from_bytes_unchecked" , ( bytes, ) )
152
+ } )
102
153
}
103
154
104
155
pub fn make_coin ( & self , coin_string : & CoinString ) -> PyResult < PyObject > {
@@ -145,8 +196,43 @@ impl Simulator {
145
196
self . make_spend . call1 ( py, ( coin, puzzle_program, solution_program) )
146
197
}
147
198
148
- pub fn perform_spend ( & self , tx : & [ SpecificTransactionBundle ] ) -> PyResult < ( ) > {
149
- todo ! ( ) ;
199
+ pub fn make_spend_bundle (
200
+ & self ,
201
+ allocator : & mut AllocEncoder ,
202
+ tx : & SpecificTransactionBundle
203
+ ) -> PyResult < PyObject > {
204
+ Python :: with_gil ( |py| {
205
+ let spend = self . make_coin_spend (
206
+ py,
207
+ allocator,
208
+ & tx. coin ,
209
+ tx. bundle . puzzle . clone ( ) ,
210
+ tx. bundle . solution
211
+ ) ?;
212
+ let signature = self . g2_element ( & tx. bundle . signature ) ?;
213
+ self . spend_bundle . call1 ( py, ( [ spend] , signature) )
214
+ } )
215
+ }
216
+
217
+ pub fn push_tx (
218
+ & self ,
219
+ allocator : & mut AllocEncoder ,
220
+ tx : & SpecificTransactionBundle
221
+ ) -> PyResult < u32 > {
222
+ let spend_bundle = self . make_spend_bundle ( allocator, tx) ?;
223
+ Python :: with_gil ( |py| {
224
+ eprintln ! ( "spend_bundle {:?}" , spend_bundle) ;
225
+ let spend_res: PyObject = self . async_client (
226
+ py,
227
+ "push_tx" ,
228
+ ( spend_bundle, )
229
+ ) ?. extract ( py) ?;
230
+ eprintln ! ( "spend_res {:?}" , spend_res) ;
231
+ let ( inclusion_status, err) : ( PyObject , PyObject ) = spend_res. extract ( py) ?;
232
+ eprintln ! ( "inclusion_status {inclusion_status}" ) ;
233
+ let status: u32 = inclusion_status. extract ( py) ?;
234
+ Ok ( status)
235
+ } )
150
236
}
151
237
}
152
238
@@ -157,21 +243,35 @@ fn test_sim() {
157
243
let mut allocator = AllocEncoder :: new ( ) ;
158
244
let s = Simulator :: new ( ) ;
159
245
let private_key: PrivateKey = rng. gen ( ) ;
160
- s. farm_block ( & private_key) ;
161
246
let identity = ChiaIdentity :: new ( & mut allocator, private_key. clone ( ) ) . expect ( "should create" ) ;
162
- let conditions = (
247
+ s. farm_block ( & identity. puzzle_hash ) ;
248
+
249
+ let coins = s. get_my_coins ( & identity. puzzle_hash ) . expect ( "got coins" ) ;
250
+ eprintln ! ( "coins {coins:?}" ) ;
251
+
252
+ let ( first_coin_parent, first_coin_ph, first_coin_amt) = coins[ 0 ] . to_parts ( ) . unwrap ( ) ;
253
+ assert_eq ! ( first_coin_ph, identity. puzzle_hash) ;
254
+
255
+ let conditions = [
163
256
( CREATE_COIN ,
164
257
( identity. puzzle_hash . clone ( ) ,
165
258
( Amount :: new ( 1 ) , ( ) )
166
259
)
167
- ) , ( )
168
- ) . to_clvm ( & mut allocator) . expect ( "should create conditions" ) ;
260
+ ) ,
261
+ ( CREATE_COIN ,
262
+ ( identity. puzzle_hash . clone ( ) ,
263
+ ( first_coin_amt - Amount :: new ( 1 ) , ( ) )
264
+ )
265
+ )
266
+ ] . to_clvm ( & mut allocator) . expect ( "should create conditions" ) ;
267
+
169
268
let ( solution, signature) = standard_solution (
170
269
& mut allocator,
171
270
& private_key,
172
271
conditions
173
272
) . expect ( "should build" ) ;
174
- let s =
273
+
274
+ let spend =
175
275
Python :: with_gil ( |py| {
176
276
s. make_coin_spend (
177
277
py,
@@ -181,5 +281,21 @@ fn test_sim() {
181
281
solution
182
282
)
183
283
} ) . expect ( "should get a spend" ) ;
184
- eprintln ! ( "spend {s:?}" ) ;
284
+
285
+ eprintln ! ( "spend {spend:?}" ) ;
286
+
287
+ let specific = SpecificTransactionBundle {
288
+ coin : coins[ 0 ] . clone ( ) ,
289
+ bundle : TransactionBundle {
290
+ puzzle : identity. puzzle . clone ( ) ,
291
+ solution,
292
+ signature,
293
+ }
294
+ } ;
295
+
296
+ let status = s. push_tx ( & mut allocator, & specific) . expect ( "should spend" ) ;
297
+
298
+ // Do at end
299
+ drop ( s) ;
300
+ assert_ne ! ( status, 3 ) ;
185
301
}
0 commit comments