Skip to content

Commit

Permalink
Fix virtual supply invariant failure.
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Vandeberg committed May 11, 2016
1 parent 0749bdd commit ae3d2e5
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 3 deletions.
9 changes: 6 additions & 3 deletions libraries/chain/database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1437,6 +1437,7 @@ void database::process_comment_cashout() {
while( current != cidx.end() && current->cashout_time <= head_block_time() ) {
share_type unclaimed;
const auto& cur = *current; ++current;
try{
bool paid = true;
asset sbd_created(0,SBD_SYMBOL);
asset vest_created(0,VESTS_SYMBOL);
Expand Down Expand Up @@ -1490,6 +1491,8 @@ void database::process_comment_cashout() {
++vote_itr;
remove(cur_vote);
}
validate_invariants();
} FC_CAPTURE_LOG_AND_RETHROW( (cur) );
}
}

Expand Down Expand Up @@ -2517,7 +2520,7 @@ void database::adjust_supply( const asset& delta, bool adjust_vesting ) {
}
case SBD_SYMBOL:
props.current_sbd_supply += delta;
props.virtual_supply += delta * get_feed_history().current_median_history;
props.virtual_supply = props.current_sbd_supply * get_feed_history().current_median_history + props.current_supply;
assert( props.current_sbd_supply.amount.value >= 0 );
break;
default:
Expand Down Expand Up @@ -2741,9 +2744,9 @@ void database::validate_invariants()const
FC_ASSERT( total_rshares2 == total_children_rshares2, "", ("total_rshares2", total_rshares2)("total_children_rshares2",total_children_rshares2));

FC_ASSERT( gpo.virtual_supply >= gpo.current_supply );
/*if ( !get_feed_history().current_median_history.is_null() )
if ( !get_feed_history().current_median_history.is_null() )
FC_ASSERT( gpo.current_sbd_supply * get_feed_history().current_median_history + gpo.current_supply
== gpo.virtual_supply, "", ("gpo.current_sbd_supply",gpo.current_sbd_supply)("get_feed_history().current_median_history",get_feed_history().current_median_history)("gpo.current_supply",gpo.current_supply)("gpo.virtual_supply",gpo.virtual_supply) );*/
== gpo.virtual_supply, "", ("gpo.current_sbd_supply",gpo.current_sbd_supply)("get_feed_history().current_median_history",get_feed_history().current_median_history)("gpo.current_supply",gpo.current_supply)("gpo.virtual_supply",gpo.virtual_supply) );
}
FC_CAPTURE_LOG_AND_RETHROW( (head_block_num()) );
}
Expand Down
110 changes: 110 additions & 0 deletions python_scripts/tests/test_payouts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
"""
This test module will only run on a POSIX system. Windows support *may* be added at some point in the future.
"""
# Global imports
import json, operator, os, signal, sys

from argparse import ArgumentParser
from pathlib import Path
from time import sleep

# local imports
from steemdebugnode import DebugNode
from steemapi.steemnoderpc import SteemNodeRPC

WAITING = True

def main( ):
global WAITING
if( os.name != "posix" ):
print( "This script only works on POSIX systems" )
return

parser = ArgumentParser( description='Run a steemd debug node on an existing chain, trigger a hardfork' \
' and verify hardfork does not break invariants or block production' )
parser.add_argument( '--steemd', '-s', type=str, required=True, help='The location of a steemd binary to run the debug node' )
parser.add_argument( '--data-dir', '-d', type=str, required=True, help='The location of an existing data directory. ' + \
'The debug node will pull blocks from this directory when replaying the chain. The directory ' + \
'will not be changed.' )
parser.add_argument( '--pause-node', '-p', type=bool, required=False, default=True, \
help='True if the debug node should pause after it\'s tests. Default: false' )

args = parser.parse_args()

steemd = Path( args.steemd )
if( not steemd.exists() ):
print( 'Error: steemd does not exist.' )
return

steemd = steemd.resolve()
if( not steemd.is_file() ):
print( 'Error: steemd is not a file.' )
return

data_dir = Path( args.data_dir )
if( not data_dir.exists() ):
print( 'Error: data_dir does not exist or is not a properly constructed steemd data directory' )

data_dir = data_dir.resolve()
if( not data_dir.is_dir() ):
print( 'Error: data_dir is not a directory' )

signal.signal( signal.SIGINT, sigint_handler )

debug_node = DebugNode( str( steemd ), str( data_dir ) )

with debug_node :

run_steemd_tests( debug_node )

# Term on completion?
if( args.pause_node ):
print( "Letting the node hang for manual inspection..." )
else:
WAITING = False

while( WAITING ):
sleep( 1 )


def run_steemd_tests( debug_node ):
from steemapi.steemnoderpc import SteemNodeRPC

try:
print( 'Replaying blocks...', )
sys.stdout.flush()
total_blocks = 0
while( total_blocks % 100000 == 0 ):
total_blocks += debug_node.debug_push_blocks( 100000, skip_validate_invariants=True )
print( 'Blocks Replayed: ' + str( total_blocks ) )
sys.stdout.flush()

print( "Triggering payouts" )
sys.stdout.flush()
debug_node.debug_generate_blocks_until( 1467590400 )

print( "Generating blocks to verify nothing broke" )
assert( debug_node.debug_generate_blocks( 10 ) == 10 )

print( "Done!" )
print( "Getting comment dump:" )
sys.stdout.flush()
rpc = SteemNodeRPC( 'ws://127.0.0.1:8095', '', '' )
ret = rpc.get_discussions_by_cashout_time( '', '', str( 0xFFFFFFFF ) );

print( 'author, url, total_payout_value, abs_rshares, num_active_votes' )

for comment in ret:
print( comment[ 'author' ] + ', ' + comment[ 'url' ] + ', ' + comment[ 'total_payout_value' ] + ', ' + comment[ 'cashout_time' ] )

except ValueError as val_err:
print( str( val_err ) )


def sigint_handler( signum, frame ):
global WAITING
WAITING = False
sleep( 3 )
sys.exit( 0 )

main()

0 comments on commit ae3d2e5

Please sign in to comment.