Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set stake_modifier + functional tests for it #974

Merged
merged 1 commit into from
Apr 15, 2019

Conversation

scravy
Copy link
Member

@scravy scravy commented Apr 12, 2019

The stake_modifier for a block is saved in CBlockIndex and it was not set before. This pull request changes that.

Updated the functional tests such that the snapshot hash calculation correctly takes stake_modifier into account. Notable change: Instead of passing snapshot_meta.hash it passes snapshot_meta which harbours both hash and stake_modifier.

Signed-off-by: Julian Fleischer [email protected]

@scravy scravy added this to the 0.1 milestone Apr 12, 2019
@scravy scravy requested a review from a team April 12, 2019 15:37
@scravy scravy self-assigned this Apr 12, 2019
@castarco
Copy link

castarco commented Apr 12, 2019

I think feature_block might be failing as the snapshot hash incorporates the stake modifier and I'm not sure the calculation is correct right now. I am running functional tests right now.

As far as I can tell, the snapshot hashes were correctly computed. At almost every step they are checked, and those assertions pass... although I'll look closer to see if the assertions are not "good enough". 🤦‍♂️ I said nothing.

@@ -16,13 +16,13 @@ struct State {

Status m_status = Status::NOT_PROPOSING;

//! \brief how often the proposer looked for an eligible coin
//! \brief how many times the proposer looked for an eligible coin
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a follow up to some earlier PR, requested by @castarco

uint256 &snapshot_hash_out, //!< [out] The snapshot hash extracted from the scriptSig
const CTransaction &tx, //!< [in] The transaction to check
blockchain::Height *height_out, //!< [out] The height extracted from the scriptSig
uint256 *snapshot_hash_out, //!< [out] The snapshot hash extracted from the scriptSig
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was requested in an earlier review by @frolosofsky, the google style guide recommend using pointers for out parameters.

There is a new caller to this function which is not interested in the outputs, so I adapted to follow the style guide and am passing nullptr further down the road.

return state.DoS(100, false, REJECT_INVALID, "bad-txnmrklroot", true, "hashMerkleRoot mismatch");

}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was a nit by @castarco in an earlier pull that these curly braces were missing.

note this is not touching bitcoin code but a file introduced by us.

Dependency<blockchain::Behavior> m_blockchain_behavior;
Dependency<ActiveChain> m_active_chain;
const Dependency<blockchain::Behavior> m_blockchain_behavior;
const Dependency<ActiveChain> m_active_chain;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is just something I'm trying to add in general, dependencies of components can/should be const.

