chainparams
This commit is contained in:
@@ -61,6 +61,8 @@ uint64_t ASSETCHAINS_COMMISSION;
|
||||
int64_t ASSETCHAINS_TIMELOCKGTE = _ASSETCHAINS_TIMELOCKOFF;
|
||||
uint64_t ASSETCHAINS_TIMEUNLOCKFROM = 0;
|
||||
uint64_t ASSETCHAINS_TIMEUNLOCKTO = 0;
|
||||
uint8_t OPRETTYPE_COINBASETIMELOCK = 1;
|
||||
uint8_t OPRETTYPE_REDEEMSCRIPT = 2;
|
||||
|
||||
uint32_t ASSETCHAINS_ERAS = 1;
|
||||
uint64_t ASSETCHAINS_ENDSUBSIDY[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_HALVING[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_DECAY[ASSETCHAINS_MAX_ERAS];
|
||||
|
||||
@@ -1011,22 +1011,47 @@ int32_t komodo_scriptitemlen(int32_t *opretlenp,uint8_t *script)
|
||||
return(len);
|
||||
}
|
||||
|
||||
// we need to replace this with an include file (like script.h) that defines all opcodes, but for now,
|
||||
// we'll keep these localized near where they're used in the two functions below. script.h is not
|
||||
// required with komodo_utils.h
|
||||
#define SCRIPT_OP_DUP 0x76
|
||||
#define SCRIPT_OP_HASH160 0xa9
|
||||
#define SCRIPT_OP_EQUALVERIFY 0x88
|
||||
#define SCRIPT_OP_CHECKSIG 0xac
|
||||
#define SCRIPT_OP_CHECKLOCKTIMEVERIFY 0xb1
|
||||
#define SCRIPT_OP_DROP 0x75
|
||||
#define SCRIPT_OP_EQUAL 0x87
|
||||
#define SCRIPT_OP_RETURN 0x6a
|
||||
#define SCRIPT_OP_PUSH1 0x4c
|
||||
#define SCRIPT_OP_PUSH2 0x4d
|
||||
|
||||
// standard spend script
|
||||
int32_t komodo_standardspend(uint8_t *script, int32_t n, const uint8_t rmd160[20])
|
||||
{
|
||||
script[n++] = SCRIPT_OP_DUP;
|
||||
script[n++] = SCRIPT_OP_HASH160;
|
||||
script[n++] = 0x14; memcpy(&script[n],rmd160,0x14); n += 0x14;
|
||||
script[n++] = SCRIPT_OP_EQUALVERIFY;
|
||||
script[n++] = SCRIPT_OP_CHECKSIG;
|
||||
return(n);
|
||||
}
|
||||
|
||||
int32_t komodo_opreturnscript(uint8_t *script,uint8_t type,uint8_t *opret,int32_t opretlen)
|
||||
{
|
||||
int32_t offset = 0;
|
||||
script[offset++] = 0x6a;
|
||||
opretlen++;
|
||||
if ( opretlen >= 0x4c )
|
||||
if ( opretlen >= SCRIPT_OP_PUSH1 )
|
||||
{
|
||||
if ( opretlen > 0xff )
|
||||
{
|
||||
script[offset++] = 0x4d;
|
||||
script[offset++] = SCRIPT_OP_PUSH2;
|
||||
script[offset++] = opretlen & 0xff;
|
||||
script[offset++] = (opretlen >> 8) & 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
script[offset++] = 0x4c;
|
||||
script[offset++] = SCRIPT_OP_PUSH1;
|
||||
script[offset++] = opretlen;
|
||||
}
|
||||
} else script[offset++] = opretlen;
|
||||
@@ -1035,23 +1060,12 @@ int32_t komodo_opreturnscript(uint8_t *script,uint8_t type,uint8_t *opret,int32_
|
||||
return(offset + opretlen - 1);
|
||||
}
|
||||
|
||||
// we need to replace this with an include file (like script.h) that defines all opcodes, but for now,
|
||||
// we'll keep these localized near where they're used in the two functions below
|
||||
#define SCRIPT_OP_DUP 0x76
|
||||
#define SCRIPT_OP_HASH160 0xa9
|
||||
#define SCRIPT_OP_EQUALVERIFY 0x88
|
||||
#define SCRIPT_OP_CHECKSIG 0xac
|
||||
#define SCRIPT_OP_CHECKLOCKTIMEVERIFY 0xb1
|
||||
#define SCRIPT_OP_DROP 0x75
|
||||
|
||||
// standard spend script
|
||||
int32_t komodo_standardspend(uint8_t *script, int32_t n, uint8_t rmd160[20])
|
||||
// pay to script hash script
|
||||
int32_t komodo_p2sh(uint8_t *script, int32_t n, const uint8_t scriptHash[20])
|
||||
{
|
||||
script[n++] = SCRIPT_OP_DUP;
|
||||
script[n++] = SCRIPT_OP_HASH160;
|
||||
script[n++] = 0x14; memcpy(&script[n],rmd160,0x14); n += 0x14;
|
||||
script[n++] = SCRIPT_OP_EQUALVERIFY;
|
||||
script[n++] = SCRIPT_OP_CHECKSIG;
|
||||
script[n++] = 0x14; memcpy(&(script[n]),scriptHash,0x14); n += 0x14;
|
||||
script[n++] = SCRIPT_OP_EQUAL;
|
||||
return(n);
|
||||
}
|
||||
|
||||
@@ -1071,13 +1085,35 @@ int32_t komodo_checklocktimeverify(uint8_t *script, int32_t n, uint64_t unlockti
|
||||
}
|
||||
|
||||
// combined CLTV script and standard spend
|
||||
int32_t komodo_timelockspend(uint8_t *script, int32_t n, uint8_t rmd160[20], uint64_t unlocktime)
|
||||
int32_t komodo_timelockspend(uint8_t *script, int32_t n, const uint8_t rmd160[20], uint64_t unlocktime)
|
||||
{
|
||||
n = komodo_checklocktimeverify(script,n,unlocktime);
|
||||
n = komodo_standardspend(script,n,rmd160);
|
||||
return(n);
|
||||
}
|
||||
|
||||
// return the unlock time from a CLTV script and ensure that it is, in fact, a CLTV script
|
||||
// if not a CLTV script, this returns 0
|
||||
uint64_t komodo_getscriptunlocktime(uint8_t *script, uint32_t scriptLen)
|
||||
{
|
||||
uint32_t nBytes;
|
||||
uint64_t unlockTime = 0;
|
||||
|
||||
nBytes = *script++;
|
||||
if ((nBytes > 0 && nBytes <= 5) && nBytes < scriptLen - 2)
|
||||
{
|
||||
if (*(script += nBytes) == SCRIPT_OP_CHECKLOCKTIMEVERIFY)
|
||||
{
|
||||
for ( ; nBytes > 0; nBytes--)
|
||||
{
|
||||
unlockTime <<= 8;
|
||||
unlockTime |= *--script;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(unlockTime);
|
||||
}
|
||||
|
||||
// get a pseudo random number that is the same for each block individually at all times and different
|
||||
// from all other blocks. the sequence is extremely likely, but not guaranteed to be unique for each block chain
|
||||
uint64_t blockPRG(uint32_t nHeight)
|
||||
@@ -1102,53 +1138,38 @@ uint64_t blockPRG(uint32_t nHeight)
|
||||
return(result);
|
||||
}
|
||||
|
||||
uint64_t komodo_pr_unlocktime(uint32_t nHeight, uint64_t fromTime, uint64_t toTime)
|
||||
// given a block height, this returns the unlock time for that block height, derived from
|
||||
// the ASSETCHAINS_MAGIC number as well as the block height, providing different random numbers
|
||||
// for corresponding blocks across chains, but the same sequence in each chain
|
||||
uint64_t komodo_block_unlocktime(uint32_t nHeight)
|
||||
{
|
||||
uint64_t unlocktime;
|
||||
uint32_t i, n = 0;
|
||||
uint64_t fromTime, toTime, unlocktime;
|
||||
|
||||
if ( toTime < fromTime )
|
||||
return(0);
|
||||
else if ( toTime == fromTime )
|
||||
unlocktime = toTime;
|
||||
if ( ASSETCHAINS_TIMEUNLOCKFROM == ASSETCHAINS_TIMEUNLOCKTO )
|
||||
unlocktime = ASSETCHAINS_TIMEUNLOCKTO;
|
||||
else
|
||||
{
|
||||
unlocktime = blockPRG(nHeight) / (0xffffffffffffffff / ((toTime - fromTime) + 1));
|
||||
// boundary and power of 2 can make it exceed toTime by 1
|
||||
unlocktime = i = (unlocktime + fromTime) <= toTime ? i : i - 1;
|
||||
unlocktime = blockPRG(nHeight) / (0xffffffffffffffff / ((ASSETCHAINS_TIMEUNLOCKTO - ASSETCHAINS_TIMEUNLOCKFROM) + 1));
|
||||
// boundary and power of 2 can make it exceed to time by 1
|
||||
unlocktime = unlocktime + ASSETCHAINS_TIMEUNLOCKFROM;
|
||||
if (unlocktime > ASSETCHAINS_TIMEUNLOCKTO)
|
||||
unlocktime--;
|
||||
}
|
||||
return (unlocktime);
|
||||
}
|
||||
|
||||
// create a CLTV output script and return the script and its P2SH address
|
||||
// create a CLTV output script, returning the script size, script, and its P2SH address
|
||||
// funds will be locked a pseudo random time between specified from and to time, with entropy taken from the parameters used
|
||||
// to setup the chain and the specified block height. this can be used to create, validate, or spend a time locked coin base transaction
|
||||
// returns unlocktime
|
||||
int64_t komodo_block_timelockscript(uint8_t *script, uint8_t *p2sh160, uint8_t *taddrrmd160, uint32_t nHeight, uint64_t fromTime, uint64_t toTime)
|
||||
uint32_t komodo_coinbase_timelock(uint8_t *script, uint8_t *p2sh160, const uint8_t taddrrmd160[20], uint32_t nHeight, int64_t nSubsidy)
|
||||
{
|
||||
uint32_t n = 0, unlocktime = komodo_pr_unlocktime(nHeight, fromTime, toTime);
|
||||
uint32_t n = 0;
|
||||
uint64_t unlocktime = nSubsidy >= ASSETCHAINS_TIMELOCKGTE ? komodo_block_unlocktime(nHeight) : 0;
|
||||
|
||||
n = komodo_timelockspend(script, n, taddrrmd160, unlocktime);
|
||||
calc_rmd160_sha256(p2sh160, script, n);
|
||||
|
||||
return(unlocktime);
|
||||
}
|
||||
|
||||
// create an otherwise normal output script to a single address, based on consensus rules,
|
||||
// including a pseudo random time lock based on block height of this chain and coinbase subsidy
|
||||
int64_t komodo_coinbase_ouputscript(uint8_t *script, uint8_t *p2sh160, uint8_t *taddrrmd160, int64_t nSubsidy, uint32_t nHeight)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
// if it should be locked, lock it, otherwise use standard spend script
|
||||
if (nSubsidy >= ASSETCHAINS_TIMELOCKGTE)
|
||||
return komodo_block_timelockscript(script, p2sh160, taddrrmd160, nHeight, ASSETCHAINS_TIMEUNLOCKFROM, ASSETCHAINS_TIMEUNLOCKTO);
|
||||
else
|
||||
{
|
||||
n = komodo_standardspend(script, n, taddrrmd160);
|
||||
calc_rmd160_sha256(p2sh160, script, n);
|
||||
return (0);
|
||||
}
|
||||
return(n);
|
||||
}
|
||||
|
||||
long _stripwhite(char *buf,int accept)
|
||||
|
||||
85
src/main.cpp
85
src/main.cpp
@@ -895,26 +895,67 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that a P2SH coinbase transaction follows consensus rules valid at a given block height.
|
||||
*
|
||||
* Notes:
|
||||
* 1. AcceptToMemoryPool calls CheckTransaction and this function.
|
||||
* 2. ProcessNewBlock calls AcceptBlock, which calls CheckBlock (which calls CheckTransaction)
|
||||
* and ContextualCheckBlock (which calls this function).
|
||||
* Ensure that a coinbase transaction is structured according to the consensus rules of the
|
||||
* chain
|
||||
*/
|
||||
int32_t ContextualCheckCoinbaseTx(const CTransaction &tx, uint32_t nHeight)
|
||||
bool ContextualCheckCoinbaseTransaction(const CTransaction& tx, const int nHeight)
|
||||
{
|
||||
int i;
|
||||
uint64_t total = 0;
|
||||
uint64_t timelock = komodo_pr_unlocktime(nHeight, ASSETCHAINS_TIMEUNLOCKFROM, ASSETCHAINS_TIMEUNLOCKTO);
|
||||
int64_t i, total = 0;
|
||||
uint8_t script[1024], scriptHash[20];
|
||||
|
||||
for (i = 0; total += tx.vout[i].IsNull() ? 0 : tx.vout[i].nValue, i < tx.vout.size(); i++);
|
||||
i = 0;
|
||||
|
||||
for (int i = 0; i < tx.vout.size(); i++)
|
||||
// if time locks are on, ensure that this coin base is time locked exactly as it should be
|
||||
if (total >= ASSETCHAINS_TIMELOCKGTE)
|
||||
{
|
||||
const CScript *script = &(tx.vout[i].scriptPubKey);
|
||||
// if there should be a timelock, get the time lock from the script and return it
|
||||
// to be valid, it must be a P2SH transaction and have an op_return in vout[1] that
|
||||
// holds either:
|
||||
// 1) the receiver's public key hash, which we can use to recreate the output script to
|
||||
// check against the hash, or
|
||||
// 2) the full output script, which may include multisig, etc., that starts with
|
||||
// the time lock verify of the correct time lock for this block height
|
||||
if (tx.vout.size() != 2 ||
|
||||
tx.vout[1].scriptPubKey.size() < 4 || // minimum for any possible future to prevent out of bounds
|
||||
tx.vout[1].scriptPubKey.data()[0] != SCRIPT_OP_RETURN ||
|
||||
tx.vout[0].scriptPubKey.size() < 22 ||
|
||||
*(uint8_t *)(tx.vout[0].scriptPubKey.data()) != 20 ||
|
||||
*(uint8_t *)((tx.vout[0].scriptPubKey.data()) + 21) != SCRIPT_OP_EQUAL)
|
||||
i = 0;
|
||||
else
|
||||
{
|
||||
i = tx.vout[1].scriptPubKey.data()[1];
|
||||
i = i < SCRIPT_OP_PUSH1 ? i :
|
||||
i == SCRIPT_OP_PUSH1 ? tx.vout[1].scriptPubKey.data()[2] :
|
||||
i == SCRIPT_OP_PUSH2 ? tx.vout[1].scriptPubKey.data()[3] << 8 + tx.vout[1].scriptPubKey.data()[2] : 0;
|
||||
if (i != 0)
|
||||
{
|
||||
if (tx.vout[1].scriptPubKey.data()[2] == OPRETTYPE_COINBASETIMELOCK && i >= 21)
|
||||
{
|
||||
// recreate the time lock script and its hash
|
||||
i = komodo_coinbase_timelock(script, scriptHash, &tx.vout[1].scriptPubKey.data()[3], nHeight, total);
|
||||
}
|
||||
else if (tx.vout[1].scriptPubKey.data()[2] == OPRETTYPE_REDEEMSCRIPT && i >= 23 && i < sizeof(script))
|
||||
{
|
||||
i -= 1;
|
||||
memcpy(script, (uint8_t *)tx.vout[1].scriptPubKey.data()+3, i);
|
||||
calc_rmd160_sha256(scriptHash, script, i);
|
||||
}
|
||||
else
|
||||
i = 0;
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
// get the lock time from the script, regardless of if we recognize the rest or not,
|
||||
// we will return true if it is a proper time lock for the right time and the script matches the hash
|
||||
if (komodo_block_unlocktime(nHeight) != komodo_getscriptunlocktime(script, i) ||
|
||||
memcmp(((uint8_t *)tx.vout[0].scriptPubKey.data())+1, scriptHash, sizeof(scriptHash)))
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return(i != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -989,21 +1030,9 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state,
|
||||
|
||||
if (tx.IsCoinBase())
|
||||
{
|
||||
int i;
|
||||
int64_t total = 0;
|
||||
uint8_t script[256], scriptHash160[20];
|
||||
|
||||
for (i = 0; total += tx.vout[i].IsNull() ? 0 : tx.vout[i].nValue, i < tx.vout.size(); i++);
|
||||
|
||||
// if time locks are on, ensure that this coin base is time locked exactly as it should be
|
||||
if (total >= ASSETCHAINS_TIMELOCKGTE)
|
||||
{
|
||||
for (i = 0; i < tx.vout.size(); i++)
|
||||
{
|
||||
// validate that the outputs are locked for the proper time
|
||||
// uint64_t i = komodo_block_timelockscript(script, scriptHash160, tx.addr, nHeight, ASSETCHAINS_TIMEUNLOCKFROM, ASSETCHAINS_TIMEUNLOCKTO)
|
||||
}
|
||||
}
|
||||
if (!ContextualCheckCoinbaseTransaction(tx, nHeight))
|
||||
return state.DoS(100, error("CheckTransaction(): invalid script data for coinbase time lock"),
|
||||
REJECT_INVALID, "bad-txns-invalid-script-data-for-coinbase-time-lock");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -107,7 +107,8 @@ void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams,
|
||||
|
||||
extern int32_t ASSETCHAINS_SEED,IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAIN_INIT,KOMODO_INITDONE,KOMODO_ON_DEMAND,KOMODO_INITDONE,KOMODO_PASSPORT_INITDONE;
|
||||
extern uint64_t ASSETCHAINS_COMMISSION;
|
||||
extern uint64_t ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS];
|
||||
extern uint64_t ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_TIMELOCKGTE;
|
||||
extern uint8_t OPRETTYPE_COINBASETIMELOCK;
|
||||
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
|
||||
extern std::string NOTARY_PUBKEY;
|
||||
extern uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33];
|
||||
@@ -120,6 +121,10 @@ int32_t komodo_is_issuer();
|
||||
int32_t komodo_gateway_deposits(CMutableTransaction *txNew,char *symbol,int32_t tokomodo);
|
||||
int32_t komodo_isrealtime(int32_t *kmdheightp);
|
||||
int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t nTime,int32_t dispflag);
|
||||
int32_t komodo_coinbase_outputscript(uint8_t *script, uint8_t *p2sh160, uint8_t *taddrrmd160, int64_t nSubsidy, uint32_t nHeight);
|
||||
int32_t komodo_coinbase_timelock(uint8_t * script, uint8_t *p2sh160, const uint8_t taddrrmd160[20], uint32_t nHeight, int64_t nSubsidy);
|
||||
int32_t komodo_p2sh(uint8_t *script, int32_t n, const uint8_t scriptHash[20]);
|
||||
int32_t komodo_opreturnscript(uint8_t *script, uint8_t type, uint8_t *opret, int32_t opretlen);
|
||||
|
||||
CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||
{
|
||||
@@ -389,13 +394,34 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||
CMutableTransaction txNew = CreateNewContextualCMutableTransaction(chainparams.GetConsensus(), nHeight);
|
||||
txNew.vin.resize(1);
|
||||
txNew.vin[0].prevout.SetNull();
|
||||
txNew.vin[0].scriptSig = CScript() << nHeight << OP_0;
|
||||
|
||||
txNew.vout.resize(1);
|
||||
txNew.vout[0].scriptPubKey = scriptPubKeyIn;
|
||||
txNew.vout[0].nValue = GetBlockSubsidy(nHeight,chainparams.GetConsensus());
|
||||
txNew.vout[0].nValue = GetBlockSubsidy(nHeight,chainparams.GetConsensus()) + nFees;
|
||||
txNew.nExpiryHeight = 0;
|
||||
// Add fees
|
||||
txNew.vout[0].nValue += nFees;
|
||||
txNew.vin[0].scriptSig = CScript() << nHeight << OP_0;
|
||||
|
||||
// check if coinbase transactions must be time locked at current subsidy and make the time lock if so
|
||||
if (txNew.vout[0].nValue >= ASSETCHAINS_TIMELOCKGTE)
|
||||
{
|
||||
int32_t opretlen, p2shlen, scriptlen;
|
||||
uint8_t opret[256], p2shscript[22], redeemscript[256], taddr[20], p2sh[20];
|
||||
|
||||
txNew.vout.resize(2);
|
||||
|
||||
memcpy(taddr, ((uint8_t *)scriptPubKeyIn.data()) + 2, sizeof(taddr));
|
||||
|
||||
scriptlen = komodo_coinbase_timelock(redeemscript, p2sh, taddr, nHeight, txNew.vout[0].nValue);
|
||||
p2shlen = komodo_p2sh(p2shscript, 0, p2sh);
|
||||
|
||||
txNew.vout[0].scriptPubKey.resize(p2shlen);
|
||||
memcpy((uint8_t *)(txNew.vout[0].scriptPubKey.data()), p2shscript, p2shlen);
|
||||
|
||||
opretlen = komodo_opreturnscript(opret, OPRETTYPE_COINBASETIMELOCK, taddr, sizeof(taddr));
|
||||
txNew.vout[1].scriptPubKey.resize(opretlen);
|
||||
memcpy((uint8_t *)(txNew.vout[1].scriptPubKey.data()), opret, opretlen);
|
||||
txNew.vout[1].nValue = 0;
|
||||
}
|
||||
|
||||
/*if ( ASSETCHAINS_SYMBOL[0] == 0 )
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user