diff --git a/qa/rpc-tests/confidential_transactions.py b/qa/rpc-tests/confidential_transactions.py index 5510d5e67d..6c62691ab8 100755 --- a/qa/rpc-tests/confidential_transactions.py +++ b/qa/rpc-tests/confidential_transactions.py @@ -222,6 +222,10 @@ def run_test(self): print("Assets tests...") + # Bitcoin is the first issuance + assert_equal(self.nodes[0].listissuances()[0]["assetlabel"], "bitcoin") + assert_equal(len(self.nodes[0].listissuances()), 1) + # Unblinded issuance of asset issued = self.nodes[0].issueasset(1, 1, False) assert_equal(self.nodes[0].getwalletinfo()["balance"][issued["asset"]], 1) @@ -351,13 +355,13 @@ def run_test(self): addr2 = txdet2[len(txdet2)-1]["address"] addr3 = txdet3[len(txdet3)-1]["address"] - assert_equal(len(self.nodes[0].listissuances()), 5); + assert_equal(len(self.nodes[0].listissuances()), 6); self.nodes[0].importaddress(addr1) self.nodes[0].importaddress(addr2) self.nodes[0].importaddress(addr3) issuances = self.nodes[0].listissuances() - assert_equal(len(issuances), 8) + assert_equal(len(issuances), 9) for issue in issuances: if issue['txid'] == redata1["txid"] and issue['vin'] == redata1["vin"]: diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py index 695f2ec3c5..a282a666ae 100755 --- a/qa/rpc-tests/wallet.py +++ b/qa/rpc-tests/wallet.py @@ -30,19 +30,15 @@ def setup_network(self, split=False): def run_test (self): - # Check that there's no UTXO on none of the nodes - assert_equal(len(self.nodes[0].listunspent()), 0) - assert_equal(len(self.nodes[1].listunspent()), 0) - assert_equal(len(self.nodes[2].listunspent()), 0) + # Check that there's 100 UTXOs on each of the nodes + assert_equal(len(self.nodes[0].listunspent()), 100) + assert_equal(len(self.nodes[1].listunspent()), 100) + assert_equal(len(self.nodes[2].listunspent()), 100) - print("Mining blocks...") - - self.nodes[0].generate(1) walletinfo = self.nodes[0].getwalletinfo() - assert_equal(walletinfo['immature_balance']["bitcoin"], 21000000) - assert("bitcoin" not in walletinfo['balance']) + assert_equal(walletinfo['balance']["bitcoin"], 21000000) - self.sync_all() + print("Mining blocks...") self.nodes[1].generate(101) self.sync_all() diff --git a/src/chainparams.cpp b/src/chainparams.cpp index eaa4243f05..276d1c1ce9 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -41,21 +41,15 @@ static CScript StrHexToScriptWithDefault(std::string strScript, const CScript de return returnScript; } -static CBlock CreateGenesisBlock(const Consensus::Params& params, const std::string& networkID, const CScript& genesisOutputScript, uint32_t nTime, const CScript& scriptChallenge, int32_t nVersion, const CAmount& genesisReward, const uint32_t rewardShards, const CAsset& asset) +static CBlock CreateGenesisBlock(const Consensus::Params& params, const std::string& networkID, uint32_t nTime, const CScript& scriptChallenge, int32_t nVersion) { - // Shards must be evenly divisible - assert(MAX_MONEY % rewardShards == 0); CMutableTransaction txNew; txNew.nVersion = 1; txNew.vin.resize(1); - txNew.vout.resize(rewardShards); // Any consensus-related values that are command-line set can be added here for anti-footgun txNew.vin[0].scriptSig = CScript(CommitToArguments(params, networkID, scriptChallenge)); - for (unsigned int i = 0; i < rewardShards; i++) { - txNew.vout[i].nValue = genesisReward/rewardShards; - txNew.vout[i].nAsset = asset; - txNew.vout[i].scriptPubKey = genesisOutputScript; - } + txNew.vout.clear(); + txNew.vout.push_back(CTxOut(CAsset(), 0, CScript() << OP_RETURN)); CBlock genesis; genesis.nTime = nTime; @@ -67,6 +61,41 @@ static CBlock CreateGenesisBlock(const Consensus::Params& params, const std::str return genesis; } +/** Add an issuance transaction to the genesis block. Typically used to pre-issue + * the policyAsset of a blockchain. The genesis block is not actually validated, + * so this transaction simply has to match issuance structure. */ +static void AppendInitialIssuance(CBlock& genesis_block, const COutPoint& prevout, const uint256& contract, const int64_t asset_outputs, const int64_t asset_values, const int64_t reissuance_outputs, const int64_t reissuance_values, const CScript& issuance_destination) { + + uint256 entropy; + GenerateAssetEntropy(entropy, prevout, contract); + + CAsset asset; + CalculateAsset(asset, entropy); + + // Re-issuance of policyAsset is always unblinded + CAsset reissuance; + CalculateReissuanceToken(reissuance, entropy, false); + + // Note: Genesis block isn't actually validated, outputs are entered into utxo db only + CMutableTransaction txNew; + txNew.nVersion = 1; + txNew.vin.resize(1); + txNew.vin[0].prevout = prevout; + txNew.vin[0].assetIssuance.assetEntropy = contract; + txNew.vin[0].assetIssuance.nAmount = asset_values*asset_outputs; + txNew.vin[0].assetIssuance.nInflationKeys = reissuance_values*reissuance_outputs; + + for (unsigned int i = 0; i < asset_outputs; i++) { + txNew.vout.push_back(CTxOut(asset, asset_values, issuance_destination)); + } + for (unsigned int i = 0; i < reissuance_outputs; i++) { + txNew.vout.push_back(CTxOut(reissuance, reissuance_values, issuance_destination)); + } + + genesis_block.vtx.push_back(MakeTransactionRef(std::move(txNew))); + genesis_block.hashMerkleRoot = BlockMerkleRoot(genesis_block); +} + void CChainParams::UpdateBIP9Parameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout) { consensus.vDeployments[d].nStartTime = nStartTime; @@ -149,7 +178,7 @@ class CElementsParams : public CChainParams { CalculateAsset(consensus.pegged_asset, entropy); CScript scriptDestination(CScript() << std::vector(parentGenesisBlockHash.begin(), parentGenesisBlockHash.end()) << OP_WITHDRAWPROOFVERIFY); - genesis = CreateGenesisBlock(consensus, strNetworkID, scriptDestination, 1231006505, genesisChallengeScript, 1, MAX_MONEY, 100, consensus.pegged_asset); + genesis = CreateGenesisBlock(consensus, strNetworkID, 1231006505, genesisChallengeScript, 1); consensus.hashGenesisBlock = genesis.GetHash(); scriptCoinbaseDestination = CScript() << ParseHex("0229536c4c83789f59c30b93eb40d4abbd99b8dcc99ba8bd748f29e33c1d279e3c") << OP_CHECKSIG; @@ -259,7 +288,8 @@ class CRegTestParams : public CChainParams { GenerateAssetEntropy(entropy, COutPoint(uint256(commit), 0), parentGenesisBlockHash); CalculateAsset(consensus.pegged_asset, entropy); - genesis = CreateGenesisBlock(consensus, strNetworkID, defaultRegtestScript, 1296688602, genesisChallengeScript, 1, MAX_MONEY, 100, consensus.pegged_asset); + genesis = CreateGenesisBlock(consensus, strNetworkID, 1296688602, genesisChallengeScript, 1); + AppendInitialIssuance(genesis, COutPoint(uint256(commit), 0), parentGenesisBlockHash, 100, 21000000000000, 0, 0, CScript() << OP_TRUE); consensus.hashGenesisBlock = genesis.GetHash(); diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 573c16b963..d36be06eb2 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -65,13 +65,15 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha RegisterAllCoreRPCCommands(tableRPC); - // Make genesis coinbase use out spend-key + int gen_size = Params().GenesisBlock().vtx.size(); + + // Make genesis second transaction(with spendable outputs) use out spend-key coinbaseKey.MakeNewKey(true); CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; - CMutableTransaction newCoinbase(*(Params().GenesisBlock().vtx[0])); - for (unsigned int i = 0; i < Params().GenesisBlock().vtx[0]->vout.size(); i++) - newCoinbase.vout[i].scriptPubKey = scriptPubKey; - const_cast(Params().GenesisBlock()).vtx[0] = MakeTransactionRef(newCoinbase); + CMutableTransaction newTransaction(*(Params().GenesisBlock().vtx[gen_size-1])); + for (unsigned int i = 0; i < Params().GenesisBlock().vtx[gen_size-1]->vout.size(); i++) + newTransaction.vout[i].scriptPubKey = scriptPubKey; + const_cast(Params().GenesisBlock()).vtx[gen_size-1] = MakeTransactionRef(newTransaction); const_cast(Params().GenesisBlock()).hashMerkleRoot = BlockMerkleRoot(Params().GenesisBlock()); const_cast(Params().GenesisBlock()).proof = CProof(CScript()<(Params().GetConsensus()).hashGenesisBlock = Params().GenesisBlock().GetHash(); @@ -114,8 +116,9 @@ TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST) { // Generate a 100-block chain: CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; - assert(Params().GenesisBlock().vtx[0]->vout[0].scriptPubKey == scriptPubKey); - coinbaseTxns.push_back(*(Params().GenesisBlock().vtx[0])); + assert(Params().GenesisBlock().vtx[Params().GenesisBlock().vtx.size()-1]->vout[0].scriptPubKey == scriptPubKey); + // Get spendable outputs from genesis block, which is non-coinbase for regtest + coinbaseTxns.push_back(*(Params().GenesisBlock().vtx[Params().GenesisBlock().vtx.size()-1])); for (int i = 0; i < COINBASE_MATURITY; i++) { std::vector noTxns; diff --git a/src/validation.cpp b/src/validation.cpp index 6388c83726..4dbc42e6d9 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2267,19 +2267,16 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin uint256 hashPrevBlock = pindex->pprev == NULL ? uint256() : pindex->pprev->GetBlockHash(); assert(hashPrevBlock == view.GetBestBlock()); - // Gesesis coinbase *is* spendable + // Add genesis outputs. The assumption made here is that there are no real spends + // occurring in this block. if (block.GetHash() == chainparams.GetConsensus().hashGenesisBlock) { if (!fJustCheck) { - assert(block.vtx.size() == 1); assert(block.nHeight == 0); + for (const auto& tx : block.vtx) { - std::vector > vPos; - std::multimap > mLocksCreated; - const CTransaction tx = *(block.vtx[0]); - - CTxUndo undoDummy; - UpdateCoins(tx, view, undoDummy, pindex->nHeight); - + // Directly add new coins to DB + view.ModifyNewCoins(tx->GetHash(), tx->IsCoinBase())->FromTx(*tx, pindex->nHeight); + } view.SetBestBlock(pindex->GetBlockHash()); } return true;