Skip to content

Commit

Permalink
Masternode creation requires authorization
Browse files Browse the repository at this point in the history
Signed-off-by: Anthony Fieroni <[email protected]>
  • Loading branch information
bvbfan committed May 14, 2021
1 parent 46fcb0d commit 046a101
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 12 deletions.
4 changes: 4 additions & 0 deletions src/masternodes/mn_checks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,10 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor
return res;
}

if (height >= static_cast<uint32_t>(Params().GetConsensus().EunosHeight) && !HasAuth(tx.vout[1].scriptPubKey)) {
return Res::Err("masternode creation needs owner auth");
}

CMasternode node;
CTxDestination dest;
if (ExtractDestination(tx.vout[1].scriptPubKey, dest)) {
Expand Down
22 changes: 16 additions & 6 deletions src/masternodes/rpc_masternodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,22 +120,32 @@ UniValue createmasternode(const JSONRPCRequest& request)
const auto txVersion = GetTransactionVersion(targetHeight);
CMutableTransaction rawTx(txVersion);

if (request.params.size() > 2) {
rawTx.vin = GetInputs(request.params[2].get_array());
CTransactionRef optAuthTx;
auto scriptOwner = GetScriptForDestination(ownerDest);
std::set<CScript> auths{scriptOwner};
rawTx.vin = GetAuthInputsSmart(pwallet, rawTx.nVersion, auths, false, optAuthTx, request.params[2]);

// Return change to owner address
CCoinControl coinControl;
if (IsValidDestination(ownerDest)) {
coinControl.destChange = ownerDest;
}

rawTx.vout.push_back(CTxOut(EstimateMnCreationFee(targetHeight), scriptMeta));
rawTx.vout.push_back(CTxOut(GetMnCollateralAmount(targetHeight), GetScriptForDestination(ownerDest)));
rawTx.vout.push_back(CTxOut(GetMnCollateralAmount(targetHeight), scriptOwner));

fund(rawTx, pwallet, {});
fund(rawTx, pwallet, optAuthTx, &coinControl);

// check execution
{
LOCK(cs_main);
CCoinsViewCache coins(&::ChainstateActive().CoinsTip());
if (optAuthTx)
AddCoins(coins, *optAuthTx, targetHeight);
auto metadata = ToByteVector(CDataStream{SER_NETWORK, PROTOCOL_VERSION, static_cast<char>(operatorDest.which()), operatorAuthKey});
execTestTx(CTransaction(rawTx), targetHeight, metadata, CCreateMasterNodeMessage{});
execTestTx(CTransaction(rawTx), targetHeight, metadata, CCreateMasterNodeMessage{}, coins);
}
return signsend(rawTx, pwallet, {})->GetHash().GetHex();
return signsend(rawTx, pwallet, optAuthTx)->GetHash().GetHex();
}

UniValue resignmasternode(const JSONRPCRequest& request)
Expand Down
6 changes: 5 additions & 1 deletion test/functional/feature_auth_return_change.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ def check_auto_auth_txs(self, tx, owner, outputs = 2):

# Auth TX outputs all belong to auth address
assert_equal(auth_tx['vout'][1]['scriptPubKey']['addresses'][0], owner)
assert_equal(len(auth_tx['vout']), 2)
decTx = self.nodes[0].getrawtransaction(tx)
customTx = self.nodes[0].decodecustomtx(decTx)
vouts = 2
if customTx['type'] == 'ResignMasternode': vouts = 3
assert_equal(len(auth_tx['vout']), vouts)

# Two outputs, single input and change to auth address on final TX
assert_equal(final_rawtx['vout'][1]['scriptPubKey']['addresses'][0], owner)
Expand Down
2 changes: 1 addition & 1 deletion test/functional/feature_burn_address.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def run_test(self):
# Check create masternode burn fee
result = self.nodes[0].listburnhistory()
assert_equal(result[0]['owner'][0:16], "6a1a446654784301") # OP_RETURN data
assert_equal(result[0]['txn'], 1)
assert_equal(result[0]['txn'], 2)
assert_equal(result[0]['type'], 'CreateMasternode')
assert_equal(result[0]['amounts'][0], '1.00000000@DFI')

Expand Down
30 changes: 26 additions & 4 deletions test/functional/rpc_mn_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ class MasternodesRpcBasicTest (DefiTestFramework):
def set_test_params(self):
self.num_nodes = 3
self.setup_clean_chain = True
self.extra_args = [['-txnotokens=0', '-amkheight=50', '-bayfrontheight=50', '-bayfrontgardensheight=50', '-dakotaheight=136'],
['-txnotokens=0', '-amkheight=50', '-bayfrontheight=50', '-bayfrontgardensheight=50', '-dakotaheight=136'],
['-txnotokens=0', '-amkheight=50', '-bayfrontheight=50', '-bayfrontgardensheight=50', '-dakotaheight=136']]
self.extra_args = [['-txnotokens=0', '-amkheight=50', '-bayfrontheight=50', '-bayfrontgardensheight=50', '-dakotaheight=136', '-eunosheight=140'],
['-txnotokens=0', '-amkheight=50', '-bayfrontheight=50', '-bayfrontgardensheight=50', '-dakotaheight=136', '-eunosheight=140'],
['-txnotokens=0', '-amkheight=50', '-bayfrontheight=50', '-bayfrontgardensheight=50', '-dakotaheight=136', '-eunosheight=140']]

def run_test(self):
assert_equal(len(self.nodes[0].listmasternodes()), 8)
Expand Down Expand Up @@ -56,6 +56,8 @@ def run_test(self):
collateral0
)