@@ -61,6 +61,7 @@ class StakingRPCImpl : public StakingRPC {
static inline void BlockInfo(UniValue &obj, const CBlockIndex &block) {
obj.pushKV("block_hash", ToUniValue(*block.phashBlock));
obj.pushKV("block_height", ToUniValue(block.nHeight));
obj.pushKV("stake_modifier", ToUniValue(block.stake_modifier));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for asserting on it in functional tests

LogPrint(BCLog::VALIDATION, "%s: Invalid stake found for block=%s failure=%s\n",
__func__, block.GetHash().ToString(), stake_validation_result.errors.ToString());
return false;
if (pindex->nHeight > 0) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this piece of code is also executed for the genesis block which

  • does not have stake (so no stake to check)
  • has a stake modifier which is 0000 by definition

skipping genesis here

return false;
}
const boost::optional<staking::Coin> utxo = utxo_view.GetUTXO(block.GetStakingInput().prevout);
if (utxo) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not further checked as CheckStake takes care of that

UTXOViewAdapter utxo_view(GetComponent<staking::ActiveChain>(), view);
auto validator = GetComponent<staking::StakeValidator>();
const staking::BlockValidationResult coinbase_validation_result =
GetComponent<staking::BlockValidator>()->CheckCoinbaseTransaction(*block.vtx[0]);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The coinbase validation has been added here so we can be sure there are staking inputs and CBlock::GetStakingInput does not abort. CheckStake would anyway complain that there's no stake, but need to get the UTXO for computing the stake modifier here already.

@kostyantyn kostyantyn changed the title Set stake_modifieri + functional tests for it Set stake_modifier + functional tests for it Apr 12, 2019
@AM5800
Copy link
Member

AM5800 commented Apr 12, 2019

Concept ACK
I lack experience in the topic. But it looks correct to me. Especially I like the test that check that stake_modifier is not zero

@scravy scravy requested a review from Nizametdinov April 12, 2019 17:30
@scravy scravy force-pushed the stake-modifier branch 4 times, most recently from 13234ec to 8add7ce Compare April 13, 2019 15:27
@@ -369,7 +368,6 @@ libunite_server_a_SOURCES = \
staking/coin.cpp \
staking/legacy_validation_interface.cpp \
staking/network.cpp \
staking/proof_of_stake.cpp \
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved from libserver to common

@@ -551,6 +549,7 @@ libunite_common_a_SOURCES = \
snapshot/messages.cpp \
snapshot/iterator.cpp \
snapshot/indexer.cpp \
staking/proof_of_stake.cpp \
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to common. linking problem in the win32 build otherwise. relies on Solver from this lib (consensus/standard.cpp)

@@ -133,7 +133,7 @@ class ProposerRPCImpl : public ProposerRPC {
return proposerstatus(request);
}

UniValue getstakeablecoins(const JSONRPCRequest &request) const override {
UniValue liststakeablecoins(const JSONRPCRequest &request) const override {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whopps, also renamed getstakeablecoins to liststakeablecoins in this pr. like it should.

@@ -19,6 +19,7 @@
t.appendCommand(NAME.name, &NAME);

void RegisterStakingRPCCommands(CRPCTable &t) {
STAKING_RPC_COMMAND(calcstakemodifier, "txid", "prev");
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added this command as suggested by @kostyantyn in the spirit of calcsnapshothash RPC for functional tests

@@ -167,7 +167,7 @@ UniValue deletesnapshot(const JSONRPCRequest &request) {
}

UniValue calcsnapshothash(const JSONRPCRequest &request) {
if (request.fHelp || request.params.size() < 2) {
if (request.fHelp || request.params.size() < 4 || request.params.size() > 5) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the validation here was not right

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

request.params.size() < 4 || request.params.size() > 5 -> request.params.size() != 4.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Guys you might want to think about that again...

4 and 5 are in, 5 is an optional argument...

@@ -217,8 +217,8 @@ UniValue calcsnapshothash(const JSONRPCRequest &request) {
stream >> inputs;
stream >> outputs;

uint256 stake_modifier = uint256(ParseHex(request.params[2].get_str()));
uint256 chain_work = uint256(ParseHex(request.params[3].get_str()));
const uint256 stake_modifier = uint256S(request.params[2].get_str());
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why u not use standard functions?!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This actually cost me several hours of debugging. uint256 . ParseHex /= uint256S!!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both functions are used in RPC, ParseHex is used when sending raw event (tx, block), uint256S is used only for uint256 values. At the time of writing, ParseHex seemed more convenient as we will have the same order of bytes in both cases.
Now, looking retrospectively, I think we should change to uint256S to be consistent with other RPCs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kostyantyn maybe you can PR it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@thothd I will. Will take care of this.

@@ -100,4 +101,32 @@ std::vector<CPubKey> ExtractBlockSigningKeys(const CBlock &block) {
return ExtractBlockSigningKeys(coinbase_inputs[1]);
}

uint256 ComputeKernelHash(const uint256 &previous_block_stake_modifier,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved these basic functions to proof_of_stake which itself is now in common. calcstakemodifier relies on that same logic here.

coins = result['stakeable_coins']
assert_equal(2, len(coins))
assert_equal(set(map(lambda x: x['coin']['amount'], coins)), set([Decimal(10000), Decimal(3.75)]))
assert_equal(set(map(lambda x: x['coin']['amount'], coins)), {Decimal(10000), Decimal(3.75)})
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

python 3.1 introduced set literals

Copy link

@castarco castarco Apr 15, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: In fact, you can also use set literals (+ comprehensions) for the left side:

{x['coin']['amount'] for x in coins}

chain_work = 2 + 2*height
if isinstance(stake_prevout_txid, CTransaction):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

feature block checks invalid transactions... well here we go.

@@ -231,7 +232,7 @@ def get_empty_block(self, sync_height):
node0 = self.nodes[0]

hashprev = uint256_from_str(unhexlify(node0.getbestblockhash())[::-1])
snapshot_hash = SnapshotMeta(node0.gettipsnapshot()).hash
snapshot_hash = get_tip_snapshot_meta(node0).hash
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no comment

assert_equal(set(map(lambda x: x['coin']['amount'], coins)), set([Decimal(10000), Decimal(3.75)]))
assert_equal(set(map(lambda x: x['coin']['amount'], coins)), {Decimal(10000), Decimal(3.75)})

self.log.info("Check that chaindata is maintained across restarts")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kostyantyn This one is just for you ;-)

@scravy
Copy link
Member Author

scravy commented Apr 13, 2019

rebased, squashed, + force pushed

Copy link

@castarco castarco left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK b63f72f

Copy link
Member

@Gnappuraz Gnappuraz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK b63f72f

@scravy scravy merged commit 3d1ef06 into dtr-org:master Apr 15, 2019
@scravy
Copy link
Member Author

scravy commented Apr 15, 2019

@castarco I'll follow up on that set-literal foreach comprehension in a follow-up PR :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants