}
}
if ( nHeight == 1 )
- if ( ASSETCHAINS_LASTERA == 0 )
- subsidy = ASSETCHAINS_SUPPLY * SATOSHIDEN + (ASSETCHAINS_MAGIC & 0xffffff);
- else
- subsidy += ASSETCHAINS_SUPPLY * SATOSHIDEN + (ASSETCHAINS_MAGIC & 0xffffff);
-
+ {
+ subsidy += ASSETCHAINS_SUPPLY * SATOSHIDEN + (ASSETCHAINS_MAGIC & 0xffffff);
+ }
return(subsidy);
}
}
}
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ if (!tx.IsCoinBase())
{
- // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed
- // keys. (remember the 520 byte limit on redeemScript size) That works
- // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627
- // bytes of scriptSig, which we round off to 1650 bytes for some minor
- // future-proofing. That's also enough to spend a 20-of-20
- // CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not
- // considered standard)
- if (txin.scriptSig.size() > 1650) {
- reason = "scriptsig-size";
- return false;
- }
- if (!txin.scriptSig.IsPushOnly()) {
- reason = "scriptsig-not-pushonly";
- return false;
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ {
+ // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed
+ // keys. (remember the 520 byte limit on redeemScript size) That works
+ // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627
+ // bytes of scriptSig, which we round off to 1650 bytes for some minor
+ // future-proofing. That's also enough to spend a 20-of-20
+ // CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not
+ // considered standard)
+ if (txin.scriptSig.size() > 1650) {
+ reason = "scriptsig-size";
+ return false;
+ }
+ if (!txin.scriptSig.IsPushOnly()) {
+ reason = "scriptsig-not-pushonly";
+ return false;
+ }
}
}
*/
bool ContextualCheckCoinbaseTransaction(const CTransaction& tx, const int nHeight)
{
- // if time locks are on, ensure that this coin base is time locked exactly as it should be
+ bool valid = true, timelocked = false;
+ CTxDestination firstDest;
+
+ // if time locks are on, ensure that this coin base is time locked exactly as it should be, or invalidate
if (((uint64_t)tx.GetValueOut() >= ASSETCHAINS_TIMELOCKGTE) ||
(((nHeight >= 31680) || strcmp(ASSETCHAINS_SYMBOL, "VRSC") != 0) && komodo_ac_block_subsidy(nHeight) >= ASSETCHAINS_TIMELOCKGTE))
{
CScriptID scriptHash;
+ valid = false;
+ timelocked = true;
// to be valid, it must be a P2SH transaction and have an op_return in vout[1] that
// holds the full output script, which may include multisig, etc., but starts with
// the time lock verify of the correct time lock for this block height
- if (tx.vout.size() == 2 &&
- CScriptExt(tx.vout[0].scriptPubKey).IsPayToScriptHash(&scriptHash) &&
- tx.vout[1].scriptPubKey.size() >= 7 && // minimum for any possible future to prevent out of bounds
- tx.vout[1].scriptPubKey[0] == OP_RETURN)
+ if (CScriptExt(tx.vout[0].scriptPubKey).IsPayToScriptHash(&scriptHash) &&
+ tx.vout.back().scriptPubKey.size() >= 7 && // minimum for any possible future to prevent out of bounds
+ tx.vout.back().scriptPubKey[0] == OP_RETURN)
{
opcodetype op;
std::vector<uint8_t> opretData = std::vector<uint8_t>();
- CScript::const_iterator it = tx.vout[1].scriptPubKey.begin() + 1;
- if (tx.vout[1].scriptPubKey.GetOp2(it, op, &opretData))
+ CScript::const_iterator it = tx.vout.back().scriptPubKey.begin() + 1;
+ if (tx.vout.back().scriptPubKey.GetOp2(it, op, &opretData))
{
if (opretData.size() > 0 && opretData.data()[0] == OPRETTYPE_TIMELOCK)
{
opretScript.IsCheckLockTimeVerify(&unlocktime) &&
komodo_block_unlocktime(nHeight) == unlocktime)
{
- return(true);
+ if (ExtractDestination(opretScript, firstDest))
+ {
+ valid = true;
+ }
}
}
}
}
- return(false);
}
- return(true);
+
+ // if there is a premine, make sure it is the right amount and goes to the correct recipient
+ if (!IsVerusActive && valid && nHeight == 1)
+ {
+ if (ConnectedChains.ThisChain().premine && !ConnectedChains.ThisChain().address.IsNull())
+ {
+ if (!timelocked && !(ExtractDestination(tx.vout[0].scriptPubKey, firstDest)))
+ {
+ valid = false;
+ }
+ else if (tx.vout[0].nValue != ConnectedChains.ThisChain().premine || GetDestinationID(firstDest) != ConnectedChains.ThisChain().address)
+ {
+ valid = false;
+ }
+ }
+
+ // ensure that if this is a PBaaS chain, block 1 includes notarization appropriately derived from the chain definition
+ // transaction. the coinbase must contain a matching notarization out, and the notarization must agree with our start height
+ CPBaaSNotarization pbn(tx);
+
+ if (!pbn.IsValid() || pbn.notarizationHeight < ConnectedChains.ThisChain().startBlock)
+ {
+ valid = false;
+ }
+ }
+
+ return valid;
}
/**
//return nSubsidy;
}
+CAmount GetBlockOnePremine()
+{
+ return ASSETCHAINS_SUPPLY * COIN;
+}
+
bool IsInitialBlockDownload()
{
const CChainParams& chainParams = Params();
/** Find the best known block, and make it the tip of the block chain */
bool ActivateBestChain(CValidationState &state, CBlock *pblock = NULL);
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
+CAmount GetBlockOnePremine();
/**
* Prune block and undo files (blk???.dat and undo???.dat) so that the disk space used is less than a user-defined target.
int64_t pbaasTransparentIn = 0;
int64_t pbaasTransparentOut = 0;
int64_t blockSubsidy = GetBlockSubsidy(nHeight, consensusParams);
+
uint256 mmrRoot;
vector<CInputDescriptor> notarizationInputs;
// make earned notarization only if this is not the notary chain and we have enough subsidy
+ //
// TODO: allow this to proceed if no subsidy and earned notarizations pay no reward as well
+ // we will need to provide a notarization reward option, even for non-fungible chains, just to enable
+ // creation of the notarizations
if (!IsVerusActive() && (blockSubsidy > PBAAS_MINNOTARIZATIONOUTPUT * 2))
{
// if we don't have a connected root PBaaS chain, we can't properly check
return 0;
}
}
+ else if (!IsVerusActive() && stakeHeight == 1)
+ {
+ // first block, send normal reward to the miner, and premine to the specified address in the
+ // chain definition
+ if (!ConnectedChains.ThisChain().address.IsNull() && GetBlockOnePremine())
+ {
+ // move miner output to output 1 and put premine in output 0
+ txNew.vout.push_back(CTxOut(txNew.vout[0].nValue - GetBlockOnePremine(), txNew.vout[0].scriptPubKey));
+ txNew.vout[0] = CTxOut(GetBlockOnePremine(), GetScriptForDestination(CTxDestination(ConnectedChains.ThisChain().address)));
+ }
+ }
txNew.nExpiryHeight = 0;
txNew.nLockTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
// check if coinbase transactions must be time locked at current subsidy and prepend the time lock
// to transaction if so, cast for GTE operator
- if ((uint64_t)(txNew.vout[0].nValue) >= ASSETCHAINS_TIMELOCKGTE)
+ CAmount cbValueOut = 0;
+ for (auto txout : txNew.vout)
+ {
+ cbValueOut += txout.nValue;
+ }
+ if (cbValueOut >= ASSETCHAINS_TIMELOCKGTE)
{
int32_t opretlen, p2shlen, scriptlen;
CScriptExt opretScript = CScriptExt();
- txNew.vout.resize(2);
+ txNew.vout.push_back(CTxOut());
// prepend time lock to original script unless original script is P2SH, in which case, we will leave the coins
// protected only by the time lock rather than 100% inaccessible
opretScript += scriptPubKeyIn;
txNew.vout[0].scriptPubKey = CScriptExt().PayToScriptHash(CScriptID(opretScript));
- txNew.vout[1].scriptPubKey = CScriptExt().OpReturnScript(opretScript, OPRETTYPE_TIMELOCK);
- txNew.vout[1].nValue = 0;
+ txNew.vout.back().scriptPubKey = CScriptExt().OpReturnScript(opretScript, OPRETTYPE_TIMELOCK);
+ txNew.vout.back().nValue = 0;
} // timelocks and commissions are currently incompatible due to validation complexity of the combination
else if ( nHeight > 1 && ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && (commission= komodo_commission((CBlock*)&pblocktemplate->block)) != 0 )
{
//printf("autocreate commision vout\n");
}
+ // finalize input of coinbase
+ txNew.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(0)) + COINBASE_FLAGS;
+ assert(txNew.vin[0].scriptSig.size() <= 100);
+
// add final notarization and instant spend fixups
if (pbaasNotarizationTx)
{
CPBaaSNotarization pbn(pblock->vtx[pbaasNotarizationTx]);
txNew.vout.insert(coinbaseOutIt, MakeCC1of1Vout(EVAL_EARNEDNOTARIZATION, needed, pk, vKeys, pbn));
txNew.vout[0].nValue = txNew.vout[0].nValue - needed;
- pblock->vtx[0] = txNew;
// bind to the right output of the coinbase
mntx.vin.push_back(CTxIn(txNew.GetHash(), pbaasCoinbaseInstantSpendOut));
}
++nExtraNonce;
- // extra nonce is kept in the header, not in the coinbase any longer
- // this allows instant spend transactions to use coinbase funds for
- // inputs by ensuring that once created, the coinbase transaction hash
- // will not continue to change
- CDataStream s(SER_NETWORK, PROTOCOL_VERSION);
- s << nExtraNonce;
- std::vector<unsigned char> vENonce(s.begin(), s.end());
- assert(pblock->ExtraDataLen() >= vENonce.size());
- pblock->SetExtraData(vENonce.data(), vENonce.size());
- /*
- unsigned int nHeight = pindexPrev->GetHeight()+1; // Height first in coinbase required for block.version=2
- CMutableTransaction txCoinbase(pblock->vtx[0]);
- txCoinbase.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS;
- assert(txCoinbase.vin[0].scriptSig.size() <= 100);
- pblock->vtx[0] = txCoinbase;
- */
+ int32_t nHeight = pindexPrev->GetHeight() + 1;
+
+ if (CConstVerusSolutionVector::activationHeight.ActiveVersion(nHeight) >= CConstVerusSolutionVector::activationHeight.SOLUTION_VERUSV3)
+ {
+ // extra nonce is kept in the header, not in the coinbase any longer
+ // this allows instant spend transactions to use coinbase funds for
+ // inputs by ensuring that once final, the coinbase transaction hash
+ // will not continue to change
+ CDataStream s(SER_NETWORK, PROTOCOL_VERSION);
+ s << nExtraNonce;
+ std::vector<unsigned char> vENonce(s.begin(), s.end());
+
+ printf("pblock->ExtraDataLen() == %u, vENonce.size() == %lu\n", pblock->ExtraDataLen(), vENonce.size());
+
+ assert(pblock->ExtraDataLen() >= vENonce.size());
+ pblock->SetExtraData(vENonce.data(), vENonce.size());
+ }
+ else
+ {
+ // finalize input of coinbase
+ CMutableTransaction txcb(pblock->vtx[0]);
+ txcb.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS;
+ assert(txcb.vin[0].scriptSig.size() <= 100);
+ pblock->vtx[0] = txcb;
+ }
+
+ printf("Coinbase Script: %s\n", pblock->vtx[0].vout[0].scriptPubKey.ToString().c_str());
if (buildMerkle)
{
vNodes[i]->copyStats(stats);
if (vNodes[i]->fSuccessfullyConnected && !vNodes[i]->fInbound)
{
- CBitcoinAddress bca(CKeyID(vNodes[i]->hashPaymentAddress));
- pbn.nodes.push_back(CNodeData(vNodes[i]->addr.ToString(), bca.ToString()));
+ pbn.nodes.push_back(CNodeData(vNodes[i]->addr.ToString(), CKeyID(vNodes[i]->hashPaymentAddress)));
}
}
}
*/
bool ValidateAcceptedNotarization(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn)
{
- // this validates the spending transaction
- // first and foremost, check the following two things:
+ // TODO: this validates the spending transaction
+ // check the following things:
// 1. It represents a valid PoS or merge mined block on the other chain, and contains the header in the opret
// 2. The MMR and proof provided for the currently asserted block can prove the provided header. The provided
// header can prove the last block referenced.
-
- // if those are true, then check if we have all relevant inputs, including that we properly finalize all necessary transactions
- // we will jump back 10 transactions, if there are that many in our thread, validate the 10th, invalidate
- // any notarizations that do not derive from that notarization, and spend as inputs
+ // 3. This notarization is not a superset of an earlier notarization posted before it that it does not
+ // reference. If that is the case, it is rejected.
+ // 4. Has all relevant inputs, including finalizes all necessary transactions, both confirmed and orphaned
printf("ValidateAcceptedNotarization\n");
return true;
}
CNodeData::CNodeData(UniValue &obj)
{
networkAddress = uni_get_str(find_value(obj, "networkaddress"));
- paymentAddress = uni_get_str(find_value(obj, "paymentaddress"));
+ CBitcoinAddress ba(uni_get_str(find_value(obj, "paymentaddress")));
+ ba.GetKeyID(paymentAddress);
}
UniValue CNodeData::ToUniValue() const
{
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("networkaddress", networkAddress));
- obj.push_back(Pair("paymentaddress", paymentAddress));
+ obj.push_back(Pair("paymentaddress", CBitcoinAddress(paymentAddress).ToString()));
return obj;
}
{
nVersion = PBAAS_VERSION;
name = uni_get_str(find_value(obj, "name"));
- address = uni_get_str(find_value(obj, "address"));
+ CBitcoinAddress ba(uni_get_str(find_value(obj, "paymentaddress")));
+ ba.GetKeyID(address);
premine = uni_get_int64(find_value(obj, "premine"));
conversion = uni_get_int64(find_value(obj, "conversion"));
launchFee = uni_get_int64(find_value(obj, "launchfee"));
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("version", (int64_t)nVersion));
obj.push_back(Pair("name", name));
- obj.push_back(Pair("address", address));
+ obj.push_back(Pair("paymentaddress", CBitcoinAddress(CTxDestination(address)).ToString()));
obj.push_back(Pair("premine", (int64_t)premine));
obj.push_back(Pair("conversion", (int64_t)conversion));
obj.push_back(Pair("launchfee", (int64_t)launchFee));
{
public:
std::string networkAddress;
- std::string paymentAddress;
+ CKeyID paymentAddress;
CNodeData() {}
CNodeData(UniValue &);
-
+ CNodeData(std::string netAddr, uint160 paymentKeyID) : networkAddress(netAddr), paymentAddress(paymentKeyID) {}
CNodeData(std::string netAddr, std::string paymentAddr) :
- networkAddress(netAddr), paymentAddress(paymentAddr) {}
+ networkAddress(netAddr)
+ {
+ CBitcoinAddress ba(paymentAddr);
+ ba.GetKeyID(paymentAddress);
+ }
ADD_SERIALIZE_METHODS;
uint32_t nVersion; // version of this chain definition data structure to allow for extensions (not daemon version)
std::string name; // chain name, maximum 64 characters
- std::string address; // non-purchased/converted premine and fee recipient address
+ CKeyID address; // non-purchased/converted premine and fee recipient address
int64_t premine; // initial supply that is distributed to the premine output address, but not purchased
int64_t conversion; // factor / 100000000 for conversion of VRSC to coin on launch
int64_t launchFee; // ratio of satoshis to send from contribution to convertible to fee address
int32_t BillingPeriod, int64_t NotaryReward, std::vector<CNodeData> &Nodes) :
nVersion(PBAAS_VERSION),
name(Name),
- address(Address),
premine(Premine),
conversion(Conversion),
launchFee(LaunchFee),
Name.resize(KOMODO_ASSETCHAIN_MAXLEN - 1);
}
name = Name;
+ CBitcoinAddress ba(Address);
+ ba.GetKeyID(address);
}
ADD_SERIALIZE_METHODS;
{
if (vout.size() > voutNum + 1 && vout[voutNum].scriptPubKey.IsPayToScriptHash())
{
- uint32_t voutNext = voutNum + 1;
-
std::vector<uint8_t> opretData;
uint160 scriptID = uint160(std::vector<unsigned char>(vout[voutNum].scriptPubKey.begin() + 2, vout[voutNum].scriptPubKey.begin() + 22));
- CScript::const_iterator it = vout[voutNext].scriptPubKey.begin() + 1;
+ CScript::const_iterator it = vout.back().scriptPubKey.begin() + 1;
opcodetype op;
- if (vout[voutNext].scriptPubKey.GetOp2(it, op, &opretData))
+ if (vout.back().scriptPubKey.GetOp2(it, op, &opretData))
{
if (opretData.size() > 0 && opretData.data()[0] == OPRETTYPE_TIMELOCK)
{
// get inputs for all of the unspent reward outputs sent to a specific reward type for the range specified
// returns the total input amount
-CAmount GetUnspentRewardInputs(const CPBaaSChainDefinition &chainDef, vector<CTxIn> &vinputs, uint160 baseAddress, int32_t serviceCode, int32_t height)
+CAmount GetUnspentRewardInputs(const CPBaaSChainDefinition &chainDef, vector<CInputDescriptor> &inputs, uint160 baseAddress, int32_t serviceCode, int32_t height)
{
CAmount retval = 0;
// we need to look through the inputs to ensure that they are
// actual service reward outputs in the correct billing periof, since we don't currently prevent other types of transaction outputs from being
// sent to the same address, though doing so would burn its value anyhow
+
+ LOCK(cs_main);
for (auto output : unspentOutputs)
{
// printf("txid: %s\n", it->first.txhash.GetHex().c_str());
- CTransaction ntx;
- uint256 blkHash;
CServiceReward sr;
- if (myGetTransaction(output.first.txhash, ntx, blkHash) &&
- (sr = CServiceReward(ntx)).IsValid() &&
- sr.serviceType == SERVICE_NOTARIZATION &&
- sr.billingPeriod <= billingPeriod)
+ CCoins coins;
+ if (pcoinsTip->GetCoins(output.first.txhash, coins))
{
- vinputs.push_back(CTxIn(output.first.txhash, output.first.index));
- retval += output.second.satoshis;
- }
- else
- {
- LogPrintf("GetUnspentRewardInputs: cannot retrieve transaction %s\n", output.first.txhash.GetHex().c_str());
- printf("GetUnspentRewardInputs: cannot retrieve transaction %s\n", output.first.txhash.GetHex().c_str());
+ for (auto txout : coins.vout)
+ {
+ COptCCParams p;
+ if (!txout.IsNull() && IsPayToCryptoCondition(txout.scriptPubKey, p) && p.evalCode == EVAL_SERVICEREWARD)
+ {
+ FromVector(p.vData[0], sr);
+ if (sr.IsValid())
+ {
+ inputs.push_back(CInputDescriptor(txout.scriptPubKey, txout.nValue, CTxIn(output.first.txhash, output.first.index)));
+ retval += txout.nValue;
+ }
+ }
+ else
+ {
+ LogPrintf("GetUnspentRewardInputs: cannot retrieve transaction %s\n", output.first.txhash.GetHex().c_str());
+ printf("GetUnspentRewardInputs: cannot retrieve transaction %s\n", output.first.txhash.GetHex().c_str());
+ }
+ }
}
}
}
return retval;
}
-
-
// this adds any new notarization rewards that have been sent to the notarization reward pool for this
// billing period since last accepted notarization, up to a maximum number of inputs
-CAmount AddNewNotarizationRewards(CPBaaSChainDefinition &chainDef, CMutableTransaction mnewTx, int32_t height)
+CAmount AddNewNotarizationRewards(CPBaaSChainDefinition &chainDef, vector<CInputDescriptor> &inputs, CMutableTransaction mnewTx, int32_t height)
{
// get current chain info
CAmount newIn = 0;
- vector<CTxIn> newInputs;
- newIn = GetUnspentRewardInputs(chainDef, newInputs, chainDef.GetChainID(), SERVICE_NOTARIZATION, height);
- for (auto input : newInputs)
+ newIn = GetUnspentRewardInputs(chainDef, inputs, chainDef.GetChainID(), SERVICE_NOTARIZATION, height);
+ for (auto input : inputs)
{
- mnewTx.vin.push_back(input);
+ mnewTx.vin.push_back(input.txIn);
}
return newIn;
}
+UniValue submitnotarizationpayment(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() != 1)
+ {
+ throw runtime_error(
+ "submitnotarizationpayment \"chainid\" \"amount\" \"billingperiod\"\n"
+ "\nAdds some amount of funds to a specific billing period of a PBaaS chain, which will be released\n"
+ "\nin the form of payments to notaries whose notarizations are confirmed.\n"
+
+ "\nArguments\n"
+
+ "\nResult:\n"
+
+ "\nExamples:\n"
+ + HelpExampleCli("submitacceptednotarization", "\"hextx\"")
+ + HelpExampleRpc("submitacceptednotarization", "\"hextx\"")
+ );
+ }
+
+}
+
UniValue submitacceptednotarization(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
// add all inputs that might provide notary reward and calculate notary reward based on that plus current
// notarization input value divided by number of blocks left in billing period, times blocks per notarization
- if (GetChainDefinition(pbn.chainID, chainDef))
+ if (pindex && GetChainDefinition(pbn.chainID, chainDef))
{
- valueIn += AddNewNotarizationRewards(chainDef, mnewTx, chainActive.LastTip()->GetHeight());
+ valueIn += AddNewNotarizationRewards(chainDef, notarizationInputs, mnewTx, pindex->GetHeight());
}
else
{
- LogPrintf("AddNewNotarizationRewards: cannot find chain %s, possible corrupted database\n", chainDef.name.c_str());
- printf("AddNewNotarizationRewards: cannot find chain %s, possible corrupted database\n", chainDef.name.c_str());
+ LogPrintf("submitacceptednotarization: cannot find chain %s, possible corrupted database\n", chainDef.name.c_str());
+ printf("submitacceptednotarization: cannot find chain %s, possible corrupted database\n", chainDef.name.c_str());
}
}
}
// minimum amount must go to main thread and finalization, then divide what is left among blocks in the billing period
- uint64_t blocksLeft = chainDef.billingPeriod - (pbn.notarizationHeight % chainDef.billingPeriod);
+ uint64_t blocksLeft = chainDef.billingPeriod - (confirmedPBN.notarizationHeight % chainDef.billingPeriod);
CAmount valueOut;
if (blocksLeft <= CPBaaSNotarization::MIN_BLOCKS_BETWEEN_ACCEPTED)
{
throw JSONRPCError(RPC_VERIFY_REJECTED, "Failed to get notarizaton data for chainID: " + pbn.chainID.GetHex());
}
-
UniValue getcrossnotarization(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 2 || params.size() > 3)
"\nArguments\n"
" {\n"
" \"name\" : \"xxxx\", (string, required) unique Verus ecosystem-wide name/symbol of this PBaaS chain\n"
- " \"address\" : \"Rxxx\", (string, optional) premine and launch fee recipient\n"
+ " \"paymentaddress\" : \"Rxxx\", (string, optional) premine and launch fee recipient\n"
" \"premine\" : \"n\", (int, optional) amount of coins that will be premined and distributed to premine address\n"
" \"convertible\" : \"n\", (int, optional) amount of coins that may be converted from Verus, price determined by total contribution\n"
" \"launchfee\" : \"n\", (int, optional) VRSC fee for conversion at startup, multiplied by amount, divided by 100000000\n"
{ "pbaas", "getnotarizationdata", &getnotarizationdata, true },
{ "pbaas", "getcrossnotarization", &getcrossnotarization, true },
{ "pbaas", "definechain", &definechain, true },
+ { "pbaas", "submitacceptednotarization", &submitacceptednotarization, true },
+ { "pbaas", "submitnotarizationpayment", &submitnotarizationpayment, true },
{ "pbaas", "addmergedblock", &addmergedblock, true }
};
CScriptExt spk = tx.vout[voutNum].scriptPubKey;
// if this is a timelocked transaction, get the destination behind the time lock
- if (tx.IsCoinBase() && tx.vout.size() == 2 && voutNum == 0 &&
+ if (tx.IsCoinBase() && voutNum == 0 &&
spk.IsPayToScriptHash(&scriptHash) &&
- tx.vout[1].scriptPubKey.IsOpReturn())
+ tx.vout.back().scriptPubKey.IsOpReturn())
{
opcodetype op;
std::vector<uint8_t> opretData = std::vector<uint8_t>();
- CScript::const_iterator it = tx.vout[1].scriptPubKey.begin() + 1;
- if (tx.vout[1].scriptPubKey.GetOp2(it, op, &opretData))
+ CScript::const_iterator it = tx.vout.back().scriptPubKey.begin() + 1;
+ if (tx.vout.back().scriptPubKey.GetOp2(it, op, &opretData))
{
if (opretData.size() > 0 && opretData[0] == OPRETTYPE_TIMELOCK)
{
// Add transparent inputs
for (auto t : m_op->inputs_) {
+ m_op->builder_.SetLockTime((uint32_t)(chainActive.Height()));
+ m_op->builder_.AddTransparentInput(COutPoint(t.txid, t.vout), t.scriptPubKey, t.amount, 0xfffffffe);
+ /*
if ((uint64_t)t.amount >= ASSETCHAINS_TIMELOCKGTE)
{
m_op->builder_.SetLockTime((uint32_t)(chainActive.Height()));
{
m_op->builder_.AddTransparentInput(COutPoint(t.txid, t.vout), t.scriptPubKey, t.amount);
}
+ */
}
// Send all value to the target z-addr
m_op->builder_.SendChangeTo(zaddr, ovk);
+
+
// Build the transaction
auto maybe_tx = m_op->builder_.Build();
if (!maybe_tx) {
return ret;
}
}
- else if (tx.vout.size() > (voutNext = voutNum + 1) &&
- tx.vout[voutNext].scriptPubKey.size() > 7 &&
- tx.vout[voutNext].scriptPubKey[0] == OP_RETURN)
+ else if (tx.vout.size() > (voutNum + 1) &&
+ tx.vout.back().scriptPubKey.size() > 7 &&
+ tx.vout.back().scriptPubKey[0] == OP_RETURN)
{
// get the opret script from next vout, verify that the front is CLTV and hash matches
// if so, remove it and use the solver
opcodetype op;
std::vector<uint8_t> opretData;
- CScript::const_iterator it = tx.vout[voutNext].scriptPubKey.begin() + 1;
- if (tx.vout[voutNext].scriptPubKey.GetOp2(it, op, &opretData))
+ CScript::const_iterator it = tx.vout.back().scriptPubKey.begin() + 1;
+ if (tx.vout.back().scriptPubKey.GetOp2(it, op, &opretData))
{
if (opretData.size() > 0 && opretData[0] == OPRETTYPE_TIMELOCK)
{