rawTx0 = self.nodes[0].getrawtransaction(idnode0)
decodeTx0 = self.nodes[0].decoderawtransaction(rawTx0)
# Create and sign (only) collateral spending tx
spendTx = self.nodes[0].createrawtransaction([{'txid':idnode0, 'vout':1}],[{collateral0:9.999}])
signedTx = self.nodes[0].signrawtransactionwithwallet(spendTx)
Expand Down Expand Up @@ -148,7 +150,7 @@ def run_test(self):
self.sync_blocks(self.nodes[0:3])
assert_equal(len(self.nodes[0].listmasternodes()), 8)
# fundingTx is removed for a block
assert_equal(self.nodes[0].getrawmempool(), [idnode0])
assert_equal(len(self.nodes[0].getrawmempool()), 1) # auto auth

collateral0 = self.nodes[0].getnewaddress("", "legacy")
self.nodes[0].createmasternode(collateral0)
Expand All @@ -158,5 +160,25 @@ def run_test(self):
assert_equal(self.nodes[0].getblockcount(), 136) # Dakota height
assert_equal(balance_before_creation - 2 + 50, self.nodes[0].getbalance())

self.nodes[0].generate(3)
colTx = self.nodes[0].sendtoaddress(collateral0, 3)
decTx = self.nodes[0].getrawtransaction(colTx, 1)
self.nodes[0].generate(1)
for outputs in decTx['vout']:
if outputs['scriptPubKey']['addresses'][0] == collateral0:
vout = outputs['n']

assert_equal(self.nodes[0].getblockcount(), 140) # Eunos height
# get createmasternode data
data = decodeTx0['vout'][0]['scriptPubKey']['hex'][4:]
cmTx = self.nodes[0].createrawtransaction([{'txid':colTx,'vout':vout}], [{'data':data},{collateral1:2}])
# HACK replace vout 0 to 1DFI
cmTx = cmTx.replace('020000000000000000', '0200e1f50500000000')
signedTx = self.nodes[0].signrawtransactionwithwallet(cmTx)
assert_equal(signedTx['complete'], True)
assert_raises_rpc_error(-26, 'masternode creation needs owner auth', self.nodes[0].sendrawtransaction, signedTx['hex'])
self.nodes[0].createmasternode(self.nodes[0].getnewaddress("", "legacy"))
self.nodes[0].generate(1)

if __name__ == '__main__':
MasternodesRpcBasicTest ().main ()

0 comments on commit 046a101

Please sign in to comment.