<s> from collections import defaultdict <EOL> from coloredcoinlib import ( ColorSet , ColorTarget , UNCOLORED_MARKER , <EOL> InvalidColorIdError , ZeroSelectError , <EOL> SimpleColorValue , CTransaction ) <EOL> from protocol_objects import ETxSpec <EOL> from ngcccbase . asset import AdditiveAssetValue <EOL> from ngcccbase . txcons import ( BaseOperationalTxSpec , <EOL> SimpleOperationalTxSpec , InsufficientFundsError ) <EOL> from ngcccbase . coindb import UTXO <EOL> import bitcoin . core <EOL> from bitcoin . wallet import CBitcoinAddress <EOL> class OperationalETxSpec ( SimpleOperationalTxSpec ) : <EOL> def __init__ ( self , model , ewctrl ) : <EOL> self . model = model <EOL> self . ewctrl = ewctrl <EOL> self . our_value_limit = None <EOL> def get_targets ( self ) : <EOL> return self . targets <EOL> def get_change_addr ( self , color_def ) : <EOL> color_id = color_def . color_id <EOL> cs = ColorSet . from_color_ids ( self . model . get_color_map ( ) , [ color_id ] ) <EOL> wam = self . model . get_address_manager ( ) <EOL> return wam . get_change_address ( cs ) . get_address ( ) <EOL> def set_our_value_limit ( self , our ) : <EOL> our_colordef = self . ewctrl . resolve_color_spec ( our [ '<STR_LIT>' ] ) <EOL> self . our_value_limit = SimpleColorValue ( colordef = our_colordef , <EOL> value = our [ '<STR_LIT:value>' ] ) <EOL> def prepare_inputs ( self , etx_spec ) : <EOL> self . inputs = defaultdict ( list ) <EOL> colordata = self . model . ccc . colordata <EOL> for color_spec , inps in etx_spec . inputs . items ( ) : <EOL> colordef = self . ewctrl . resolve_color_spec ( color_spec ) <EOL> color_id_set = set ( [ colordef . get_color_id ( ) ] ) <EOL> for inp in inps : <EOL> txhash , outindex = inp <EOL> tx = self . model . ccc . blockchain_state . get_tx ( txhash ) <EOL> prevout = tx . outputs [ outindex ] <EOL> utxo = UTXO ( { "<STR_LIT>" : txhash , <EOL> "<STR_LIT>" : outindex , <EOL> "<STR_LIT:value>" : prevout . value , <EOL> "<STR_LIT>" : prevout . script } ) <EOL> colorvalue = None <EOL> if colordef == UNCOLORED_MARKER : <EOL> colorvalue = SimpleColorValue ( colordef = UNCOLORED_MARKER , <EOL> value = prevout . value ) <EOL> else : <EOL> css = colordata . get_colorvalues ( color_id_set , <EOL> txhash , <EOL> outindex ) <EOL> if ( css and len ( css ) == <NUM_LIT:1> ) : <EOL> colorvalue = css [ <NUM_LIT:0> ] <EOL> if colorvalue : <EOL> self . inputs [ colordef . get_color_id ( ) ] . append ( <EOL> ( colorvalue , utxo ) ) <EOL> def prepare_targets ( self , etx_spec , their ) : <EOL> self . targets = [ ] <EOL> for address , color_spec , value in etx_spec . targets : <EOL> colordef = self . ewctrl . resolve_color_spec ( color_spec ) <EOL> self . targets . append ( ColorTarget ( address , <EOL> SimpleColorValue ( colordef = colordef , <EOL> value = value ) ) ) <EOL> wam = self . model . get_address_manager ( ) <EOL> colormap = self . model . get_color_map ( ) <EOL> their_colordef = self . ewctrl . resolve_color_spec ( their [ '<STR_LIT>' ] ) <EOL> their_color_set = ColorSet . from_color_ids ( self . model . get_color_map ( ) , <EOL> [ their_colordef . get_color_id ( ) ] ) <EOL> ct = ColorTarget ( wam . get_change_address ( their_color_set ) . get_address ( ) , <EOL> SimpleColorValue ( colordef = their_colordef , <EOL> value = their [ '<STR_LIT:value>' ] ) ) <EOL> self . targets . append ( ct ) <EOL> def select_uncolored_coins ( self , colorvalue , use_fee_estimator ) : <EOL> selected_inputs = [ ] <EOL> selected_value = SimpleColorValue ( colordef = UNCOLORED_MARKER , <EOL> value = <NUM_LIT:0> ) <EOL> if use_fee_estimator : <EOL> needed = colorvalue + use_fee_estimator . estimate_required_fee ( ) <EOL> else : <EOL> needed = colorvalue <EOL> color_id = <NUM_LIT:0> <EOL> if color_id in self . inputs : <EOL> total = SimpleColorValue . sum ( [ cv_u [ <NUM_LIT:0> ] <EOL> for cv_u in self . inputs [ color_id ] ] ) <EOL> needed -= total <EOL> selected_inputs += [ cv_u [ <NUM_LIT:1> ] <EOL> for cv_u in self . inputs [ color_id ] ] <EOL> selected_value += total <EOL> if needed > <NUM_LIT:0> : <EOL> value_limit = SimpleColorValue ( colordef = UNCOLORED_MARKER , <EOL> value = <NUM_LIT> + <NUM_LIT> * <NUM_LIT:2> ) <EOL> if self . our_value_limit . is_uncolored ( ) : <EOL> value_limit += self . our_value_limit <EOL> if needed > value_limit : <EOL> msg = "<STR_LIT>" <EOL> raise InsufficientFundsError ( msg % ( needed , value_limit ) ) <EOL> our_inputs , our_value = super ( OperationalETxSpec , self ) . select_coins ( colorvalue - selected_value , use_fee_estimator ) <EOL> selected_inputs += our_inputs <EOL> selected_value += our_value <EOL> return selected_inputs , selected_value <EOL> def select_coins ( self , colorvalue , use_fee_estimator = None ) : <EOL> self . _validate_select_coins_parameters ( colorvalue , use_fee_estimator ) <EOL> colordef = colorvalue . get_colordef ( ) <EOL> if colordef == UNCOLORED_MARKER : <EOL> return self . select_uncolored_coins ( colorvalue , use_fee_estimator ) <EOL> color_id = colordef . get_color_id ( ) <EOL> if color_id in self . inputs : <EOL> total = SimpleColorValue . sum ( [ cv_u [ <NUM_LIT:0> ] <EOL> for cv_u in self . inputs [ color_id ] ] ) <EOL> if total < colorvalue : <EOL> msg = '<STR_LIT>' <EOL> raise InsufficientFundsError ( msg % ( colorvalue , total ) ) <EOL> return [ cv_u [ <NUM_LIT:1> ] for cv_u in self . inputs [ color_id ] ] , total <EOL> if colorvalue > self . our_value_limit : <EOL> raise InsufficientFundsError ( "<STR_LIT>" <EOL> % ( colorvalue , self . our_value_limit ) ) <EOL> return super ( OperationalETxSpec , self ) . select_coins ( colorvalue ) <EOL> class EWalletController ( object ) : <EOL> def __init__ ( self , model , wctrl ) : <EOL> self . model = model <EOL> self . wctrl = wctrl <EOL> def publish_tx ( self , raw_tx , my_offer ) : <EOL> txhash = raw_tx . get_hex_txhash ( ) <EOL> self . model . tx_history . add_trade_entry ( <EOL> txhash , <EOL> self . offer_side_to_colorvalue ( my_offer . B ) , <EOL> self . offer_side_to_colorvalue ( my_offer . A ) ) <EOL> self . wctrl . publish_tx ( raw_tx ) <EOL> def check_tx ( self , raw_tx , etx_spec ) : <EOL> """<STR_LIT>""" <EOL> bctx = bitcoin . core . CTransaction . deserialize ( raw_tx . get_tx_data ( ) ) <EOL> ctx = CTransaction . from_bitcoincore ( raw_tx . get_hex_txhash ( ) , <EOL> bctx , <EOL> self . model . ccc . blockchain_state ) <EOL> color_id_set = set ( [ ] ) <EOL> targets = [ ] <EOL> for target in etx_spec . targets : <EOL> our_address , color_spec , value = target <EOL> raw_addr = CBitcoinAddress ( our_address ) <EOL> color_def = self . resolve_color_spec ( color_spec ) <EOL> color_id = color_def . get_color_id ( ) <EOL> color_id_set . add ( color_id ) <EOL> targets . append ( ( raw_addr , color_id , value ) ) <EOL> used_outputs = set ( [ ] ) <EOL> satisfied_targets = set ( [ ] ) <EOL> for color_id in color_id_set : <EOL> if color_id == <NUM_LIT:0> : <EOL> continue <EOL> out_colorvalues = self . model . ccc . colordata . get_colorvalues_raw ( <EOL> color_id , ctx ) <EOL> for oi in range ( len ( ctx . outputs ) ) : <EOL> if oi in used_outputs : <EOL> continue <EOL> if out_colorvalues [ oi ] : <EOL> for target in targets : <EOL> if target in satisfied_targets : <EOL> continue <EOL> raw_address , tgt_color_id , value = target <EOL> if ( ( tgt_color_id == color_id ) and <EOL> ( value == out_colorvalues [ oi ] . get_value ( ) ) and <EOL> ( raw_address == ctx . outputs [ oi ] . raw_address ) ) : <EOL> satisfied_targets . add ( target ) <EOL> used_outputs . add ( oi ) <EOL> for target in targets : <EOL> if target in satisfied_targets : <EOL> continue <EOL> raw_address , tgt_color_id , value = target <EOL> if tgt_color_id == <NUM_LIT:0> : <EOL> for oi in range ( len ( ctx . outputs ) ) : <EOL> if oi in used_outputs : <EOL> continue <EOL> if ( ( value == ctx . outputs [ oi ] . value ) and <EOL> ( raw_address == ctx . outputs [ oi ] . raw_address ) ) : <EOL> satisfied_targets . add ( target ) <EOL> used_outputs . add ( oi ) <EOL> return len ( targets ) == len ( satisfied_targets ) <EOL> def resolve_color_spec ( self , color_spec ) : <EOL> colormap = self . model . get_color_map ( ) <EOL> return colormap . get_color_def ( color_spec ) <EOL> def offer_side_to_colorvalue ( self , side ) : <EOL> colordef = self . resolve_color_spec ( side [ '<STR_LIT>' ] ) <EOL> return SimpleColorValue ( colordef = colordef , <EOL> value = side [ '<STR_LIT:value>' ] ) <EOL> def select_inputs ( self , colorvalue ) : <EOL> op_tx_spec = SimpleOperationalTxSpec ( self . model , None ) <EOL> if colorvalue . is_uncolored ( ) : <EOL> composed_tx_spec = op_tx_spec . make_composed_tx_spec ( ) <EOL> selection , total = op_tx_spec . select_coins ( colorvalue , composed_tx_spec ) <EOL> change = total - colorvalue - composed_tx_spec . estimate_required_fee ( extra_txins = len ( selection ) ) <EOL> if change < op_tx_spec . get_dust_threshold ( ) : <EOL> change = SimpleColorValue ( colordef = UNCOLORED_MARKER , <EOL> value = <NUM_LIT:0> ) <EOL> return selection , change <EOL> else : <EOL> selection , total = op_tx_spec . select_coins ( colorvalue ) <EOL> change = total - colorvalue <EOL> return selection , change <EOL> def make_etx_spec ( self , our , their ) : <EOL> our_color_def = self . resolve_color_spec ( our [ '<STR_LIT>' ] ) <EOL> our_color_set = ColorSet . from_color_ids ( self . model . get_color_map ( ) , <EOL> [ our_color_def . get_color_id ( ) ] ) <EOL> their_color_def = self . resolve_color_spec ( their [ '<STR_LIT>' ] ) <EOL> their_color_set = ColorSet . from_color_ids ( self . model . get_color_map ( ) , <EOL> [ their_color_def . get_color_id ( ) ] ) <EOL> extra_value = <NUM_LIT:0> <EOL> if our_color_def == UNCOLORED_MARKER : <EOL> extra_value = <NUM_LIT> + <NUM_LIT> * <NUM_LIT:1> <EOL> c_utxos , c_change = self . select_inputs ( <EOL> SimpleColorValue ( colordef = our_color_def , <EOL> value = our [ '<STR_LIT:value>' ] + extra_value ) ) <EOL> inputs = { our [ '<STR_LIT>' ] : <EOL> [ utxo . get_outpoint ( ) for utxo in c_utxos ] } <EOL> wam = self . model . get_address_manager ( ) <EOL> our_address = wam . get_change_address ( their_color_set ) <EOL> targets = [ ( our_address . get_address ( ) , <EOL> their [ '<STR_LIT>' ] , their [ '<STR_LIT:value>' ] ) ] <EOL> if c_change > <NUM_LIT:0> : <EOL> our_change_address = wam . get_change_address ( our_color_set ) <EOL> targets . append ( ( our_change_address . get_address ( ) , <EOL> our [ '<STR_LIT>' ] , c_change . get_value ( ) ) ) <EOL> return ETxSpec ( inputs , targets , c_utxos ) <EOL> def make_reply_tx ( self , etx_spec , our , their ) : <EOL> op_tx_spec = OperationalETxSpec ( self . model , self ) <EOL> op_tx_spec . set_our_value_limit ( our ) <EOL> op_tx_spec . prepare_inputs ( etx_spec ) <EOL> op_tx_spec . prepare_targets ( etx_spec , their ) <EOL> signed_tx = self . model . transform_tx_spec ( op_tx_spec , '<STR_LIT>' ) <EOL> return signed_tx </s>
