ImportPayout cc eval code and alot of general cc polish. tests to write
This commit is contained in:
@@ -43,7 +43,7 @@ LIBBITCOIN_CLI=libbitcoin_cli.a
|
|||||||
LIBBITCOIN_UTIL=libbitcoin_util.a
|
LIBBITCOIN_UTIL=libbitcoin_util.a
|
||||||
LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a
|
LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a
|
||||||
LIBSECP256K1=secp256k1/libsecp256k1.la
|
LIBSECP256K1=secp256k1/libsecp256k1.la
|
||||||
LIBCRYPTOCONDITIONS=cryptoconditions/cryptoconditions_core.a
|
LIBCRYPTOCONDITIONS=cryptoconditions/libcryptoconditions_core.la
|
||||||
LIBSNARK=snark/libsnark.a
|
LIBSNARK=snark/libsnark.a
|
||||||
LIBUNIVALUE=univalue/libunivalue.la
|
LIBUNIVALUE=univalue/libunivalue.la
|
||||||
LIBZCASH=libzcash.a -lcurl
|
LIBZCASH=libzcash.a -lcurl
|
||||||
@@ -135,6 +135,7 @@ BITCOIN_CORE_H = \
|
|||||||
asyncrpcqueue.h \
|
asyncrpcqueue.h \
|
||||||
base58.h \
|
base58.h \
|
||||||
bloom.h \
|
bloom.h \
|
||||||
|
cc/eval.h \
|
||||||
chain.h \
|
chain.h \
|
||||||
chainparams.h \
|
chainparams.h \
|
||||||
chainparamsbase.h \
|
chainparamsbase.h \
|
||||||
@@ -162,7 +163,7 @@ BITCOIN_CORE_H = \
|
|||||||
init.h \
|
init.h \
|
||||||
key.h \
|
key.h \
|
||||||
keystore.h \
|
keystore.h \
|
||||||
komodo_cryptoconditions.h \
|
komodo_cc.h \
|
||||||
leveldbwrapper.h \
|
leveldbwrapper.h \
|
||||||
limitedmap.h \
|
limitedmap.h \
|
||||||
main.h \
|
main.h \
|
||||||
@@ -191,7 +192,7 @@ BITCOIN_CORE_H = \
|
|||||||
script/interpreter.h \
|
script/interpreter.h \
|
||||||
script/script.h \
|
script/script.h \
|
||||||
script/script_error.h \
|
script/script_error.h \
|
||||||
script/sigcache.h \
|
script/serverchecker.h \
|
||||||
script/sign.h \
|
script/sign.h \
|
||||||
script/standard.h \
|
script/standard.h \
|
||||||
serialize.h \
|
serialize.h \
|
||||||
@@ -249,13 +250,14 @@ libbitcoin_server_a_SOURCES = \
|
|||||||
asyncrpcoperation.cpp \
|
asyncrpcoperation.cpp \
|
||||||
asyncrpcqueue.cpp \
|
asyncrpcqueue.cpp \
|
||||||
bloom.cpp \
|
bloom.cpp \
|
||||||
|
cc/eval.cpp \
|
||||||
|
cc/importpayout.cpp \
|
||||||
chain.cpp \
|
chain.cpp \
|
||||||
checkpoints.cpp \
|
checkpoints.cpp \
|
||||||
deprecation.cpp \
|
deprecation.cpp \
|
||||||
httprpc.cpp \
|
httprpc.cpp \
|
||||||
httpserver.cpp \
|
httpserver.cpp \
|
||||||
init.cpp \
|
init.cpp \
|
||||||
komodo_cryptoconditions.cpp \
|
|
||||||
leveldbwrapper.cpp \
|
leveldbwrapper.cpp \
|
||||||
main.cpp \
|
main.cpp \
|
||||||
merkleblock.cpp \
|
merkleblock.cpp \
|
||||||
@@ -274,7 +276,7 @@ libbitcoin_server_a_SOURCES = \
|
|||||||
rpcnet.cpp \
|
rpcnet.cpp \
|
||||||
rpcrawtransaction.cpp \
|
rpcrawtransaction.cpp \
|
||||||
rpcserver.cpp \
|
rpcserver.cpp \
|
||||||
script/sigcache.cpp \
|
script/serverchecker.cpp \
|
||||||
timedata.cpp \
|
timedata.cpp \
|
||||||
torcontrol.cpp \
|
torcontrol.cpp \
|
||||||
txdb.cpp \
|
txdb.cpp \
|
||||||
@@ -378,7 +380,6 @@ libbitcoin_common_a_SOURCES = \
|
|||||||
hash.cpp \
|
hash.cpp \
|
||||||
key.cpp \
|
key.cpp \
|
||||||
keystore.cpp \
|
keystore.cpp \
|
||||||
komodo_cryptoconditions.cpp \
|
|
||||||
netbase.cpp \
|
netbase.cpp \
|
||||||
primitives/block.cpp \
|
primitives/block.cpp \
|
||||||
primitives/transaction.cpp \
|
primitives/transaction.cpp \
|
||||||
|
|||||||
@@ -25,4 +25,6 @@ zcash_CreateJoinSplit_LDADD = \
|
|||||||
$(LIBBITCOIN_UTIL) \
|
$(LIBBITCOIN_UTIL) \
|
||||||
$(LIBBITCOIN_CRYPTO) \
|
$(LIBBITCOIN_CRYPTO) \
|
||||||
$(BOOST_LIBS) \
|
$(BOOST_LIBS) \
|
||||||
$(LIBZCASH_LIBS)
|
$(LIBZCASH_LIBS) \
|
||||||
|
$(LIBCRYPTOCONDITIONS) \
|
||||||
|
$(LIBSECP256K1)
|
||||||
|
|||||||
23
src/cc/eval.cpp
Normal file
23
src/cc/eval.cpp
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#include "primitives/transaction.h"
|
||||||
|
#include "komodo_cc.h"
|
||||||
|
#include "cc/eval.h"
|
||||||
|
#include <cryptoconditions.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test the validity of an Eval node
|
||||||
|
*/
|
||||||
|
bool EvalConditionValidity(const CC *cond, const CTransaction *txTo, int nIn)
|
||||||
|
{
|
||||||
|
if (strcmp(cond->method, "testEval") == 0) {
|
||||||
|
return cond->paramsBinLength == 8 &&
|
||||||
|
memcmp(cond->paramsBin, "testEval", 8) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(cond->method, "ImportPayout") == 0) {
|
||||||
|
return CheckImportPayout(cond, txTo, nIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "no defined behaviour for method: %s\n", cond->method);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
18
src/cc/eval.h
Normal file
18
src/cc/eval.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#ifndef CC_EVAL_H
|
||||||
|
#define CC_EVAL_H
|
||||||
|
|
||||||
|
#include "cryptoconditions/include/cryptoconditions.h"
|
||||||
|
#include "primitives/transaction.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test validity of a CC_Eval node
|
||||||
|
*/
|
||||||
|
bool EvalConditionValidity(const CC *cond, const CTransaction *tx, int nIn);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test an ImportPayout CC Eval condition
|
||||||
|
*/
|
||||||
|
bool CheckImportPayout(const CC *cond, const CTransaction *payoutTx, int nIn);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* CC_EVAL_H */
|
||||||
191
src/cc/importpayout.cpp
Normal file
191
src/cc/importpayout.cpp
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
#include "primitives/transaction.h"
|
||||||
|
#include "streams.h"
|
||||||
|
#include "chain.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "cryptoconditions/include/cryptoconditions.h"
|
||||||
|
|
||||||
|
|
||||||
|
bool GetPushData(const CScript &sig, std::vector<unsigned char> &data)
|
||||||
|
{
|
||||||
|
opcodetype opcode;
|
||||||
|
auto pc = sig.begin();
|
||||||
|
if (sig.GetOp(pc, opcode, data)) return opcode > OP_0 && opcode <= OP_PUSHDATA4;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool GetOpReturnData(const CScript &sig, std::vector<unsigned char> &data)
|
||||||
|
{
|
||||||
|
auto pc = sig.begin();
|
||||||
|
opcodetype opcode;
|
||||||
|
if (sig.GetOp2(pc, opcode, NULL))
|
||||||
|
if (opcode == OP_RETURN)
|
||||||
|
if (sig.GetOp(pc, opcode, data))
|
||||||
|
return opcode > OP_0 && opcode <= OP_PUSHDATA4;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class MomProof
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uint256 notaryHash;
|
||||||
|
int nPos; // Position of imported tx in MoM
|
||||||
|
std::vector<uint256> branch;
|
||||||
|
|
||||||
|
ADD_SERIALIZE_METHODS;
|
||||||
|
|
||||||
|
template <typename Stream, typename Operation>
|
||||||
|
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||||
|
READWRITE(notaryHash);
|
||||||
|
READWRITE(VARINT(nPos));
|
||||||
|
READWRITE(branch);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp);
|
||||||
|
|
||||||
|
bool DerefNotaryPubkey(const COutPoint &prevout, char *pk33)
|
||||||
|
{
|
||||||
|
CTransaction tx;
|
||||||
|
uint256 hashBlock;
|
||||||
|
if (!GetTransaction(prevout.hash, tx, hashBlock, false)) return false;
|
||||||
|
if (tx.vout.size() < prevout.n) return false;
|
||||||
|
const unsigned char *script = tx.vout[prevout.n].scriptPubKey.data();
|
||||||
|
if (script[0] != 33) return false;
|
||||||
|
memcpy(pk33, script+1, 33);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t timestamp)
|
||||||
|
{
|
||||||
|
if (tx.vin.size() < 11) return false;
|
||||||
|
|
||||||
|
uint8_t notaries[64][33];
|
||||||
|
uint8_t seenNotaries[64];
|
||||||
|
int nNotaries = komodo_notaries(notaries, height, timestamp);
|
||||||
|
char *pk;
|
||||||
|
|
||||||
|
BOOST_FOREACH(const CTxIn &txIn, tx.vin)
|
||||||
|
{
|
||||||
|
if (!DerefNotaryPubkey(txIn.prevout, pk)) return false;
|
||||||
|
|
||||||
|
for (int i=0; i<nNotaries; i++) {
|
||||||
|
if (!seenNotaries[i]) {
|
||||||
|
if (memcmp(pk, notaries[i], 33) == 0) {
|
||||||
|
seenNotaries[i] = 1;
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
found:;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get MoM from a notarisation tx hash
|
||||||
|
*/
|
||||||
|
bool GetMoM(const uint256 notaryHash, uint256 &mom)
|
||||||
|
{
|
||||||
|
CTransaction notarisationTx;
|
||||||
|
uint256 notarisationBlock;
|
||||||
|
if (!GetTransaction(notaryHash, notarisationTx, notarisationBlock, true)) return 0;
|
||||||
|
CBlockIndex* blockindex = mapBlockIndex[notarisationBlock];
|
||||||
|
if (!CheckNotaryInputs(notarisationTx, blockindex->nHeight, blockindex->nTime)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!notarisationTx.vout.size() < 1) return 0;
|
||||||
|
std::vector<unsigned char> opret;
|
||||||
|
if (!GetOpReturnData(notarisationTx.vout[0].scriptPubKey, opret)) return 0;
|
||||||
|
if (opret.size() < 36) return 0; // In reality it is more than 36, but at the moment I
|
||||||
|
// only know where it is relative to the end, and this
|
||||||
|
// is enough to prevent a memory fault. In the case that
|
||||||
|
// the assumption about the presence of a MoM at this
|
||||||
|
// offset fails, we will return random other data that is
|
||||||
|
// not more likely to generate a false positive.
|
||||||
|
memcpy(mom.begin(), opret.data()+opret.size()-36, 32);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint256 ExecMerkle(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex)
|
||||||
|
{
|
||||||
|
return CBlock::CheckMerkleBranch(hash, vMerkleBranch, nIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Crypto-Condition EVAL method that verifies a payout against a transaction
|
||||||
|
* notarised on another chain.
|
||||||
|
*
|
||||||
|
* IN: cond - CC EVAL node
|
||||||
|
* IN: payoutTx - Payout transaction on value chain (KMD)
|
||||||
|
* IN: nIn - index of input of stake
|
||||||
|
*
|
||||||
|
* payoutTx: Spends stakeTx with payouts from asset chain
|
||||||
|
*
|
||||||
|
* in 0: Spends Stake TX and contains ImportPayout CC
|
||||||
|
* out 0: OP_RETURN MomProof
|
||||||
|
* out 1: OP_RETURN serialized exportTx from other chain
|
||||||
|
* out 2-: arbitrary payouts
|
||||||
|
*
|
||||||
|
* exportTx: Spends sessionTx.0 (opener on asset chain)
|
||||||
|
*
|
||||||
|
* in 0: spends sessionTx.0
|
||||||
|
* in 1-: anything
|
||||||
|
* out 0: OP_RETURN hash of payouts
|
||||||
|
* out 1-: anything
|
||||||
|
*/
|
||||||
|
bool CheckImportPayout(const CC *cond, const CTransaction *payoutTx, int nIn)
|
||||||
|
{
|
||||||
|
// TODO: Error messages!
|
||||||
|
if (payoutTx->vin.size() != 1) return 0;
|
||||||
|
if (payoutTx->vout.size() < 2) return 0;
|
||||||
|
|
||||||
|
// Get hash of payouts
|
||||||
|
std::vector<CTxOut> payouts(payoutTx->vout.begin() + 2, payoutTx->vout.end());
|
||||||
|
uint256 payoutsHash = SerializeHash(payouts);
|
||||||
|
std::vector<unsigned char> vPayoutsHash(payoutsHash.begin(), payoutsHash.end());
|
||||||
|
|
||||||
|
// load exportTx from vout[1]
|
||||||
|
CTransaction exportTx;
|
||||||
|
{
|
||||||
|
std::vector<unsigned char> exportData;
|
||||||
|
if (!GetOpReturnData(payoutTx->vout[1].scriptPubKey, exportData)) return 0;
|
||||||
|
CDataStream(exportData, SER_DISK, PROTOCOL_VERSION) >> exportTx;
|
||||||
|
// TODO: end of stream? exception?
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check exportTx.0 is vPayoutsHash
|
||||||
|
std::vector<unsigned char> exportPayoutsHash;
|
||||||
|
if (!GetOpReturnData(exportTx.vout[0].scriptPubKey, exportPayoutsHash)) return 0;
|
||||||
|
if (exportPayoutsHash != vPayoutsHash) return 0;
|
||||||
|
|
||||||
|
// Check exportTx spends sessionTx.0
|
||||||
|
// condition ImportPayout params is session ID from other chain
|
||||||
|
{
|
||||||
|
if (cond->paramsBinLength != 32) return 0;
|
||||||
|
COutPoint prevout = exportTx.vin[0].prevout;
|
||||||
|
if (memcmp(prevout.hash.begin(), cond->paramsBin, 32) != 0 ||
|
||||||
|
prevout.n != 0) return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check exportTx solves momproof from vout[0]
|
||||||
|
{
|
||||||
|
std::vector<unsigned char> vchMomProof;
|
||||||
|
if (!GetOpReturnData(payoutTx->vout[0].scriptPubKey, vchMomProof)) return 0;
|
||||||
|
|
||||||
|
MomProof momProof;
|
||||||
|
CDataStream(vchMomProof, SER_DISK, PROTOCOL_VERSION) >> momProof;
|
||||||
|
|
||||||
|
uint256 mom;
|
||||||
|
if (!GetMoM(momProof.notaryHash, mom)) return 0;
|
||||||
|
|
||||||
|
uint256 proofResult = ExecMerkle(exportTx.GetHash(), momProof.branch, momProof.nPos);
|
||||||
|
if (proofResult != mom) return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@ lib_LTLIBRARIES=libcryptoconditions.la
|
|||||||
noinst_LTLIBRARIES=$(CRYPTOCONDITIONS_CORE)
|
noinst_LTLIBRARIES=$(CRYPTOCONDITIONS_CORE)
|
||||||
SUBDIRS = src/include/secp256k1
|
SUBDIRS = src/include/secp256k1
|
||||||
|
|
||||||
|
include_HEADERS = include/cryptoconditions.h
|
||||||
|
|
||||||
# Have a separate build target for cryptoconditions that does not contain secp256k1
|
# Have a separate build target for cryptoconditions that does not contain secp256k1
|
||||||
|
|
||||||
libcryptoconditions_la_SOURCES = include/cryptoconditions.h
|
libcryptoconditions_la_SOURCES = include/cryptoconditions.h
|
||||||
|
|||||||
@@ -84,9 +84,9 @@ unsigned char* cc_conditionUri(const CC *cond);
|
|||||||
unsigned char* cc_jsonRPC(unsigned char *request);
|
unsigned char* cc_jsonRPC(unsigned char *request);
|
||||||
unsigned long cc_getCost(const CC *cond);
|
unsigned long cc_getCost(const CC *cond);
|
||||||
enum CCTypeId cc_typeId(const CC *cond);
|
enum CCTypeId cc_typeId(const CC *cond);
|
||||||
|
uint32_t cc_typeMask(const CC *cond);
|
||||||
void cc_free(struct CC *cond);
|
void cc_free(struct CC *cond);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ void appendUriSubtypes(uint32_t mask, unsigned char *buf) {
|
|||||||
} else {
|
} else {
|
||||||
strcat(buf, "&subtypes=");
|
strcat(buf, "&subtypes=");
|
||||||
strcat(buf, typeRegistry[i]->name);
|
strcat(buf, typeRegistry[i]->name);
|
||||||
|
append = 1;
|
||||||
}
|
}
|
||||||
append = 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,7 +70,7 @@ unsigned char *cc_conditionUri(const CC *cond) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static uint32_t getSubtypes(CC *cond) {
|
uint32_t cc_typeMask(const CC *cond) {
|
||||||
uint32_t mask = 1 << cond->type->typeId;
|
uint32_t mask = 1 << cond->type->typeId;
|
||||||
if (cond->type->hasSubtypes) {
|
if (cond->type->hasSubtypes) {
|
||||||
mask |= cond->type->getSubtypes(cond);
|
mask |= cond->type->getSubtypes(cond);
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ static CC *mkAnon(const Condition_t *asnCond);
|
|||||||
static void asnCondition(const CC *cond, Condition_t *asn);
|
static void asnCondition(const CC *cond, Condition_t *asn);
|
||||||
static Condition_t *asnConditionNew(const CC *cond);
|
static Condition_t *asnConditionNew(const CC *cond);
|
||||||
static Fulfillment_t *asnFulfillmentNew(const CC *cond);
|
static Fulfillment_t *asnFulfillmentNew(const CC *cond);
|
||||||
static uint32_t getSubtypes(CC *cond);
|
|
||||||
static cJSON *jsonEncodeCondition(cJSON *params, unsigned char *err);
|
static cJSON *jsonEncodeCondition(cJSON *params, unsigned char *err);
|
||||||
static struct CC *fulfillmentToCC(Fulfillment_t *ffill);
|
static struct CC *fulfillmentToCC(Fulfillment_t *ffill);
|
||||||
static struct CCType *getTypeByAsnEnum(Condition_PR present);
|
static struct CCType *getTypeByAsnEnum(Condition_PR present);
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ static Fulfillment_t *prefixToFulfillment(const CC *cond) {
|
|||||||
|
|
||||||
|
|
||||||
static uint32_t prefixSubtypes(const CC *cond) {
|
static uint32_t prefixSubtypes(const CC *cond) {
|
||||||
return getSubtypes(cond->subcondition) & ~(1 << cc_prefixType.typeId);
|
return cc_typeMask(cond->subcondition) & ~(1 << cc_prefixType.typeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ int secp256k1Verify(CC *cond, CCVisitor visitor) {
|
|||||||
|
|
||||||
|
|
||||||
static int cc_secp256k1VerifyTreeMsg32(const CC *cond, const unsigned char *msg32) {
|
static int cc_secp256k1VerifyTreeMsg32(const CC *cond, const unsigned char *msg32) {
|
||||||
int subtypes = getSubtypes(cond);
|
int subtypes = cc_typeMask(cond);
|
||||||
if (subtypes & (1 << cc_prefixType.typeId) &&
|
if (subtypes & (1 << cc_prefixType.typeId) &&
|
||||||
subtypes & (1 << cc_secp256k1Type.typeId)) {
|
subtypes & (1 << cc_secp256k1Type.typeId)) {
|
||||||
// No support for prefix currently, due to pending protocol decision on
|
// No support for prefix currently, due to pending protocol decision on
|
||||||
@@ -148,7 +148,7 @@ static int secp256k1Sign(CC *cond, CCVisitor visitor) {
|
|||||||
* Sign secp256k1 conditions in a tree
|
* Sign secp256k1 conditions in a tree
|
||||||
*/
|
*/
|
||||||
int cc_signTreeSecp256k1Msg32(CC *cond, const unsigned char *privateKey, const unsigned char *msg32) {
|
int cc_signTreeSecp256k1Msg32(CC *cond, const unsigned char *privateKey, const unsigned char *msg32) {
|
||||||
if (getSubtypes(cond) & (1 << cc_preimageType.typeId)) {
|
if (cc_typeMask(cond) & (1 << cc_preimageType.typeId)) {
|
||||||
// No support for prefix currently, due to pending protocol decision on
|
// No support for prefix currently, due to pending protocol decision on
|
||||||
// how to combine message and prefix into 32 byte hash
|
// how to combine message and prefix into 32 byte hash
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ struct CCType cc_thresholdType;
|
|||||||
static uint32_t thresholdSubtypes(const CC *cond) {
|
static uint32_t thresholdSubtypes(const CC *cond) {
|
||||||
uint32_t mask = 0;
|
uint32_t mask = 0;
|
||||||
for (int i=0; i<cond->size; i++) {
|
for (int i=0; i<cond->size; i++) {
|
||||||
mask |= getSubtypes(cond->subconditions[i]);
|
mask |= cc_typeMask(cond->subconditions[i]);
|
||||||
}
|
}
|
||||||
mask &= ~(1 << cc_thresholdType.typeId);
|
mask &= ~(1 << cc_thresholdType.typeId);
|
||||||
return mask;
|
return mask;
|
||||||
|
|||||||
40
src/komodo_cc.h
Normal file
40
src/komodo_cc.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#ifndef KOMODO_CC_H
|
||||||
|
#define KOMODO_CC_H
|
||||||
|
|
||||||
|
#include "cryptoconditions/include/cryptoconditions.h"
|
||||||
|
#include "primitives/transaction.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if CryptoConditions is enabled based on chain or cmd flag
|
||||||
|
*/
|
||||||
|
extern int32_t ASSETCHAINS_CC;
|
||||||
|
static bool IsCryptoConditionsEnabled()
|
||||||
|
{
|
||||||
|
return 0 != ASSETCHAINS_CC;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if the server can accept the condition based on it's structure / types
|
||||||
|
*/
|
||||||
|
static bool IsAcceptableCryptoCondition(const CC *cond)
|
||||||
|
{
|
||||||
|
int32_t typeMask = cc_typeMask(cond);
|
||||||
|
|
||||||
|
// Require a signature to prevent transaction malleability
|
||||||
|
if (0 == typeMask & (1 << CC_Secp256k1) ||
|
||||||
|
0 == typeMask & (1 << CC_Ed25519)) return false;
|
||||||
|
|
||||||
|
// Limit acceptable condition types
|
||||||
|
// Prefix not enabled because no current use case, ambiguity on how to combine with secp256k1
|
||||||
|
// RSA not enabled because no current use case, not implemented
|
||||||
|
int enabledTypes = 1 << CC_Secp256k1 | 1 << CC_Threshold | 1 << CC_Eval | \
|
||||||
|
1 << CC_Preimage | 1 << CC_Ed25519;
|
||||||
|
if (typeMask & ~enabledTypes) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* KOMODO_CC_H */
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
#include "komodo_cryptoconditions.h"
|
|
||||||
#include "cryptoconditions/include/cryptoconditions.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Evaluate the validity of an Eval node
|
|
||||||
*/
|
|
||||||
bool EvalConditionValidity(const CC *cond, const CTransaction *txTo)
|
|
||||||
{
|
|
||||||
if (strcmp(cond->method, "testEval") == 0) {
|
|
||||||
return cond->paramsBinLength == 8 &&
|
|
||||||
memcmp(cond->paramsBin, "testEval", 8) == 0;
|
|
||||||
}
|
|
||||||
fprintf(stderr, "no defined behaviour for method: %s\n", cond->method);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool GetOpReturnData(const CScript &sig, std::vector<unsigned char> &data)
|
|
||||||
{
|
|
||||||
auto pc = sig.begin();
|
|
||||||
opcodetype opcode;
|
|
||||||
if (sig.GetOp(pc, opcode))
|
|
||||||
if (opcode == OP_RETURN)
|
|
||||||
if (sig.GetOp(pc, opcode, data))
|
|
||||||
return opcode > OP_0 && opcode <= OP_PUSHDATA4;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#ifndef KOMODO_CRYPTOCONDITIONS_H
|
|
||||||
#define KOMODO_CRYPTOCONDITIONS_H
|
|
||||||
|
|
||||||
#include "cryptoconditions/include/cryptoconditions.h"
|
|
||||||
#include "primitives/transaction.h"
|
|
||||||
#include "script/script.h"
|
|
||||||
|
|
||||||
|
|
||||||
extern int32_t ASSETCHAINS_CC;
|
|
||||||
|
|
||||||
static bool IsCryptoConditionsEnabled() {
|
|
||||||
return 0 != ASSETCHAINS_CC;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EvalConditionValidity(const CC *cond, const CTransaction *tx);
|
|
||||||
|
|
||||||
bool GetOpReturnData(const CScript &sig, std::vector<unsigned char> &data);
|
|
||||||
|
|
||||||
#endif /* KOMODO_CRYPTOCONDITIONS_H */
|
|
||||||
@@ -1931,7 +1931,7 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
|
|||||||
|
|
||||||
bool CScriptCheck::operator()() {
|
bool CScriptCheck::operator()() {
|
||||||
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
|
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
|
||||||
if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), consensusBranchId, &error)) {
|
if (!VerifyScript(scriptSig, scriptPubKey, nFlags, ServerTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), consensusBranchId, &error)) {
|
||||||
return ::error("CScriptCheck(): %s:%d VerifySignature failed: %s", ptxTo->GetHash().ToString(), nIn, ScriptErrorString(error));
|
return ::error("CScriptCheck(): %s:%d VerifySignature failed: %s", ptxTo->GetHash().ToString(), nIn, ScriptErrorString(error));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
#include "primitives/block.h"
|
#include "primitives/block.h"
|
||||||
#include "primitives/transaction.h"
|
#include "primitives/transaction.h"
|
||||||
#include "script/script.h"
|
#include "script/script.h"
|
||||||
#include "script/sigcache.h"
|
#include "script/serverchecker.h"
|
||||||
#include "script/standard.h"
|
#include "script/standard.h"
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
#include "tinyformat.h"
|
#include "tinyformat.h"
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
#include "pubkey.h"
|
#include "pubkey.h"
|
||||||
#include "script/script.h"
|
#include "script/script.h"
|
||||||
#include "uint256.h"
|
#include "uint256.h"
|
||||||
#include "komodo_cryptoconditions.h"
|
#include "cryptoconditions/include/cryptoconditions.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@@ -1295,20 +1295,10 @@ bool TransactionSignatureChecker::CheckSig(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool TransactionSignatureChecker::CheckEvalCondition(const CC *cond) const
|
|
||||||
{
|
|
||||||
return EvalConditionValidity(cond, txTo);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int komodoCCEval(CC *cond, void *checker)
|
|
||||||
{
|
|
||||||
return ((TransactionSignatureChecker*)checker)->CheckEvalCondition(cond);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool TransactionSignatureChecker::CheckCryptoCondition(const CC *cond, const std::vector<unsigned char>& condBin, const CScript& scriptCode, uint32_t consensusBranchId) const
|
bool TransactionSignatureChecker::CheckCryptoCondition(const CC *cond, const std::vector<unsigned char>& condBin, const CScript& scriptCode, uint32_t consensusBranchId) const
|
||||||
{
|
{
|
||||||
|
if (!IsAcceptableCryptoCondition(cond)) return false;
|
||||||
|
|
||||||
uint256 sighash;
|
uint256 sighash;
|
||||||
try {
|
try {
|
||||||
sighash = SignatureHash(scriptCode, *txTo, nIn, SIGHASH_ALL, amount, consensusBranchId, this->txdata);
|
sighash = SignatureHash(scriptCode, *txTo, nIn, SIGHASH_ALL, amount, consensusBranchId, this->txdata);
|
||||||
@@ -1316,7 +1306,15 @@ bool TransactionSignatureChecker::CheckCryptoCondition(const CC *cond, const std
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return cc_verify(cond, (const unsigned char*)&sighash, 32, 0,
|
return cc_verify(cond, (const unsigned char*)&sighash, 32, 0,
|
||||||
condBin.data(), condBin.size(), komodoCCEval, (void*)this);
|
condBin.data(), condBin.size(), GetCCEval(), (void*)this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VerifyEval TransactionSignatureChecker::GetCCEval() const {
|
||||||
|
return [] (CC *cond, void *checker) {
|
||||||
|
fprintf(stderr, "Cannot check crypto-condition Eval outside of server\n");
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#include "script_error.h"
|
#include "script_error.h"
|
||||||
#include "primitives/transaction.h"
|
#include "primitives/transaction.h"
|
||||||
#include "komodo_cryptoconditions.h"
|
#include "komodo_cc.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -153,7 +153,7 @@ public:
|
|||||||
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, uint32_t consensusBranchId) const;
|
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, uint32_t consensusBranchId) const;
|
||||||
bool CheckLockTime(const CScriptNum& nLockTime) const;
|
bool CheckLockTime(const CScriptNum& nLockTime) const;
|
||||||
bool CheckCryptoCondition(const CC *cond, const std::vector<unsigned char>& condBin, const CScript& scriptCode, uint32_t consensusBranchId) const;
|
bool CheckCryptoCondition(const CC *cond, const std::vector<unsigned char>& condBin, const CScript& scriptCode, uint32_t consensusBranchId) const;
|
||||||
bool CheckEvalCondition(const CC *cond) const;
|
VerifyEval GetCCEval() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MutableTransactionSignatureChecker : public TransactionSignatureChecker
|
class MutableTransactionSignatureChecker : public TransactionSignatureChecker
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include "tinyformat.h"
|
#include "tinyformat.h"
|
||||||
#include "utilstrencodings.h"
|
#include "utilstrencodings.h"
|
||||||
|
#include "komodo_cc.h"
|
||||||
|
#include "cryptoconditions/include/cryptoconditions.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
inline std::string ValueString(const std::vector<unsigned char>& vch)
|
inline std::string ValueString(const std::vector<unsigned char>& vch)
|
||||||
@@ -238,6 +240,20 @@ bool CScript::IsPayToCryptoCondition() const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CScript::MayAcceptCryptoCondition() const
|
||||||
|
{
|
||||||
|
// Get the type mask of the condition
|
||||||
|
const_iterator pc = this->begin();
|
||||||
|
vector<unsigned char> data;
|
||||||
|
opcodetype opcode;
|
||||||
|
if (!this->GetOp(pc, opcode, data)) return false;
|
||||||
|
if (!(opcode > OP_0 && opcode < OP_PUSHDATA1)) return false;
|
||||||
|
CC *cond = cc_readConditionBinary(data.data(), data.size());
|
||||||
|
if (!cond) return false;
|
||||||
|
bool accept = IsAcceptableCryptoCondition(cond);
|
||||||
|
return accept;
|
||||||
|
}
|
||||||
|
|
||||||
bool CScript::IsPushOnly() const
|
bool CScript::IsPushOnly() const
|
||||||
{
|
{
|
||||||
const_iterator pc = begin();
|
const_iterator pc = begin();
|
||||||
|
|||||||
@@ -565,6 +565,7 @@ public:
|
|||||||
|
|
||||||
bool IsPayToScriptHash() const;
|
bool IsPayToScriptHash() const;
|
||||||
bool IsPayToCryptoCondition() const;
|
bool IsPayToCryptoCondition() const;
|
||||||
|
bool MayAcceptCryptoCondition() const;
|
||||||
|
|
||||||
/** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */
|
/** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */
|
||||||
bool IsPushOnly() const;
|
bool IsPushOnly() const;
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
// Distributed under the MIT software license, see the accompanying
|
// Distributed under the MIT software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
#include "sigcache.h"
|
#include "serverchecker.h"
|
||||||
|
#include "komodo_cc.h"
|
||||||
|
#include "cc/eval.h"
|
||||||
|
|
||||||
#include "pubkey.h"
|
#include "pubkey.h"
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
@@ -26,13 +28,13 @@ private:
|
|||||||
//! sigdata_type is (signature hash, signature, public key):
|
//! sigdata_type is (signature hash, signature, public key):
|
||||||
typedef boost::tuple<uint256, std::vector<unsigned char>, CPubKey> sigdata_type;
|
typedef boost::tuple<uint256, std::vector<unsigned char>, CPubKey> sigdata_type;
|
||||||
std::set< sigdata_type> setValid;
|
std::set< sigdata_type> setValid;
|
||||||
boost::shared_mutex cs_sigcache;
|
boost::shared_mutex cs_serverchecker;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool
|
bool
|
||||||
Get(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey)
|
Get(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey)
|
||||||
{
|
{
|
||||||
boost::shared_lock<boost::shared_mutex> lock(cs_sigcache);
|
boost::shared_lock<boost::shared_mutex> lock(cs_serverchecker);
|
||||||
|
|
||||||
sigdata_type k(hash, vchSig, pubKey);
|
sigdata_type k(hash, vchSig, pubKey);
|
||||||
std::set<sigdata_type>::iterator mi = setValid.find(k);
|
std::set<sigdata_type>::iterator mi = setValid.find(k);
|
||||||
@@ -47,10 +49,10 @@ public:
|
|||||||
// (~200 bytes per cache entry times 50,000 entries)
|
// (~200 bytes per cache entry times 50,000 entries)
|
||||||
// Since there can be no more than 20,000 signature operations per block
|
// Since there can be no more than 20,000 signature operations per block
|
||||||
// 50,000 is a reasonable default.
|
// 50,000 is a reasonable default.
|
||||||
int64_t nMaxCacheSize = GetArg("-maxsigcachesize", 50000);
|
int64_t nMaxCacheSize = GetArg("-maxservercheckersize", 50000);
|
||||||
if (nMaxCacheSize <= 0) return;
|
if (nMaxCacheSize <= 0) return;
|
||||||
|
|
||||||
boost::unique_lock<boost::shared_mutex> lock(cs_sigcache);
|
boost::unique_lock<boost::shared_mutex> lock(cs_serverchecker);
|
||||||
|
|
||||||
while (static_cast<int64_t>(setValid.size()) > nMaxCacheSize)
|
while (static_cast<int64_t>(setValid.size()) > nMaxCacheSize)
|
||||||
{
|
{
|
||||||
@@ -74,7 +76,7 @@ public:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CachingTransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
|
bool ServerTransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
|
||||||
{
|
{
|
||||||
static CSignatureCache signatureCache;
|
static CSignatureCache signatureCache;
|
||||||
|
|
||||||
@@ -88,3 +90,24 @@ bool CachingTransactionSignatureChecker::VerifySignature(const std::vector<unsig
|
|||||||
signatureCache.Set(sighash, vchSig, pubkey);
|
signatureCache.Set(sighash, vchSig, pubkey);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The reason that these functions are here is that the what used to be the
|
||||||
|
* CachingTransactionSignatureChecker, now the ServerTransactionSignatureChecker,
|
||||||
|
* is an entry point that the server uses to validate signatures and which is not
|
||||||
|
* included as part of bitcoin common libs. Since Crypto-Condtions eval methods
|
||||||
|
* may call server code (GetTransaction etc), the best way to get it to run this
|
||||||
|
* code without pulling the whole bitcoin server code into bitcoin common was
|
||||||
|
* using this class. Thus it has been renamed to ServerTransactionSignatureChecker.
|
||||||
|
*/
|
||||||
|
VerifyEval ServerTransactionSignatureChecker::GetCCEval() const
|
||||||
|
{
|
||||||
|
return [] (CC *cond, void *checker) {
|
||||||
|
return ((ServerTransactionSignatureChecker*)checker)->CheckEvalCondition(cond);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
int ServerTransactionSignatureChecker::CheckEvalCondition(CC *cond) const
|
||||||
|
{
|
||||||
|
return EvalConditionValidity(cond, txTo, nIn);
|
||||||
|
}
|
||||||
30
src/script/serverchecker.h
Normal file
30
src/script/serverchecker.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||||
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#ifndef BITCOIN_SCRIPT_SERVERCHECKER_H
|
||||||
|
#define BITCOIN_SCRIPT_SERVERCHECKER_H
|
||||||
|
|
||||||
|
#include "script/interpreter.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class CPubKey;
|
||||||
|
|
||||||
|
class ServerTransactionSignatureChecker : public TransactionSignatureChecker
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
bool store;
|
||||||
|
const CTransaction* txTo;
|
||||||
|
unsigned int nIn;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ServerTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amount, txdataIn), store(storeIn) {}
|
||||||
|
|
||||||
|
bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
|
||||||
|
int CheckEvalCondition(CC *cond) const;
|
||||||
|
VerifyEval GetCCEval() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BITCOIN_SCRIPT_SERVERCHECKER_H
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|
||||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
|
||||||
// Distributed under the MIT software license, see the accompanying
|
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
||||||
|
|
||||||
#ifndef BITCOIN_SCRIPT_SIGCACHE_H
|
|
||||||
#define BITCOIN_SCRIPT_SIGCACHE_H
|
|
||||||
|
|
||||||
#include "script/interpreter.h"
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
class CPubKey;
|
|
||||||
|
|
||||||
class CachingTransactionSignatureChecker : public TransactionSignatureChecker
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
bool store;
|
|
||||||
|
|
||||||
public:
|
|
||||||
CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amount, txdataIn), store(storeIn) {}
|
|
||||||
|
|
||||||
bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // BITCOIN_SCRIPT_SIGCACHE_H
|
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
#include "script/script.h"
|
#include "script/script.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utilstrencodings.h"
|
#include "utilstrencodings.h"
|
||||||
#include "komodo_cryptoconditions.h"
|
#include "komodo_cc.h"
|
||||||
|
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
@@ -72,9 +72,11 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
|
|||||||
if (IsCryptoConditionsEnabled()) {
|
if (IsCryptoConditionsEnabled()) {
|
||||||
// Shortcut for pay-to-crypto-condition
|
// Shortcut for pay-to-crypto-condition
|
||||||
if (scriptPubKey.IsPayToCryptoCondition()) {
|
if (scriptPubKey.IsPayToCryptoCondition()) {
|
||||||
typeRet = TX_CRYPTOCONDITION;
|
if (scriptPubKey.MayAcceptCryptoCondition()) {
|
||||||
// TODO: Extract solutions
|
typeRet = TX_CRYPTOCONDITION;
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user