Permalink
Browse files

Pulling in upstream changes while retaining speed optimizations

  • Loading branch information...
2 parents 94a2205 + f3ed89f commit 739e3067cc9a5ebd2e6fd80e31ed16d94e426155 @dave-andersen committed Feb 4, 2014
@@ -18,15 +18,21 @@ namespace bts { namespace blockchain {
*/
struct trx_eval
{
- trx_eval():coindays_destroyed(0),total_spent(0){}
+ trx_eval()
+ :coindays_destroyed(0),
+ invalid_coindays_destroyed(0),
+ total_spent(0){}
+
asset fees; // any fees that would be generated
uint64_t coindays_destroyed;
+ uint64_t invalid_coindays_destroyed;
uint64_t total_spent;
trx_eval& operator += ( const trx_eval& e )
{
- fees += e.fees;
- coindays_destroyed += e.coindays_destroyed;
- total_spent += e.total_spent;
+ fees += e.fees;
+ coindays_destroyed += e.coindays_destroyed;
+ invalid_coindays_destroyed += e.invalid_coindays_destroyed;
+ total_spent += e.total_spent;
return *this;
}
};
@@ -29,6 +29,16 @@ namespace bts { namespace blockchain {
};
bool operator < ( const market_order& a, const market_order& b );
bool operator == ( const market_order& a, const market_order& b );
+
+ struct margin_call
+ {
+ margin_call( const price& callp, const output_reference& loc ):call_price(callp),location(loc){}
+
+ price call_price;
+ output_reference location;
+ };
+ bool operator < ( const margin_call& a, const margin_call& b );
+ bool operator == ( const margin_call& a, const margin_call& b );
/**
* Manages the current state of the market to enable effecient
@@ -43,11 +53,15 @@ namespace bts { namespace blockchain {
void open( const fc::path& db_dir );
std::vector<market_order> get_bids( asset::type quote_unit, asset::type base_unit )const;
std::vector<market_order> get_asks( asset::type quote_unit, asset::type base_unit )const;
+ std::vector<margin_call> get_calls( price call_price )const;
+
void insert_bid( const market_order& m );
void insert_ask( const market_order& m );
void remove_bid( const market_order& m );
void remove_ask( const market_order& m );
+ void insert_call( const margin_call& c );
+ void remove_call( const margin_call& c );
/** @pre quote > base */
fc::optional<market_order> get_highest_bid( asset::type quote, asset::type base );
@@ -61,3 +75,4 @@ namespace bts { namespace blockchain {
} } // bts::blockchain
FC_REFLECT( bts::blockchain::market_order, (base_unit)(quote_unit)(ratio)(location) );
+FC_REFLECT( bts::blockchain::margin_call, (call_price)(location) )
@@ -141,19 +141,15 @@ struct claim_by_cover_output
{
static const claim_type_enum type;
- claim_by_cover_output( const asset& payoff, const address& own )
- :payoff_unit(payoff.unit),
- payoff_amount(payoff.get_rounded_amount()),
- owner(own){}
+ claim_by_cover_output( const asset& pay, const address& own )
+ :payoff(pay), owner(own){}
- claim_by_cover_output()
- :payoff_amount(0){}
+ claim_by_cover_output(){}
- asset get_payoff_amount()const { return asset( payoff_amount, payoff_unit); }
+ price get_call_price( asset collat )const;
bool operator == ( const claim_by_cover_output& other )const;
- asset_type payoff_unit;
- uint64_t payoff_amount;
+ asset payoff;
bts::address owner;
};
@@ -324,7 +320,7 @@ FC_REFLECT( bts::blockchain::claim_by_signature_output, (owner) )
FC_REFLECT( bts::blockchain::claim_by_pts_output, (owner) )
FC_REFLECT( bts::blockchain::claim_by_bid_output, (pay_address)(ask_price) )
FC_REFLECT( bts::blockchain::claim_by_long_output, (pay_address)(ask_price) )
-FC_REFLECT( bts::blockchain::claim_by_cover_output, (payoff_unit)(payoff_amount)(owner) )
+FC_REFLECT( bts::blockchain::claim_by_cover_output, (payoff)(owner) )
FC_REFLECT( bts::blockchain::claim_by_opt_execute_output, (optionor)(expire_time)(strike_unit)(strike_amount)(optionee) )
FC_REFLECT( bts::blockchain::claim_by_escrow_output, (agreement)(agent_terms)(agent)(payee)(payor) )
FC_REFLECT( bts::blockchain::claim_by_multi_sig_output, (required)(addresses) )
@@ -74,6 +74,7 @@ namespace bts { namespace blockchain {
*/
const signed_transaction trx; // TODO make reference?
uint64_t total_cdd;
+ uint64_t uncounted_cdd;
uint32_t prev_block_id1; // block ids that count for CDD
uint32_t prev_block_id2; // block ids that count for CDD
@@ -3,7 +3,6 @@
#include <fc/io/varint.hpp>
#include <fc/crypto/ripemd160.hpp>
#include <fc/reflect/reflect.hpp>
-#include <fc/crypto/sha256.hpp>
#define MOMENTUM_NONCE_BITS 26
#define MAX_MOMENTUM_NONCE (1<<MOMENTUM_NONCE_BITS)
@@ -86,6 +86,12 @@ namespace bts { namespace blockchain {
market_order order( cbl.ask_price, o );
_market_db.remove_bid( order );
}
+ if( trx_out.claim_func == claim_by_cover )
+ {
+ auto cbc = trx_out.as<claim_by_cover_output>();
+ margin_call order( cbc.get_call_price( trx_out.amount ), o );
+ _market_db.remove_call( order );
+ }
}
@@ -135,6 +141,11 @@ namespace bts { namespace blockchain {
elog( "Insert Short Ask: ${bid}", ("bid",market_order(cbl.ask_price, output_reference( t.id(), i )) ) );
_market_db.insert_bid( market_order(cbl.ask_price, output_reference( t.id(), i )) );
}
+ else if( t.outputs[i].claim_func == claim_by_cover )
+ {
+ auto cbc = t.outputs[i].as<claim_by_cover_output>();
+ _market_db.insert_call( margin_call( cbc.get_call_price(t.outputs[i].amount), output_reference( t.id(), i ) ) );
+ }
}
}
@@ -405,10 +416,10 @@ namespace bts { namespace blockchain {
"", ("bid", working_bid) );
}
} // while( ... )
- ilog( "." );
+
+ // We are done with all of the asks, but not the bids as margin calls may use the bids...
if( has_change && working_ask.amount.get_rounded_amount() > 0 )
{
- ilog( "." );
FC_ASSERT( ask_itr != asks.end() );
if( pay_asker.amount > 0 )
{
@@ -417,10 +428,180 @@ namespace bts { namespace blockchain {
market_trx.outputs.push_back( trx_output( claim_by_signature_output( ask_payout_address ), pay_asker ) );
}
}
+
+ //=================== START MARGIN CALL SECTION ==========================
+ if( base == asset::bts && bid_itr != bids.rend())
+ {
+ price call_price;
+ if( working_bid.claim_func == claim_by_long )
+ call_price = working_bid.as<claim_by_long_output>().ask_price;
+ else
+ call_price = working_bid.as<claim_by_bid_output>().ask_price;
+
+ // all of these margin positions must accept the highest bid
+ auto margin_positions = _market_db.get_calls( call_price );
+ ilog( "\n\nMARGIN POSITIONS:\n${p}\n\n", ("p", margin_positions ) );
+
+ trx_output working_call;
+ claim_by_cover_output cover;
+
+ auto call_itr = margin_positions.begin();
+ if( call_itr != margin_positions.end() )
+ {
+ working_call = get_output( call_itr->location );
+ cover = working_call.as<claim_by_cover_output>();
+ }
+
+ while( call_itr != margin_positions.end() &&
+ bid_itr != bids.rend() )
+ {
+ has_change = true;
+ if( working_bid.claim_func == claim_by_bid_output::type )
+ {
+ auto bid_out = working_bid.as<claim_by_bid_output>();
+ auto max_collat_purchase = working_call.amount * bid_out.ask_price;
+ bid_payout_address = bid_out.pay_address;
+ if( working_bid.amount.get_rounded_amount() >= cover.payoff.get_rounded_amount() )
+ {
+ // then the bid has enough USD... but is there enough collateral to purchase it
+ auto consumed_margin = cover.payoff * bid_out.ask_price;
+ if( max_collat_purchase.get_rounded_amount() > working_bid.amount.get_rounded_amount() )
+ { // we have fully covered the collateral position and can pay off the change
+
+ // TODO: charge a 5% fee..
+ market_trx.outputs.push_back( trx_output( claim_by_signature_output( cover.owner ),
+ working_call.amount - consumed_margin ) );
+
+ working_bid.amount -= consumed_margin * bid_out.ask_price;
+ pay_bidder += consumed_margin;
+ }
+ else // we have run out of collateral... there is no change to the short
+ {
+ working_bid.amount -= max_collat_purchase;
+ pay_bidder += max_collat_purchase * bid_out.ask_price;
+ }
+
+ market_trx.inputs.push_back( call_itr->location );
+ ++call_itr;
+ if( call_itr != margin_positions.end() )
+ {
+ working_call = get_output( call_itr->location );
+ cover = working_call.as<claim_by_cover_output>();
+ }
+ continue;
+ }
+ else // consume all of the bid, leave margin position as change
+ {
+ if( max_collat_purchase >= working_bid.amount )
+ {
+ pay_bidder += working_bid.amount * bid_out.ask_price;
+ cover.payoff -= working_bid.amount;
+ working_call.amount -= working_bid.amount * bid_out.ask_price;
+
+ market_trx.inputs.push_back( bid_itr->location );
+ market_trx.outputs.push_back( trx_output( claim_by_signature_output( bid_out.pay_address ),
+ pay_bidder) );
+
+ ++bid_itr;
+ if( bid_itr != bids.rend() ) working_bid = get_output( bid_itr->location );
+ }
+ else // we lack sufficient collateral... I guess we only consume part of the bid
+ {
+ pay_bidder += max_collat_purchase * bid_out.ask_price;
+ working_bid.amount -= max_collat_purchase;
+ market_trx.inputs.push_back( call_itr->location );
+ ++call_itr;
+ if( call_itr != margin_positions.end() )
+ {
+ working_call = get_output( call_itr->location );
+ cover = working_call.as<claim_by_cover_output>();
+ }
+ }
+ }
+ }
+ else // claim_func == claim_by_long...
+ {
+ auto long_claim = working_bid.as<claim_by_long_output>();
+ auto max_collat_purchase = working_call.amount * long_claim.ask_price;
+ auto avail_usd = working_bid.amount * long_claim.ask_price;
+ bid_payout_address = long_claim.pay_address;
+ if( avail_usd.get_rounded_amount() >= cover.payoff.get_rounded_amount() )
+ { // then the bid has enough USD... but is there enough collateral to purchase it
+ if( max_collat_purchase.get_rounded_amount() >= avail_usd.get_rounded_amount() )
+ { // then we have enough collateral to accept the full bid
+ loan_amount += avail_usd;
+ collateral_amount += working_bid.amount + working_bid.amount;
+ working_call.amount -= working_bid.amount;
+ cover.payoff -= avail_usd;
+
+ market_trx.inputs.push_back( bid_itr->location );
+ market_trx.outputs.push_back(
+ trx_output( claim_by_cover_output( loan_amount, long_claim.pay_address ), collateral_amount) );
+
+ loan_amount = asset(ULLCONST(0),loan_amount.unit);
+ collateral_amount = asset();
+ ++bid_itr;
+ if( bid_itr != bids.rend() ) working_bid = get_output( bid_itr->location );
+ }
+ else // we don't actually have enough collateral to accept the full bid
+ {
+ // consume all of the collateral... leaving what is left of the bid
+ loan_amount += max_collat_purchase;
+ collateral_amount += working_call.amount + working_call.amount;
+ working_bid.amount -= working_call.amount;
+
+ ++call_itr;
+ if( call_itr != margin_positions.end() )
+ {
+ working_call = get_output( call_itr->location );
+ cover = working_call.as<claim_by_cover_output>();
+ }
+ }
+ }
+ else // consume all of the margin...
+ {
+ cover.payoff -= avail_usd;
+ working_call.amount -= working_bid.amount;
+
+ loan_amount += avail_usd;
+ working_bid.amount -= working_bid.amount;
+
+ market_trx.inputs.push_back( call_itr->location );
+ // TODO: charge a 5% fee..
+ market_trx.outputs.push_back( trx_output( claim_by_signature_output( cover.owner ),
+ working_call.amount ) );
+ ++call_itr;
+ if( call_itr != margin_positions.end() )
+ {
+ working_call = get_output( call_itr->location );
+ cover = working_call.as<claim_by_cover_output>();
+ }
+ }
+ }
+ } // loop over margin positions..
+
+ if( margin_positions.end() != call_itr ) //
+ {
+ auto orig = get_output(call_itr->location);
+ if( orig.amount != working_call.amount )
+ {
+ // then we have some change in the margin call... apparently there
+ // were not enough bids...
+ market_trx.inputs.push_back( call_itr->location );
+ market_trx.outputs.push_back( trx_output( cover, working_call.amount ) );
+ }
+ }
+ }
+ //================ END MARGIN CALL SECTION ===============================
+
+
+
+ ilog( "has change ${C} working_bid ${b}", ("C",has_change)( "b",working_bid ) );
+
if( has_change && working_bid.amount.get_rounded_amount() > 0 )
{
- ilog( "." );
FC_ASSERT( bid_itr != bids.rend() );
+ ilog( "collateral_amount ${c}", ("c", collateral_amount ) );
if( collateral_amount.get_rounded_amount() > 0 )
{
market_trx.inputs.push_back( bid_itr->location );
@@ -429,13 +610,18 @@ namespace bts { namespace blockchain {
}
else if( working_bid.claim_func == claim_by_bid )
{
+ ilog( "pay bidder ${b}", ("b",pay_bidder) );
if( pay_bidder.get_rounded_amount() > 0 )
{
market_trx.inputs.push_back( bid_itr->location );
market_trx.outputs.push_back( working_bid );
market_trx.outputs.push_back( trx_output( claim_by_signature_output( bid_payout_address ), pay_bidder ) );
}
}
+ else
+ {
+ ilog( "\n\n SOMETHING WENT WRONG \n\n" );
+ }
}
wlog( "Market Transaction: ${trx}", ("trx", market_trx) );
@@ -669,6 +855,7 @@ namespace bts { namespace blockchain {
}
e.total_spent += vstate.balance_sheet[asset::bts].in.get_rounded_amount() + vstate.balance_sheet[asset::bts].collat_in.get_rounded_amount();
e.coindays_destroyed = vstate.total_cdd;
+ e.invalid_coindays_destroyed = vstate.uncounted_cdd;
return e;
} FC_RETHROW_EXCEPTIONS( warn, "error evaluating transaction ${t}", ("t", trx) );
}
@@ -838,6 +1025,7 @@ namespace bts { namespace blockchain {
asset total_fees;
uint64_t total_cdd = 0;
+ uint64_t invalid_cdd = 0;
uint64_t total_spent = 0;
std::unordered_set<output_reference> consumed_outputs;
@@ -873,6 +1061,7 @@ namespace bts { namespace blockchain {
("cdd",stats[i].eval.coindays_destroyed) );
total_fees += stats[i].eval.fees;
total_cdd += stats[i].eval.coindays_destroyed;
+ invalid_cdd += stats[i].eval.invalid_coindays_destroyed;
total_spent += stats[i].eval.total_spent;
}
}
@@ -919,7 +1108,8 @@ namespace bts { namespace blockchain {
new_blk.avail_coindays = my->head_block.avail_coindays
- total_cdd
+ my->head_block.total_shares - total_spent
- - total_fees.get_rounded_amount();
+ - total_fees.get_rounded_amount()
+ - invalid_cdd;
new_blk.trx_mroot = new_blk.calculate_merkle_root();
Oops, something went wrong.

0 comments on commit 739e306

Please sign in to comment.