Compare commits
124 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 33051b5bee | |||
| e79da7f582 | |||
| 39fa08d769 | |||
| ae02e63ddc | |||
| 9128ef79b9 | |||
| 8bbcc07dd2 | |||
| ff5917f45f | |||
| de812d9c9a | |||
| 5de3d11ccb | |||
| 49a238086e | |||
| 91b90dbc01 | |||
| 8f3385902d | |||
| ad6ba0d7f0 | |||
| 1608a9e1a9 | |||
| 14e378aa0f | |||
| dd4be285f1 | |||
| b9260e0c7b | |||
| d93aaec6a5 | |||
| bd1af278a5 | |||
| 2a4f5cea7c | |||
| 16eba0d12d | |||
| aa39526fe8 | |||
| 44ee67d21f | |||
| 0f9c969b83 | |||
| ac5dcc2133 | |||
| 069c83ef32 | |||
| 655f79b0e0 | |||
| 01ed1460e3 | |||
| bd7fb25315 | |||
| cdf439d83f | |||
| d47d988a72 | |||
| 1c06a70b58 | |||
| 20c20f5522 | |||
| a275227d76 | |||
| ac1425cbcb | |||
| f1a39778cb | |||
| 79e5c63a7d | |||
| d58b8a8f8d | |||
| 37d2297a2b | |||
| 5afa141942 | |||
| 088a0f4c00 | |||
| c75b1d464b | |||
| b3e74bffda | |||
| c696b5b43f | |||
| 084ea7fd77 | |||
| e7a1430242 | |||
| a138d12221 | |||
| dd63cb209d | |||
| 161ec204e6 | |||
| 2104ac35d5 | |||
| 30a1cf7813 | |||
| 32dfbcf8ea | |||
| b8d2ba017e | |||
| b18445f6e7 | |||
| bea129bb73 | |||
| 690e900011 | |||
| 516511da69 | |||
| 0aadf3db51 | |||
| be8c2e9c8f | |||
| 66854eb683 | |||
| a9f2317ffa | |||
| eea6d166b2 | |||
| 6bb5e00c17 | |||
| 7bbb0cf80e | |||
| 16f9569d0c | |||
| e6143eb9c0 | |||
| 1b2f6af8f8 | |||
| eb61aefe8b | |||
| 1d0ada1c82 | |||
| 0bb1785826 | |||
| 1c48ad7e46 | |||
| f0c26e6d5b | |||
| 7a1d7271a1 | |||
| 30e051fa46 | |||
| 4ccd4fdca7 | |||
| 71bda2c8bb | |||
| 261c518133 | |||
| 2a1741ac52 | |||
| 1f59698bda | |||
| 3238964d2a | |||
| 85260f0281 | |||
| 8c944e469c | |||
| dae35d962a | |||
| 89fc132363 | |||
| af3cc3e902 | |||
| 4d8a30042e | |||
| a760b46501 | |||
| 9ef2d782c1 | |||
| 278654276e | |||
| 5ca2284583 | |||
| 100f6cb2d5 | |||
| 59edc8c114 | |||
| 82693cbe57 | |||
| 1547e8d121 | |||
| 22c123ff32 | |||
| 8e026a0684 | |||
| 7fa30e45cc | |||
| 5747436dd3 | |||
| 62b4dc68e7 | |||
| 6731280da4 | |||
| d1281ee79f | |||
| 1182f790c5 | |||
| d3a0336291 | |||
| 0c18e18560 | |||
| 23c3520d13 | |||
| fa62a68afa | |||
| 1afe313308 | |||
| 516160568f | |||
| 157948193d | |||
| b627d4d36e | |||
| eb4d1a5225 | |||
| bdefbffd43 | |||
| 125a1ab637 | |||
| f97a87a97a | |||
| 3b5542e94a | |||
| 9bc777cf7d | |||
| 66fd45fd11 | |||
| 6c09ba09fd | |||
| 90aac49c77 | |||
| e6ebe4d355 | |||
| 0e72d68d94 | |||
| 170d0c0ec9 | |||
| 5548c6de53 | |||
| 56ea8f3792 |
@@ -0,0 +1,19 @@
|
||||
on: push
|
||||
|
||||
name: Test
|
||||
|
||||
jobs:
|
||||
build_lin:
|
||||
name: Ubuntu test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Prepare Ubuntu tools
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt-get install -y libboost-dev libboost-system-dev libboost-date-time-dev libsodium-dev
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@master
|
||||
- name: Test
|
||||
run: |
|
||||
npm install
|
||||
./tests/run.sh
|
||||
@@ -4,7 +4,8 @@ Node-CryptoForkNote-Util with Merged Mining support
|
||||
Installing locally and testing
|
||||
-----
|
||||
```
|
||||
npm install https://github.com/MoneroOcean/node-cryptoforknote-util
|
||||
JOBS=$(nproc) npm install https://github.com/MoneroOcean/node-cryptoforknote-util
|
||||
node_modules/cryptoforknote-util/tests/run.sh
|
||||
```
|
||||
|
||||
Dependencies
|
||||
|
||||
+4
-2
@@ -4,8 +4,10 @@
|
||||
"target_name": "cryptoforknote",
|
||||
"sources": [
|
||||
"src/main.cc",
|
||||
"src/cryptonote_core/cryptonote_format_utils.cpp",
|
||||
"src/cryptonote_basic/cryptonote_format_utils.cpp",
|
||||
"src/offshore/pricing_record.cpp",
|
||||
"src/zephyr_oracle/pricing_record.cpp",
|
||||
"src/salvium_oracle/pricing_record.cpp",
|
||||
"src/crypto/tree-hash.c",
|
||||
"src/crypto/crypto.cpp",
|
||||
"src/crypto/crypto-ops.c",
|
||||
@@ -30,7 +32,7 @@
|
||||
"-fno-exceptions -std=gnu11 -march=native -fPIC -DNDEBUG -Ofast -funroll-loops -fvariable-expansion-in-unroller -ftree-loop-if-convert-stores -fmerge-all-constants -fbranch-target-load-optimize2"
|
||||
],
|
||||
"cflags_cc": [
|
||||
"-fexceptions -frtti -std=gnu++11 -march=native -fPIC -DNDEBUG -Ofast -s -funroll-loops -fvariable-expansion-in-unroller -ftree-loop-if-convert-stores -fmerge-all-constants -fbranch-target-load-optimize2"
|
||||
"-fexceptions -frtti -std=c++17 -march=native -fPIC -DNDEBUG -Ofast -s -funroll-loops -fvariable-expansion-in-unroller -ftree-loop-if-convert-stores -fmerge-all-constants -fbranch-target-load-optimize2"
|
||||
],
|
||||
"xcode_settings": {
|
||||
"OTHER_CFLAGS": [ "-fexceptions -frtti" ]
|
||||
|
||||
@@ -46,10 +46,28 @@ function hash256(buffer) {
|
||||
return sha256(sha256(buffer));
|
||||
};
|
||||
|
||||
function getMerkleRoot(transactions) {
|
||||
function sha256_3(buffer) {
|
||||
return crypto.createHash('sha3-256').update(buffer).digest();
|
||||
};
|
||||
|
||||
function hash256_3(buffer) {
|
||||
return sha256_3(sha256_3(buffer));
|
||||
};
|
||||
|
||||
function transaction_hash(transaction, forWitness) {
|
||||
if (forWitness && transaction.isCoinbase()) return Buffer.alloc(32, 0);
|
||||
return hash256(transaction.__toBuffer(undefined, undefined, forWitness));
|
||||
}
|
||||
|
||||
function transaction_hash3(transaction, forWitness) {
|
||||
if (forWitness && transaction.isCoinbase()) return Buffer.alloc(32, 0);
|
||||
return hash256_3(transaction.__toBuffer(undefined, undefined, forWitness));
|
||||
}
|
||||
|
||||
function getMerkleRoot(transactions, transaction_hash_func, detectWitness) {
|
||||
if (transactions.length === 0) return Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex')
|
||||
const forWitness = txesHaveWitnessCommit(transactions);
|
||||
const hashes = transactions.map(transaction => transaction.getHash(forWitness));
|
||||
const forWitness = detectWitness ? txesHaveWitnessCommit(transactions) : false;
|
||||
const hashes = transactions.map(transaction => transaction_hash_func(transaction, forWitness));
|
||||
const rootHash = fastMerkleRoot(hashes, hash256);
|
||||
return forWitness ? hash256(Buffer.concat([rootHash, transactions[0].ins[0].witness[0]])) : rootHash;
|
||||
}
|
||||
@@ -92,6 +110,11 @@ module.exports.RavenBlockTemplate = function(rpcData, poolAddress) {
|
||||
|
||||
txCoinbase.addOutput(scriptCompile(poolAddrHash), Math.floor(rpcData.coinbasevalue));
|
||||
|
||||
// For CLORE
|
||||
if (rpcData.CommunityAutonomousAddress && rpcData.CommunityAutonomousValue) {
|
||||
txCoinbase.addOutput(scriptCompile(bitcoin.address.fromBase58Check(rpcData.CommunityAutonomousAddress).hash), Math.floor(rpcData.CommunityAutonomousValue));
|
||||
}
|
||||
|
||||
if (rpcData.default_witness_commitment) {
|
||||
txCoinbase.addOutput(Buffer.from(rpcData.default_witness_commitment, 'hex'), 0);
|
||||
}
|
||||
@@ -107,14 +130,14 @@ module.exports.RavenBlockTemplate = function(rpcData, poolAddress) {
|
||||
header.writeUInt32BE(rpcData.version, position += 32, 4); // version 121-153
|
||||
header = reverseBuffer(header);
|
||||
}
|
||||
|
||||
|
||||
let blob = Buffer.concat([
|
||||
header, // 80 bytes
|
||||
Buffer.from('AAAAAAAAAAAAAAAA', 'hex'), // 8 bytes
|
||||
Buffer.from('BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB', 'hex'), // 32 bytes
|
||||
varuint.encode(rpcData.transactions.length + 1, Buffer.alloc(varuint.encodingLength(rpcData.transactions.length + 1)), 0)
|
||||
]);
|
||||
const offset1 = blob.length;
|
||||
const offset1 = blob.length;
|
||||
blob = Buffer.concat([ blob, Buffer.from(txCoinbase.toHex(), 'hex') ]);
|
||||
|
||||
rpcData.transactions.forEach(function (value) {
|
||||
@@ -152,7 +175,7 @@ module.exports.RavenBlockTemplate = function(rpcData, poolAddress) {
|
||||
};
|
||||
};
|
||||
|
||||
function update_merkle_root_hash(offset, payload, blob_in, blob_out) {
|
||||
function update_merkle_root_hash(offset, payload, blob_in, blob_out, transaction_hash_func, detectWitness) {
|
||||
const nTransactions = varuint.decode(blob_in, offset);
|
||||
offset += varuint.decode.bytes;
|
||||
let transactions = [];
|
||||
@@ -161,17 +184,25 @@ function update_merkle_root_hash(offset, payload, blob_in, blob_out) {
|
||||
transactions.push(tx);
|
||||
offset += tx.byteLength();
|
||||
}
|
||||
getMerkleRoot(transactions).copy(blob_out, 4 + 32);
|
||||
getMerkleRoot(transactions, transaction_hash_func, detectWitness).copy(blob_out, 4 + 32);
|
||||
};
|
||||
|
||||
module.exports.blockHashBuff = function(blobBuffer) {
|
||||
return reverseBuffer(hash256(blobBuffer));
|
||||
};
|
||||
|
||||
module.exports.blockHashBuff3 = function(blobBuffer) {
|
||||
return reverseBuffer(hash256_3(blobBuffer));
|
||||
};
|
||||
|
||||
module.exports.convertRavenBlob = function(blobBuffer) {
|
||||
let header = blobBuffer.slice(0, 80);
|
||||
update_merkle_root_hash(80 + 8 + 32, false, blobBuffer, header);
|
||||
return reverseBuffer(hash256(header));
|
||||
update_merkle_root_hash(80 + 8 + 32, false, blobBuffer, header, transaction_hash, true);
|
||||
return module.exports.blockHashBuff(header);
|
||||
};
|
||||
|
||||
module.exports.constructNewRavenBlob = function(blockTemplate, nonceBuff, mixhashBuff) {
|
||||
update_merkle_root_hash(80 + 8 + 32, false, blockTemplate, blockTemplate);
|
||||
update_merkle_root_hash(80 + 8 + 32, false, blockTemplate, blockTemplate, transaction_hash, true);
|
||||
nonceBuff.copy (blockTemplate, 80, 0, 8);
|
||||
mixhashBuff.copy(blockTemplate, 88, 0, 32);
|
||||
return blockTemplate;
|
||||
@@ -208,12 +239,24 @@ module.exports.RtmBlockTemplate = function(rpcData, poolAddress) {
|
||||
|
||||
module.exports.convertRtmBlob = function(blobBuffer) {
|
||||
let header = blobBuffer.slice(0, 80);
|
||||
update_merkle_root_hash(80, true, blobBuffer, header);
|
||||
update_merkle_root_hash(80, true, blobBuffer, header, transaction_hash, true);
|
||||
return header;
|
||||
};
|
||||
|
||||
module.exports.convertKcnBlob = function(blobBuffer) {
|
||||
let header = blobBuffer.slice(0, 80);
|
||||
update_merkle_root_hash(80, false, blobBuffer, header, transaction_hash3, false);
|
||||
return header;
|
||||
};
|
||||
|
||||
module.exports.constructNewRtmBlob = function(blockTemplate, nonceBuff) {
|
||||
update_merkle_root_hash(80, true, blockTemplate, blockTemplate);
|
||||
update_merkle_root_hash(80, true, blockTemplate, blockTemplate, transaction_hash, true);
|
||||
nonceBuff.copy(blockTemplate, 76, 0, 4);
|
||||
return blockTemplate;
|
||||
};
|
||||
|
||||
module.exports.constructNewKcnBlob = function(blockTemplate, nonceBuff) {
|
||||
update_merkle_root_hash(80, false, blockTemplate, blockTemplate, transaction_hash3, false);
|
||||
nonceBuff.copy(blockTemplate, 76, 0, 4);
|
||||
return blockTemplate;
|
||||
};
|
||||
|
||||
+9
-9
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"name": "cryptoforknote-util",
|
||||
"version": "11.0.0",
|
||||
"main": "cryptoforknote-util",
|
||||
"version": "15.8.4",
|
||||
"author": {
|
||||
"name": "LucasJones",
|
||||
"email": "lucasjonesdev@hotmail.co.uk"
|
||||
@@ -11,15 +10,16 @@
|
||||
"url": "https://github.com/haven-protocol-org/node-cryptoforknote-util.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"promise": "*",
|
||||
"bindings": "*",
|
||||
"nan": "^2.14.2",
|
||||
"bignum": "^0.13.1",
|
||||
"sha3": "*",
|
||||
"base58-native": "*",
|
||||
"varuint-bitcoin": "^1.0.4",
|
||||
"bech32": "*",
|
||||
"bignum": "^0.13.1",
|
||||
"bindings": "*",
|
||||
"bitcoinjs-lib": "git+https://github.com/MoneroOcean/bitcoinjs-lib.git",
|
||||
"merkle-lib": "^2.0.10",
|
||||
"bitcoinjs-lib": "git+https://github.com/MoneroOcean/bitcoinjs-lib.git"
|
||||
"nan": "^2.20.0",
|
||||
"promise": "*",
|
||||
"sha3": "*",
|
||||
"varuint-bitcoin": "^1.0.4"
|
||||
},
|
||||
"keywords": [
|
||||
"cryptonight",
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
const bignum = require('bignum');
|
||||
const base58 = require('base58-native');
|
||||
const bignum = require('bignum');
|
||||
const base58 = require('base58-native');
|
||||
const bech32 = require('bech32');
|
||||
const bitcoin = require('bitcoinjs-lib');
|
||||
|
||||
const diff1 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
|
||||
|
||||
@@ -147,14 +149,20 @@ function getTransactionBuffers(txs) {
|
||||
}
|
||||
|
||||
function addressToScript(addr) {
|
||||
const decoded = base58.decode(addr);
|
||||
if (decoded.length != 25) throw new Error('Invalid address length for ' + addr);
|
||||
if (!decoded) throw new Error('Base58 decode failed for ' + addr);
|
||||
let decoded;
|
||||
try {
|
||||
decoded = base58.decode(addr);
|
||||
} catch(err) {}
|
||||
if (!decoded || decoded.length != 25) {
|
||||
const decoded2 = Buffer.from(bech32.bech32.fromWords(bech32.bech32.decode(addr).words.slice(1)));
|
||||
if (decoded2.length != 20) throw new Error('Invalid address ' + addr);
|
||||
return Buffer.concat([Buffer.from([0x0, 0x14]), decoded2]);
|
||||
}
|
||||
const pubkey = decoded.slice(1, -4);
|
||||
return Buffer.concat([Buffer.from([0x76, 0xa9, 0x14]), pubkey, Buffer.from([0x88, 0xac])]);
|
||||
}
|
||||
|
||||
function createOutputTransaction(amount, payee, rewardToPool, reward, txOutputBuffers, payeeScript) {
|
||||
function createTransactionOutput(amount, payee, rewardToPool, reward, txOutputBuffers, payeeScript) {
|
||||
const payeeReward = amount;
|
||||
if (!payeeScript) payeeScript = addressToScript(payee);
|
||||
txOutputBuffers.push(Buffer.concat([
|
||||
@@ -165,19 +173,25 @@ function createOutputTransaction(amount, payee, rewardToPool, reward, txOutputBu
|
||||
return { reward: reward - amount, rewardToPool: rewardToPool - amount };
|
||||
}
|
||||
|
||||
function generateOutputTransactions(rpcData, poolAddress) {
|
||||
let reward = rpcData.coinbasevalue;
|
||||
function generateTransactionOutputs(rpcData, poolAddress) {
|
||||
let reward = rpcData.coinbasevalue + (rpcData.coinbasedevreward ? rpcData.coinbasedevreward.value : 0);
|
||||
let rewardToPool = reward;
|
||||
let txOutputBuffers = [];
|
||||
|
||||
if (rpcData.coinbasedevreward) {
|
||||
const rewards = createTransactionOutput(rpcData.coinbasedevreward.value, null, rewardToPool, reward, txOutputBuffers, Buffer.from(rpcData.coinbasedevreward.scriptpubkey, 'hex'));
|
||||
reward = rewards.reward;
|
||||
rewardToPool = rewards.rewardToPool;
|
||||
}
|
||||
|
||||
if (rpcData.smartnode) {
|
||||
if (rpcData.smartnode.payee) {
|
||||
const rewards = createOutputTransaction(rpcData.smartnode.amount, rpcData.smartnode.payee, rewardToPool, reward, txOutputBuffers);
|
||||
const rewards = createTransactionOutput(rpcData.smartnode.amount, rpcData.smartnode.payee, rewardToPool, reward, txOutputBuffers);
|
||||
reward = rewards.reward;
|
||||
rewardToPool = rewards.rewardToPool;
|
||||
} else if (Array.isArray(rpcData.smartnode)) {
|
||||
for (let i in rpcData.smartnode) {
|
||||
const rewards = createOutputTransaction(rpcData.smartnode[i].amount, rpcData.smartnode[i].payee, rewardToPool, reward, txOutputBuffers);
|
||||
const rewards = createTransactionOutput(rpcData.smartnode[i].amount, rpcData.smartnode[i].payee, rewardToPool, reward, txOutputBuffers);
|
||||
reward = rewards.reward;
|
||||
rewardToPool = rewards.rewardToPool;
|
||||
}
|
||||
@@ -186,7 +200,7 @@ function generateOutputTransactions(rpcData, poolAddress) {
|
||||
|
||||
if (rpcData.superblock) {
|
||||
for (let i in rpcData.superblock) {
|
||||
const rewards = createOutputTransaction(rpcData.superblock[i].amount, rpcData.superblock[i].payee, rewardToPool, reward, txOutputBuffers);
|
||||
const rewards = createTransactionOutput(rpcData.superblock[i].amount, rpcData.superblock[i].payee, rewardToPool, reward, txOutputBuffers);
|
||||
reward = rewards.reward;
|
||||
rewardToPool = rewards.rewardToPool;
|
||||
}
|
||||
@@ -194,41 +208,44 @@ function generateOutputTransactions(rpcData, poolAddress) {
|
||||
|
||||
if (rpcData.founder_payments_started && rpcData.founder) {
|
||||
const founderReward = rpcData.founder.amount || 0;
|
||||
const rewards = createOutputTransaction(founderReward, rpcData.founder.payee, rewardToPool, reward, txOutputBuffers);
|
||||
const rewards = createTransactionOutput(founderReward, rpcData.founder.payee, rewardToPool, reward, txOutputBuffers);
|
||||
reward = rewards.reward;
|
||||
rewardToPool = rewards.rewardToPool;
|
||||
}
|
||||
|
||||
createOutputTransaction(rewardToPool, null, rewardToPool, reward, txOutputBuffers, Buffer.from(addressToScript(poolAddress), "hex"));
|
||||
createTransactionOutput(rewardToPool, null, rewardToPool, reward, txOutputBuffers, Buffer.from(addressToScript(poolAddress), "hex"));
|
||||
|
||||
if (rpcData.default_witness_commitment !== undefined) {
|
||||
const witness_commitment = Buffer.from(rpcData.default_witness_commitment, 'hex');
|
||||
txOutputBuffers.unshift(Buffer.concat([
|
||||
packInt64LE(0),
|
||||
varIntBuffer(witness_commitment.length),
|
||||
witness_commitment
|
||||
if (rpcData.default_witness_commitment) {
|
||||
createTransactionOutput(0, null, rewardToPool, reward, txOutputBuffers, Buffer.from(rpcData.default_witness_commitment, 'hex'));
|
||||
txOutputBuffers.push(Buffer.concat([
|
||||
varIntBuffer(1),
|
||||
varIntBuffer(32),
|
||||
Buffer.alloc(32, 0)
|
||||
]));
|
||||
}
|
||||
|
||||
return Buffer.concat([ varIntBuffer(txOutputBuffers.length), Buffer.concat(txOutputBuffers)]);
|
||||
return Buffer.concat([ varIntBuffer(rpcData.default_witness_commitment ? txOutputBuffers.length - 1 : txOutputBuffers.length), Buffer.concat(txOutputBuffers)]);
|
||||
}
|
||||
|
||||
module.exports.RtmBlockTemplate = function(rpcData, poolAddress) {
|
||||
const extraNoncePlaceholderLength = 17;
|
||||
const coinbaseVersion = Buffer.concat([packUInt16LE(3), packUInt16LE(5)]);
|
||||
const coinbaseVersion = rpcData.coinbasedevreward ? Buffer.concat([packUInt16LE(1), packUInt16LE(0)]) : Buffer.concat([packUInt16LE(3), packUInt16LE(5)]);
|
||||
|
||||
const scriptSigPart1 = Buffer.concat([
|
||||
serializeNumber(rpcData.height),
|
||||
Buffer.from(rpcData.coinbaseaux.flags, 'hex'),
|
||||
Buffer.from(rpcData.coinbaseaux.flags ? rpcData.coinbaseaux.flags : "", 'hex'),
|
||||
serializeNumber(Date.now() / 1000 | 0),
|
||||
Buffer.from([extraNoncePlaceholderLength])
|
||||
]);
|
||||
|
||||
const scriptSigPart2 = serializeString('/nodeStratum/');
|
||||
|
||||
const is_witness = rpcData.default_witness_commitment !== undefined;
|
||||
|
||||
const blob1 = Buffer.concat([
|
||||
coinbaseVersion,
|
||||
// transaction input
|
||||
Buffer.from(is_witness ? "0001" : "", 'hex'),
|
||||
varIntBuffer(1), // txInputsCount
|
||||
uint256BufferFromHash(""), // txInPrevOutHash
|
||||
packUInt32LE(Math.pow(2, 32) - 1), // txInPrevOutIndex
|
||||
@@ -241,26 +258,51 @@ module.exports.RtmBlockTemplate = function(rpcData, poolAddress) {
|
||||
packUInt32LE(0), // txInSequence
|
||||
// end transaction input
|
||||
// transaction output
|
||||
generateOutputTransactions(rpcData, poolAddress),
|
||||
generateTransactionOutputs(rpcData, poolAddress, is_witness),
|
||||
// end transaction ouput
|
||||
packUInt32LE(0), // txLockTime
|
||||
varIntBuffer(rpcData.coinbase_payload.length / 2),
|
||||
Buffer.from(rpcData.coinbase_payload, 'hex')
|
||||
packUInt32LE(0) // txLockTime
|
||||
]);
|
||||
|
||||
if (rpcData.coinbase_payload) {
|
||||
blob2 = Buffer.concat([
|
||||
blob2,
|
||||
varIntBuffer(rpcData.coinbase_payload.length / 2),
|
||||
Buffer.from(rpcData.coinbase_payload, 'hex')
|
||||
]);
|
||||
}
|
||||
|
||||
const prev_hash = reverseBuffer(Buffer.from(rpcData.previousblockhash, 'hex')).toString('hex');
|
||||
const version = packInt32LE(rpcData.version).toString('hex');
|
||||
const curtime = packUInt32LE(rpcData.curtime).toString('hex');
|
||||
let bits = Buffer.from(rpcData.bits, 'hex');
|
||||
let bits = Buffer.from(rpcData.bits, 'hex');
|
||||
bits.writeUInt32LE(bits.readUInt32BE());
|
||||
const txn = varIntBuffer(rpcData.transactions.length + 1);
|
||||
let txs = [];
|
||||
// skip version 1 transaction because they contain some OP_RETURN(0x6A) opcode in the beginning of
|
||||
// tx input scripts instead of size of script part so not sure how to parse them
|
||||
// just drop them for now
|
||||
// example: https://explorer.raptoreum.com/tx/1461d70fa8362b0896e2e9be6312521f2684f22c9b0f9152695f33f67d9f9d3f
|
||||
rpcData.transactions.forEach(function(tx) {
|
||||
if (tx.version != 1) {
|
||||
try {
|
||||
bitcoin.Transaction.fromBuffer(Buffer.from(tx.data, 'hex'), false, false);
|
||||
} catch(err) {
|
||||
console.error("Skip RTM tx due to parse error: " + tx.data);
|
||||
return; // skip transaction if it is not parsed OK (varint coding seems to be different for RTM)
|
||||
}
|
||||
txs.push(tx);
|
||||
} else {
|
||||
console.error("Skip RTM v1 tx: " + tx.data);
|
||||
}
|
||||
});
|
||||
const txn = varIntBuffer(txs.length + 1);
|
||||
|
||||
return {
|
||||
difficulty: parseFloat((diff1 / bignum(rpcData.target, 16).toNumber()).toFixed(9)),
|
||||
height: rpcData.height,
|
||||
prev_hash: rpcData.previousblockhash,
|
||||
blocktemplate_blob: version + rpcData.previousblockhash + Buffer.alloc(32, 0).toString('hex') + curtime + bits.toString('hex') + Buffer.alloc(4, 0).toString('hex') +
|
||||
txn.toString('hex') + blob1.toString('hex') + Buffer.alloc(extraNoncePlaceholderLength, 0xCC).toString('hex') + blob2.toString('hex') +
|
||||
Buffer.concat(rpcData.transactions.map(function(tx) { return Buffer.from(tx.data, 'hex'); })).toString('hex'),
|
||||
prev_hash: prev_hash,
|
||||
blocktemplate_blob: version + prev_hash + Buffer.alloc(32, 0).toString('hex') + curtime + bits.toString('hex') + Buffer.alloc(4, 0).toString('hex') +
|
||||
txn.toString('hex') + blob1.toString('hex') + Buffer.alloc(extraNoncePlaceholderLength, 0xCC).toString('hex') + blob2.toString('hex') +
|
||||
Buffer.concat(txs.map(function(tx) { return Buffer.from(tx.data, 'hex'); })).toString('hex'),
|
||||
reserved_offset: 80 + txn.length + blob1.length
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
// Copyright (c) 2024, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
//! @file Supporting types for Carrot (anchor, view tag, etc.).
|
||||
|
||||
#pragma once
|
||||
|
||||
//standard headers
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
//forward declarations
|
||||
|
||||
namespace carrot
|
||||
{
|
||||
|
||||
constexpr std::size_t JANUS_ANCHOR_BYTES{16};
|
||||
|
||||
/// either encodes randomness the private key of, or an HMAC of, the ephemeral pubkey
|
||||
struct janus_anchor_t final
|
||||
{
|
||||
unsigned char bytes[JANUS_ANCHOR_BYTES];
|
||||
};
|
||||
|
||||
/// carrot janus anchor XORd with a user-defined secret
|
||||
using encrypted_janus_anchor_t = janus_anchor_t;
|
||||
|
||||
/// carrot enote types
|
||||
enum class CarrotEnoteType : unsigned char
|
||||
{
|
||||
PAYMENT = 0,
|
||||
CHANGE = 1
|
||||
};
|
||||
|
||||
/// carrot encrypted amount
|
||||
constexpr std::size_t ENCRYPTED_AMOUNT_BYTES{8};
|
||||
struct encrypted_amount_t final
|
||||
{
|
||||
unsigned char bytes[ENCRYPTED_AMOUNT_BYTES];
|
||||
};
|
||||
|
||||
/// legacy payment ID
|
||||
constexpr std::size_t PAYMENT_ID_BYTES{8};
|
||||
struct payment_id_t final
|
||||
{
|
||||
unsigned char bytes[PAYMENT_ID_BYTES];
|
||||
};
|
||||
static constexpr payment_id_t null_payment_id{{0}};
|
||||
|
||||
/// legacy encrypted payment ID
|
||||
struct encrypted_payment_id_t final
|
||||
{
|
||||
unsigned char bytes[PAYMENT_ID_BYTES];
|
||||
};
|
||||
|
||||
/// carrot view tags
|
||||
constexpr std::size_t VIEW_TAG_BYTES{3};
|
||||
struct view_tag_t final
|
||||
{
|
||||
unsigned char bytes[VIEW_TAG_BYTES];
|
||||
};
|
||||
|
||||
static_assert(sizeof(view_tag_t) < 32, "uint8_t cannot index all view tag bits");
|
||||
|
||||
/// carrot input context
|
||||
constexpr std::size_t INPUT_CONTEXT_BYTES{1 + 32};
|
||||
struct input_context_t final
|
||||
{
|
||||
unsigned char bytes[INPUT_CONTEXT_BYTES];
|
||||
};
|
||||
|
||||
// SPARC encrypted return public key
|
||||
constexpr std::size_t ENCRYPTED_RETURN_PUBKEY_BYTES{32};
|
||||
struct encrypted_return_pubkey_t final
|
||||
{
|
||||
unsigned char bytes[ENCRYPTED_RETURN_PUBKEY_BYTES];
|
||||
};
|
||||
|
||||
} //namespace carrot
|
||||
@@ -26,12 +26,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <set>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <boost/mpl/vector.hpp>
|
||||
#include <boost/mpl/contains_fwd.hpp>
|
||||
#include <cstdint>
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "serialization"
|
||||
|
||||
@@ -50,279 +50,8 @@ namespace crypto {
|
||||
return &reinterpret_cast<const unsigned char &>(scalar);
|
||||
}
|
||||
|
||||
static inline void random_scalar(ec_scalar &res) {
|
||||
unsigned char tmp[64];
|
||||
generate_random_bytes(64, tmp);
|
||||
sc_reduce(tmp);
|
||||
memcpy(&res, tmp, 32);
|
||||
}
|
||||
|
||||
static inline void hash_to_scalar(const void *data, size_t length, ec_scalar &res) {
|
||||
cn_fast_hash(data, length, reinterpret_cast<hash &>(res));
|
||||
sc_reduce32(&res);
|
||||
}
|
||||
|
||||
void crypto_ops::generate_keys(public_key &pub, secret_key &sec) {
|
||||
lock_guard<mutex> lock(random_lock);
|
||||
ge_p3 point;
|
||||
random_scalar(sec);
|
||||
ge_scalarmult_base(&point, &sec);
|
||||
ge_p3_tobytes(&pub, &point);
|
||||
}
|
||||
|
||||
bool crypto_ops::check_key(const public_key &key) {
|
||||
ge_p3 point;
|
||||
return ge_frombytes_vartime(&point, &key) == 0;
|
||||
}
|
||||
|
||||
bool crypto_ops::secret_key_to_public_key(const secret_key &sec, public_key &pub) {
|
||||
ge_p3 point;
|
||||
if (sc_check(&sec) != 0) {
|
||||
return false;
|
||||
}
|
||||
ge_scalarmult_base(&point, &sec);
|
||||
ge_p3_tobytes(&pub, &point);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool crypto_ops::generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation) {
|
||||
ge_p3 point;
|
||||
ge_p2 point2;
|
||||
ge_p1p1 point3;
|
||||
assert(sc_check(&key2) == 0);
|
||||
if (ge_frombytes_vartime(&point, &key1) != 0) {
|
||||
return false;
|
||||
}
|
||||
ge_scalarmult(&point2, &key2, &point);
|
||||
ge_mul8(&point3, &point2);
|
||||
ge_p1p1_to_p2(&point2, &point3);
|
||||
ge_tobytes(&derivation, &point2);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res) {
|
||||
struct {
|
||||
key_derivation derivation;
|
||||
char output_index[(sizeof(size_t) * 8 + 6) / 7];
|
||||
} buf;
|
||||
char *end = buf.output_index;
|
||||
buf.derivation = derivation;
|
||||
tools::write_varint(end, output_index);
|
||||
assert(end <= buf.output_index + sizeof buf.output_index);
|
||||
hash_to_scalar(&buf, end - reinterpret_cast<char *>(&buf), res);
|
||||
}
|
||||
|
||||
bool crypto_ops::derive_public_key(const key_derivation &derivation, size_t output_index,
|
||||
const public_key &base, public_key &derived_key) {
|
||||
ec_scalar scalar;
|
||||
ge_p3 point1;
|
||||
ge_p3 point2;
|
||||
ge_cached point3;
|
||||
ge_p1p1 point4;
|
||||
ge_p2 point5;
|
||||
if (ge_frombytes_vartime(&point1, &base) != 0) {
|
||||
return false;
|
||||
}
|
||||
derivation_to_scalar(derivation, output_index, scalar);
|
||||
ge_scalarmult_base(&point2, &scalar);
|
||||
ge_p3_to_cached(&point3, &point2);
|
||||
ge_add(&point4, &point1, &point3);
|
||||
ge_p1p1_to_p2(&point5, &point4);
|
||||
ge_tobytes(&derived_key, &point5);
|
||||
return true;
|
||||
}
|
||||
|
||||
void crypto_ops::derive_secret_key(const key_derivation &derivation, size_t output_index,
|
||||
const secret_key &base, secret_key &derived_key) {
|
||||
ec_scalar scalar;
|
||||
assert(sc_check(&base) == 0);
|
||||
derivation_to_scalar(derivation, output_index, scalar);
|
||||
sc_add(&derived_key, &base, &scalar);
|
||||
}
|
||||
|
||||
struct s_comm {
|
||||
hash h;
|
||||
ec_point key;
|
||||
ec_point comm;
|
||||
};
|
||||
|
||||
void crypto_ops::generate_signature(const hash &prefix_hash, const public_key &pub, const secret_key &sec, signature &sig) {
|
||||
lock_guard<mutex> lock(random_lock);
|
||||
ge_p3 tmp3;
|
||||
ec_scalar k;
|
||||
s_comm buf;
|
||||
#if !defined(NDEBUG)
|
||||
{
|
||||
ge_p3 t;
|
||||
public_key t2;
|
||||
assert(sc_check(&sec) == 0);
|
||||
ge_scalarmult_base(&t, &sec);
|
||||
ge_p3_tobytes(&t2, &t);
|
||||
assert(pub == t2);
|
||||
}
|
||||
#endif
|
||||
buf.h = prefix_hash;
|
||||
buf.key = pub;
|
||||
random_scalar(k);
|
||||
ge_scalarmult_base(&tmp3, &k);
|
||||
ge_p3_tobytes(&buf.comm, &tmp3);
|
||||
hash_to_scalar(&buf, sizeof(s_comm), sig.c);
|
||||
sc_mulsub(&sig.r, &sig.c, &sec, &k);
|
||||
}
|
||||
|
||||
bool crypto_ops::check_signature(const hash &prefix_hash, const public_key &pub, const signature &sig) {
|
||||
ge_p2 tmp2;
|
||||
ge_p3 tmp3;
|
||||
ec_scalar c;
|
||||
s_comm buf;
|
||||
assert(check_key(pub));
|
||||
buf.h = prefix_hash;
|
||||
buf.key = pub;
|
||||
if (ge_frombytes_vartime(&tmp3, &pub) != 0) {
|
||||
abort();
|
||||
}
|
||||
if (sc_check(&sig.c) != 0 || sc_check(&sig.r) != 0) {
|
||||
return false;
|
||||
}
|
||||
ge_double_scalarmult_base_vartime(&tmp2, &sig.c, &tmp3, &sig.r);
|
||||
ge_tobytes(&buf.comm, &tmp2);
|
||||
hash_to_scalar(&buf, sizeof(s_comm), c);
|
||||
sc_sub(&c, &c, &sig.c);
|
||||
return sc_isnonzero(&c) == 0;
|
||||
}
|
||||
|
||||
static void hash_to_ec(const public_key &key, ge_p3 &res) {
|
||||
hash h;
|
||||
ge_p2 point;
|
||||
ge_p1p1 point2;
|
||||
cn_fast_hash(std::addressof(key), sizeof(public_key), h);
|
||||
ge_fromfe_frombytes_vartime(&point, reinterpret_cast<const unsigned char *>(&h));
|
||||
ge_mul8(&point2, &point);
|
||||
ge_p1p1_to_p3(&res, &point2);
|
||||
}
|
||||
|
||||
void crypto_ops::generate_key_image(const public_key &pub, const secret_key &sec, key_image &image) {
|
||||
ge_p3 point;
|
||||
ge_p2 point2;
|
||||
assert(sc_check(&sec) == 0);
|
||||
hash_to_ec(pub, point);
|
||||
ge_scalarmult(&point2, &sec, &point);
|
||||
ge_tobytes(&image, &point2);
|
||||
}
|
||||
|
||||
PUSH_WARNINGS
|
||||
DISABLE_VS_WARNINGS(4200)
|
||||
struct rs_comm {
|
||||
hash h;
|
||||
struct {
|
||||
ec_point a, b;
|
||||
} ab[];
|
||||
} rcs;
|
||||
POP_WARNINGS
|
||||
|
||||
static inline size_t rs_comm_size(size_t pubs_count) {
|
||||
return sizeof(rs_comm) + pubs_count * sizeof(rcs.ab[0]);
|
||||
}
|
||||
|
||||
void crypto_ops::generate_ring_signature(const hash &prefix_hash, const key_image &image,
|
||||
const public_key *const *pubs, size_t pubs_count,
|
||||
const secret_key &sec, size_t sec_index,
|
||||
signature *sig) {
|
||||
lock_guard<mutex> lock(random_lock);
|
||||
size_t i;
|
||||
ge_p3 image_unp;
|
||||
ge_dsmp image_pre;
|
||||
ec_scalar sum, k, h;
|
||||
rs_comm *const buf = reinterpret_cast<rs_comm *>(alloca(rs_comm_size(pubs_count)));
|
||||
assert(sec_index < pubs_count);
|
||||
#if !defined(NDEBUG)
|
||||
{
|
||||
ge_p3 t;
|
||||
public_key t2;
|
||||
key_image t3;
|
||||
assert(sc_check(&sec) == 0);
|
||||
ge_scalarmult_base(&t, &sec);
|
||||
ge_p3_tobytes(&t2, &t);
|
||||
assert(*pubs[sec_index] == t2);
|
||||
generate_key_image(*pubs[sec_index], sec, t3);
|
||||
assert(image == t3);
|
||||
for (i = 0; i < pubs_count; i++) {
|
||||
assert(check_key(*pubs[i]));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (ge_frombytes_vartime(&image_unp, &image) != 0) {
|
||||
abort();
|
||||
}
|
||||
ge_dsm_precomp(image_pre, &image_unp);
|
||||
sc_0(&sum);
|
||||
buf->h = prefix_hash;
|
||||
for (i = 0; i < pubs_count; i++) {
|
||||
ge_p2 tmp2;
|
||||
ge_p3 tmp3;
|
||||
if (i == sec_index) {
|
||||
random_scalar(k);
|
||||
ge_scalarmult_base(&tmp3, &k);
|
||||
ge_p3_tobytes(&buf->ab[i].a, &tmp3);
|
||||
hash_to_ec(*pubs[i], tmp3);
|
||||
ge_scalarmult(&tmp2, &k, &tmp3);
|
||||
ge_tobytes(&buf->ab[i].b, &tmp2);
|
||||
} else {
|
||||
random_scalar(sig[i].c);
|
||||
random_scalar(sig[i].r);
|
||||
if (ge_frombytes_vartime(&tmp3, &*pubs[i]) != 0) {
|
||||
abort();
|
||||
}
|
||||
ge_double_scalarmult_base_vartime(&tmp2, &sig[i].c, &tmp3, &sig[i].r);
|
||||
ge_tobytes(&buf->ab[i].a, &tmp2);
|
||||
hash_to_ec(*pubs[i], tmp3);
|
||||
ge_double_scalarmult_precomp_vartime(&tmp2, &sig[i].r, &tmp3, &sig[i].c, image_pre);
|
||||
ge_tobytes(&buf->ab[i].b, &tmp2);
|
||||
sc_add(&sum, &sum, &sig[i].c);
|
||||
}
|
||||
}
|
||||
hash_to_scalar(buf, rs_comm_size(pubs_count), h);
|
||||
sc_sub(&sig[sec_index].c, &h, &sum);
|
||||
sc_mulsub(&sig[sec_index].r, &sig[sec_index].c, &sec, &k);
|
||||
}
|
||||
|
||||
bool crypto_ops::check_ring_signature(const hash &prefix_hash, const key_image &image,
|
||||
const public_key *const *pubs, size_t pubs_count,
|
||||
const signature *sig) {
|
||||
size_t i;
|
||||
ge_p3 image_unp;
|
||||
ge_dsmp image_pre;
|
||||
ec_scalar sum, h;
|
||||
rs_comm *const buf = reinterpret_cast<rs_comm *>(alloca(rs_comm_size(pubs_count)));
|
||||
#if !defined(NDEBUG)
|
||||
for (i = 0; i < pubs_count; i++) {
|
||||
assert(check_key(*pubs[i]));
|
||||
}
|
||||
#endif
|
||||
if (ge_frombytes_vartime(&image_unp, &image) != 0) {
|
||||
return false;
|
||||
}
|
||||
ge_dsm_precomp(image_pre, &image_unp);
|
||||
sc_0(&sum);
|
||||
buf->h = prefix_hash;
|
||||
for (i = 0; i < pubs_count; i++) {
|
||||
ge_p2 tmp2;
|
||||
ge_p3 tmp3;
|
||||
if (sc_check(&sig[i].c) != 0 || sc_check(&sig[i].r) != 0) {
|
||||
return false;
|
||||
}
|
||||
if (ge_frombytes_vartime(&tmp3, &*pubs[i]) != 0) {
|
||||
abort();
|
||||
}
|
||||
ge_double_scalarmult_base_vartime(&tmp2, &sig[i].c, &tmp3, &sig[i].r);
|
||||
ge_tobytes(&buf->ab[i].a, &tmp2);
|
||||
hash_to_ec(*pubs[i], tmp3);
|
||||
ge_double_scalarmult_precomp_vartime(&tmp2, &sig[i].r, &tmp3, &sig[i].c, image_pre);
|
||||
ge_tobytes(&buf->ab[i].b, &tmp2);
|
||||
sc_add(&sum, &sum, &sig[i].c);
|
||||
}
|
||||
hash_to_scalar(buf, rs_comm_size(pubs_count), h);
|
||||
sc_sub(&h, &h, &sum);
|
||||
return sc_isnonzero(&h) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-99
@@ -49,12 +49,16 @@ namespace crypto {
|
||||
ec_scalar c, r;
|
||||
friend class crypto_ops;
|
||||
};
|
||||
|
||||
POD_CLASS view_tag {
|
||||
char data;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
static_assert(sizeof(ec_point) == 32 && sizeof(ec_scalar) == 32 &&
|
||||
sizeof(public_key) == 32 && sizeof(secret_key) == 32 &&
|
||||
sizeof(key_derivation) == 32 && sizeof(key_image) == 32 &&
|
||||
sizeof(signature) == 64, "Invalid structure size");
|
||||
sizeof(signature) == 64 && sizeof(view_tag) == 1, "Invalid structure size");
|
||||
|
||||
class crypto_ops {
|
||||
crypto_ops();
|
||||
@@ -62,32 +66,8 @@ namespace crypto {
|
||||
void operator=(const crypto_ops &);
|
||||
~crypto_ops();
|
||||
|
||||
static void generate_keys(public_key &, secret_key &);
|
||||
friend void generate_keys(public_key &, secret_key &);
|
||||
static bool check_key(const public_key &);
|
||||
friend bool check_key(const public_key &);
|
||||
static bool secret_key_to_public_key(const secret_key &, public_key &);
|
||||
friend bool secret_key_to_public_key(const secret_key &, public_key &);
|
||||
static bool generate_key_derivation(const public_key &, const secret_key &, key_derivation &);
|
||||
friend bool generate_key_derivation(const public_key &, const secret_key &, key_derivation &);
|
||||
static bool derive_public_key(const key_derivation &, std::size_t, const public_key &, public_key &);
|
||||
friend bool derive_public_key(const key_derivation &, std::size_t, const public_key &, public_key &);
|
||||
static void derive_secret_key(const key_derivation &, std::size_t, const secret_key &, secret_key &);
|
||||
friend void derive_secret_key(const key_derivation &, std::size_t, const secret_key &, secret_key &);
|
||||
static void generate_signature(const hash &, const public_key &, const secret_key &, signature &);
|
||||
friend void generate_signature(const hash &, const public_key &, const secret_key &, signature &);
|
||||
static bool check_signature(const hash &, const public_key &, const signature &);
|
||||
friend bool check_signature(const hash &, const public_key &, const signature &);
|
||||
static void generate_key_image(const public_key &, const secret_key &, key_image &);
|
||||
friend void generate_key_image(const public_key &, const secret_key &, key_image &);
|
||||
static void generate_ring_signature(const hash &, const key_image &,
|
||||
const public_key *const *, std::size_t, const secret_key &, std::size_t, signature *);
|
||||
friend void generate_ring_signature(const hash &, const key_image &,
|
||||
const public_key *const *, std::size_t, const secret_key &, std::size_t, signature *);
|
||||
static bool check_ring_signature(const hash &, const key_image &,
|
||||
const public_key *const *, std::size_t, const signature *);
|
||||
friend bool check_ring_signature(const hash &, const key_image &,
|
||||
const public_key *const *, std::size_t, const signature *);
|
||||
};
|
||||
|
||||
/* Generate a value filled with random bytes.
|
||||
@@ -100,87 +80,14 @@ namespace crypto {
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Generate a new key pair
|
||||
*/
|
||||
inline void generate_keys(public_key &pub, secret_key &sec) {
|
||||
crypto_ops::generate_keys(pub, sec);
|
||||
}
|
||||
|
||||
/* Check a public key. Returns true if it is valid, false otherwise.
|
||||
*/
|
||||
inline bool check_key(const public_key &key) {
|
||||
return crypto_ops::check_key(key);
|
||||
}
|
||||
|
||||
/* Checks a private key and computes the corresponding public key.
|
||||
*/
|
||||
inline bool secret_key_to_public_key(const secret_key &sec, public_key &pub) {
|
||||
return crypto_ops::secret_key_to_public_key(sec, pub);
|
||||
}
|
||||
|
||||
/* To generate an ephemeral key used to send money to:
|
||||
* * The sender generates a new key pair, which becomes the transaction key. The public transaction key is included in "extra" field.
|
||||
* * Both the sender and the receiver generate key derivation from the transaction key, the receivers' "view" key and the output index.
|
||||
* * The sender uses key derivation and the receivers' "spend" key to derive an ephemeral public key.
|
||||
* * The receiver can either derive the public key (to check that the transaction is addressed to him) or the private key (to spend the money).
|
||||
*/
|
||||
inline bool generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation) {
|
||||
return crypto_ops::generate_key_derivation(key1, key2, derivation);
|
||||
}
|
||||
inline bool derive_public_key(const key_derivation &derivation, std::size_t output_index,
|
||||
const public_key &base, public_key &derived_key) {
|
||||
return crypto_ops::derive_public_key(derivation, output_index, base, derived_key);
|
||||
}
|
||||
inline void derive_secret_key(const key_derivation &derivation, std::size_t output_index,
|
||||
const secret_key &base, secret_key &derived_key) {
|
||||
crypto_ops::derive_secret_key(derivation, output_index, base, derived_key);
|
||||
}
|
||||
|
||||
/* Generation and checking of a standard signature.
|
||||
*/
|
||||
inline void generate_signature(const hash &prefix_hash, const public_key &pub, const secret_key &sec, signature &sig) {
|
||||
crypto_ops::generate_signature(prefix_hash, pub, sec, sig);
|
||||
}
|
||||
inline bool check_signature(const hash &prefix_hash, const public_key &pub, const signature &sig) {
|
||||
return crypto_ops::check_signature(prefix_hash, pub, sig);
|
||||
}
|
||||
|
||||
/* To send money to a key:
|
||||
* * The sender generates an ephemeral key and includes it in transaction output.
|
||||
* * To spend the money, the receiver generates a key image from it.
|
||||
* * Then he selects a bunch of outputs, including the one he spends, and uses them to generate a ring signature.
|
||||
* To check the signature, it is necessary to collect all the keys that were used to generate it. To detect double spends, it is necessary to check that each key image is used at most once.
|
||||
*/
|
||||
inline void generate_key_image(const public_key &pub, const secret_key &sec, key_image &image) {
|
||||
crypto_ops::generate_key_image(pub, sec, image);
|
||||
}
|
||||
inline void generate_ring_signature(const hash &prefix_hash, const key_image &image,
|
||||
const public_key *const *pubs, std::size_t pubs_count,
|
||||
const secret_key &sec, std::size_t sec_index,
|
||||
signature *sig) {
|
||||
crypto_ops::generate_ring_signature(prefix_hash, image, pubs, pubs_count, sec, sec_index, sig);
|
||||
}
|
||||
inline bool check_ring_signature(const hash &prefix_hash, const key_image &image,
|
||||
const public_key *const *pubs, std::size_t pubs_count,
|
||||
const signature *sig) {
|
||||
return crypto_ops::check_ring_signature(prefix_hash, image, pubs, pubs_count, sig);
|
||||
}
|
||||
|
||||
/* Variants with vector<const public_key *> parameters.
|
||||
*/
|
||||
inline void generate_ring_signature(const hash &prefix_hash, const key_image &image,
|
||||
const std::vector<const public_key *> &pubs,
|
||||
const secret_key &sec, std::size_t sec_index,
|
||||
signature *sig) {
|
||||
generate_ring_signature(prefix_hash, image, pubs.data(), pubs.size(), sec, sec_index, sig);
|
||||
}
|
||||
inline bool check_ring_signature(const hash &prefix_hash, const key_image &image,
|
||||
const std::vector<const public_key *> &pubs,
|
||||
const signature *sig) {
|
||||
return check_ring_signature(prefix_hash, image, pubs.data(), pubs.size(), sig);
|
||||
}
|
||||
}
|
||||
|
||||
CRYPTO_MAKE_COMPARABLE(public_key)
|
||||
CRYPTO_MAKE_HASHABLE(key_image)
|
||||
CRYPTO_MAKE_COMPARABLE(signature)
|
||||
CRYPTO_MAKE_COMPARABLE(view_tag)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cryptonote_core/cryptonote_basic.h"
|
||||
#include "cryptonote_basic.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "serialization/keyvalue_serialization.h"
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace cryptonote_arq
|
||||
{
|
||||
enum class txversion : uint16_t
|
||||
{
|
||||
v0 = 0,
|
||||
v1,
|
||||
v2,
|
||||
v3,
|
||||
|
||||
_count
|
||||
};
|
||||
|
||||
enum class txtype : uint16_t
|
||||
{
|
||||
standard = 0,
|
||||
state_change,
|
||||
key_image_unlock,
|
||||
stake,
|
||||
|
||||
_count
|
||||
};
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+29
-276
@@ -56,85 +56,6 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool generate_key_image_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki)
|
||||
{
|
||||
crypto::key_derivation recv_derivation = AUTO_VAL_INIT(recv_derivation);
|
||||
bool r = crypto::generate_key_derivation(tx_public_key, ack.m_view_secret_key, recv_derivation);
|
||||
CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to generate_key_derivation(" << tx_public_key << ", " << ack.m_view_secret_key << ")");
|
||||
|
||||
r = crypto::derive_public_key(recv_derivation, real_output_index, ack.m_account_address.m_spend_public_key, in_ephemeral.pub);
|
||||
CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to derive_public_key(" << recv_derivation << ", " << real_output_index << ", " << ack.m_account_address.m_spend_public_key << ")");
|
||||
|
||||
crypto::derive_secret_key(recv_derivation, real_output_index, ack.m_spend_secret_key, in_ephemeral.sec);
|
||||
|
||||
crypto::generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
uint64_t power_integral(uint64_t a, uint64_t b)
|
||||
{
|
||||
if(b == 0)
|
||||
return 1;
|
||||
uint64_t total = a;
|
||||
for(uint64_t i = 1; i != b; i++)
|
||||
total *= a;
|
||||
return total;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_tx_fee(const transaction& tx, uint64_t & fee)
|
||||
{
|
||||
uint64_t amount_in = 0;
|
||||
uint64_t amount_out = 0;
|
||||
if (tx.blob_type == BLOB_TYPE_CRYPTONOTE_XHV)
|
||||
{
|
||||
// This is the correct way to get the fee for Haven, because outs may be in different currencies to ins
|
||||
switch (tx.version) {
|
||||
case 5:
|
||||
fee = tx.rct_signatures.txnFee + tx.rct_signatures.txnOffshoreFee;
|
||||
break;
|
||||
case 4:
|
||||
case 3:
|
||||
if (tx.vin[0].type() == typeid(txin_to_key)) {
|
||||
fee = tx.rct_signatures.txnFee + tx.rct_signatures.txnOffshoreFee;
|
||||
} else if (tx.vin[0].type() == typeid(txin_offshore)) {
|
||||
fee = tx.rct_signatures.txnFee_usd + tx.rct_signatures.txnOffshoreFee_usd;
|
||||
} else if (tx.vin[0].type() == typeid(txin_onshore)) {
|
||||
fee = tx.rct_signatures.txnFee_usd + tx.rct_signatures.txnOffshoreFee_usd;
|
||||
} else if (tx.vin[0].type() == typeid(txin_xasset)) {
|
||||
fee = tx.rct_signatures.txnFee_xasset + tx.rct_signatures.txnOffshoreFee_xasset;
|
||||
} else {
|
||||
CHECK_AND_ASSERT_MES(false, false, "unexpected type id in transaction");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
case 1:
|
||||
fee = tx.rct_signatures.txnFee;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
BOOST_FOREACH(auto& in, tx.vin)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key), 0, "unexpected type id in transaction");
|
||||
amount_in += boost::get<txin_to_key>(in).amount;
|
||||
}
|
||||
BOOST_FOREACH(auto& o, tx.vout)
|
||||
amount_out += o.amount;
|
||||
|
||||
CHECK_AND_ASSERT_MES(amount_in >= amount_out, false, "transaction spend (" <<amount_in << ") more than it has (" << amount_out << ")");
|
||||
fee = amount_in - amount_out;
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
uint64_t get_tx_fee(const transaction& tx)
|
||||
{
|
||||
uint64_t r = 0;
|
||||
if(!get_tx_fee(tx, r))
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool parse_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<tx_extra_field>& tx_extra_fields)
|
||||
{
|
||||
tx_extra_fields.clear();
|
||||
@@ -242,155 +163,6 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_inputs_money_amount(const transaction& tx, uint64_t& money)
|
||||
{
|
||||
money = 0;
|
||||
BOOST_FOREACH(const auto& in, tx.vin)
|
||||
{
|
||||
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false);
|
||||
money += tokey_in.amount;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
uint64_t get_block_height(const block& b)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.vin.size() == 1, 0, "wrong miner tx in block: " << get_block_hash(b) << ", b.miner_tx.vin.size() != 1");
|
||||
CHECKED_GET_SPECIFIC_VARIANT(b.miner_tx.vin[0], const txin_gen, coinbase_in, 0);
|
||||
return coinbase_in.height;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool check_inputs_types_supported(const transaction& tx)
|
||||
{
|
||||
BOOST_FOREACH(const auto& in, tx.vin)
|
||||
{
|
||||
if (tx.blob_type != BLOB_TYPE_CRYPTONOTE_XHV) {
|
||||
CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key), false, "wrong variant type: "
|
||||
<< in.type().name() << ", expected " << typeid(txin_to_key).name()
|
||||
<< ", in transaction id=" << get_transaction_hash(tx));
|
||||
} else {
|
||||
CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key) || in.type() == typeid(txin_offshore) || in.type() == typeid(txin_onshore) || in.type() == typeid(txin_xasset), false, "wrong variant type: "
|
||||
<< in.type().name() << ", expected " << typeid(txin_to_key).name()
|
||||
<< "or " << typeid(txin_offshore).name()
|
||||
<< "or " << typeid(txin_onshore).name()
|
||||
<< "or " << typeid(txin_xasset).name()
|
||||
<< ", in transaction id=" << get_transaction_hash(tx));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool check_outs_valid(const transaction& tx)
|
||||
{
|
||||
BOOST_FOREACH(const tx_out& out, tx.vout)
|
||||
{
|
||||
if (tx.blob_type != BLOB_TYPE_CRYPTONOTE_XHV) {
|
||||
CHECK_AND_ASSERT_MES(out.target.type() == typeid(txout_to_key), false, "wrong variant type: "
|
||||
<< out.target.type().name() << ", expected " << typeid(txout_to_key).name()
|
||||
<< ", in transaction id=" << get_transaction_hash(tx));
|
||||
} else {
|
||||
CHECK_AND_ASSERT_MES(out.target.type() == typeid(txout_to_key) ||
|
||||
out.target.type() == typeid(txout_offshore) ||
|
||||
out.target.type() == typeid(txout_xasset), false, "wrong variant type: "
|
||||
<< out.target.type().name() << ", expected " << typeid(txout_to_key).name()
|
||||
<< "or " << typeid(txout_offshore).name()
|
||||
<< "or " << typeid(txout_xasset).name()
|
||||
<< ", in transaction id=" << get_transaction_hash(tx));
|
||||
}
|
||||
|
||||
if (tx.version == 1)
|
||||
{
|
||||
CHECK_AND_NO_ASSERT_MES(0 < out.amount, false, "zero amount ouput in transaction id=" << get_transaction_hash(tx));
|
||||
}
|
||||
|
||||
if (tx.blob_type != BLOB_TYPE_CRYPTONOTE_XHV) {
|
||||
if(!check_key(boost::get<txout_to_key>(out.target).key))
|
||||
return false;
|
||||
} else {
|
||||
if(!check_key(out.target.type() == typeid(txout_to_key) ? boost::get<txout_to_key>(out.target).key :
|
||||
out.target.type() == typeid(txout_offshore) ? boost::get<txout_offshore>(out.target).key :
|
||||
boost::get<txout_xasset>(out.target).key))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool check_money_overflow(const transaction& tx)
|
||||
{
|
||||
return check_inputs_overflow(tx) && check_outs_overflow(tx);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool check_inputs_overflow(const transaction& tx)
|
||||
{
|
||||
uint64_t money = 0;
|
||||
BOOST_FOREACH(const auto& in, tx.vin)
|
||||
{
|
||||
if (tx.blob_type == BLOB_TYPE_CRYPTONOTE_XHV && tx.vin[0].type() == typeid(txin_xasset)) {
|
||||
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_xasset, tokey_in, false);
|
||||
if(money > tokey_in.amount + money)
|
||||
return false;
|
||||
money += tokey_in.amount;
|
||||
} else if (tx.blob_type == BLOB_TYPE_CRYPTONOTE_XHV && tx.vin[0].type() == typeid(txin_offshore)) {
|
||||
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_offshore, tokey_in, false);
|
||||
if(money > tokey_in.amount + money)
|
||||
return false;
|
||||
money += tokey_in.amount;
|
||||
} else if (tx.blob_type == BLOB_TYPE_CRYPTONOTE_XHV && tx.vin[0].type() == typeid(txin_onshore)) {
|
||||
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_onshore, tokey_in, false);
|
||||
if(money > tokey_in.amount + money)
|
||||
return false;
|
||||
money += tokey_in.amount;
|
||||
} else {
|
||||
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false);
|
||||
if(money > tokey_in.amount + money)
|
||||
return false;
|
||||
money += tokey_in.amount;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool check_outs_overflow(const transaction& tx)
|
||||
{
|
||||
uint64_t money = 0;
|
||||
BOOST_FOREACH(const auto& o, tx.vout)
|
||||
{
|
||||
if(money > o.amount + money)
|
||||
return false;
|
||||
money += o.amount;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
//---------------------------------------------------------------
|
||||
uint64_t get_outs_money_amount(const transaction& tx)
|
||||
{
|
||||
uint64_t outputs_amount = 0;
|
||||
BOOST_FOREACH(const auto& o, tx.vout)
|
||||
outputs_amount += o.amount;
|
||||
return outputs_amount;
|
||||
}
|
||||
*/
|
||||
//---------------------------------------------------------------
|
||||
std::map<std::string, uint64_t> get_outs_money_amount(const transaction& tx)
|
||||
{
|
||||
std::map<std::string, uint64_t> outputs_amount;
|
||||
for(const auto& o: tx.vout) {
|
||||
std::string asset_type;
|
||||
if (o.target.type() == typeid(txout_offshore)) {
|
||||
asset_type = "XUSD";
|
||||
} else if (o.target.type() == typeid(txout_xasset)) {;
|
||||
asset_type = boost::get<txout_xasset>(o.target).asset_type;
|
||||
} else {
|
||||
// this close covers miner tx and normal XHV ouputs.
|
||||
asset_type = "XHV";
|
||||
}
|
||||
outputs_amount[asset_type] += o.amount;
|
||||
}
|
||||
return outputs_amount;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
std::string short_hash_str(const crypto::hash& h)
|
||||
{
|
||||
std::string res = string_tools::pod_to_hex(h);
|
||||
@@ -400,40 +172,6 @@ namespace cryptonote
|
||||
return res;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, size_t output_index)
|
||||
{
|
||||
crypto::key_derivation derivation;
|
||||
generate_key_derivation(tx_pub_key, acc.m_view_secret_key, derivation);
|
||||
crypto::public_key pk;
|
||||
derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk);
|
||||
return pk == out_key.key;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered)
|
||||
{
|
||||
crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx);
|
||||
if(null_pkey == tx_pub_key)
|
||||
return false;
|
||||
return lookup_acc_outs(acc, tx, tx_pub_key, outs, money_transfered);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<size_t>& outs, uint64_t& money_transfered)
|
||||
{
|
||||
money_transfered = 0;
|
||||
size_t i = 0;
|
||||
BOOST_FOREACH(const tx_out& o, tx.vout)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key), false, "wrong type id in transaction out" );
|
||||
if(is_out_to_acc(acc, boost::get<txout_to_key>(o.target), tx_pub_key, i))
|
||||
{
|
||||
outs.push_back(i);
|
||||
money_transfered += o.amount;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
void get_blob_hash(const blobdata& blob, crypto::hash& res)
|
||||
{
|
||||
cn_fast_hash(blob.data(), blob.size(), res);
|
||||
@@ -482,8 +220,8 @@ namespace cryptonote
|
||||
{
|
||||
std::stringstream ss;
|
||||
binary_archive<true> ba(ss);
|
||||
const size_t inputs = t.vin.size();
|
||||
const size_t outputs = t.vout.size();
|
||||
const size_t inputs = t.blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM ? t.vin_salvium.size() : (t.blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR ? t.vin_zephyr.size() : t.vin.size());
|
||||
const size_t outputs = t.blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM ? t.vout_salvium.size() : (t.blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR ? t.vout_zephyr.size() : (t.blob_type != BLOB_TYPE_CRYPTONOTE_XHV ? t.vout.size() : t.vout_xhv.size()));
|
||||
bool r = tt.rct_signatures.serialize_rctsig_base(ba, inputs, outputs);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to serialize rct signatures base");
|
||||
cryptonote::get_blob_hash(ss.str(), hashes[1]);
|
||||
@@ -498,18 +236,23 @@ namespace cryptonote
|
||||
{
|
||||
std::stringstream ss;
|
||||
binary_archive<true> ba(ss);
|
||||
const size_t inputs = t.vin.size();
|
||||
const size_t outputs = t.vout.size();
|
||||
const size_t inputs = t.blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM ? t.vin_salvium.size() : (t.blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR ? t.vin_zephyr.size() : t.vin.size());
|
||||
const size_t outputs = t.blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM ? t.vout_salvium.size() : (t.blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR ? t.vout_zephyr.size() : (t.blob_type != BLOB_TYPE_CRYPTONOTE_XHV ? t.vout.size() : t.vout_xhv.size()));
|
||||
size_t mixin;
|
||||
if (t.blob_type != BLOB_TYPE_CRYPTONOTE_XHV) {
|
||||
mixin = t.vin.empty() ? 0 : t.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(t.vin[0]).key_offsets.size() - 1 : 0;
|
||||
} else {
|
||||
if (t.blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM) {
|
||||
mixin = t.vin_salvium.empty() ? 0 : t.vin_salvium[0].type() == typeid(txin_salvium_key) ? boost::get<txin_salvium_key>(t.vin_salvium[0]).key_offsets.size() - 1 : 0;
|
||||
} else if (t.blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR) {
|
||||
mixin = t.vin_zephyr.empty() ? 0 : t.vin_zephyr[0].type() == typeid(txin_zephyr_key) ? boost::get<txin_zephyr_key>(t.vin_zephyr[0]).key_offsets.size() - 1 : 0;
|
||||
} else if (t.blob_type == BLOB_TYPE_CRYPTONOTE_XHV) {
|
||||
mixin = t.vin.empty() ? 0 :
|
||||
t.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(t.vin[0]).key_offsets.size() - 1 :
|
||||
t.vin[0].type() == typeid(txin_offshore) ? boost::get<txin_offshore>(t.vin[0]).key_offsets.size() - 1 :
|
||||
t.vin[0].type() == typeid(txin_onshore) ? boost::get<txin_onshore>(t.vin[0]).key_offsets.size() - 1 :
|
||||
t.vin[0].type() == typeid(txin_xasset) ? boost::get<txin_xasset>(t.vin[0]).key_offsets.size() - 1 :
|
||||
0;
|
||||
t.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(t.vin[0]).key_offsets.size() - 1 :
|
||||
t.vin[0].type() == typeid(txin_offshore) ? boost::get<txin_offshore>(t.vin[0]).key_offsets.size() - 1 :
|
||||
t.vin[0].type() == typeid(txin_onshore) ? boost::get<txin_onshore>(t.vin[0]).key_offsets.size() - 1 :
|
||||
t.vin[0].type() == typeid(txin_xasset) ? boost::get<txin_xasset>(t.vin[0]).key_offsets.size() - 1 :
|
||||
t.vin[0].type() == typeid(txin_haven_key) ? boost::get<txin_haven_key>(t.vin[0]).key_offsets.size() - 1 :
|
||||
0;
|
||||
} else {
|
||||
mixin = t.vin.empty() ? 0 : t.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(t.vin[0]).key_offsets.size() - 1 : 0;
|
||||
}
|
||||
bool r = tt.rct_signatures.p.serialize_rctsig_prunable(ba, t.rct_signatures.type, inputs, outputs, mixin);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to serialize rct signatures prunable");
|
||||
@@ -544,7 +287,11 @@ namespace cryptonote
|
||||
}
|
||||
crypto::hash tree_root_hash = get_tx_tree_hash(b);
|
||||
blob.append(reinterpret_cast<const char*>(&tree_root_hash), sizeof(tree_root_hash));
|
||||
blob.append(tools::get_varint_data(b.tx_hashes.size()+1));
|
||||
if (b.blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM) {
|
||||
blob.append(tools::get_varint_data(b.tx_hashes.size() + (b.major_version >= HF_VERSION_ENABLE_N_OUTS ? 2 : 1)));
|
||||
} else {
|
||||
blob.append(tools::get_varint_data(b.tx_hashes.size()+1));
|
||||
}
|
||||
if (b.blob_type == BLOB_TYPE_CRYPTONOTE3) {
|
||||
blob.append(reinterpret_cast<const char*>(&b.uncle), sizeof(b.uncle));
|
||||
}
|
||||
@@ -630,7 +377,7 @@ namespace cryptonote
|
||||
ss << b_blob;
|
||||
binary_archive<false> ba(ss);
|
||||
bool r = ::serialization::serialize(ba, b);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to parse block from blob");
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to parse block from blob 1");
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
@@ -672,6 +419,12 @@ namespace cryptonote
|
||||
crypto::hash h = null_hash;
|
||||
size_t bl_sz = 0;
|
||||
get_transaction_hash(b.miner_tx, h, bl_sz);
|
||||
if (b.blob_type == BLOB_TYPE_CRYPTONOTE_SALVIUM) {
|
||||
txs_ids.push_back(h);
|
||||
h = null_hash;
|
||||
bl_sz = 0;
|
||||
get_transaction_hash(b.protocol_tx, h, bl_sz);
|
||||
}
|
||||
txs_ids.push_back(h);
|
||||
BOOST_FOREACH(auto& th, b.tx_hashes)
|
||||
txs_ids.push_back(th);
|
||||
+2
-25
@@ -4,8 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
|
||||
#include "cryptonote_core/cryptonote_basic_impl.h"
|
||||
#include "cryptonote_core/difficulty.h"
|
||||
#include "cryptonote_basic_impl.h"
|
||||
#include "difficulty.h"
|
||||
#include "account.h"
|
||||
#include "include_base_utils.h"
|
||||
#include "crypto/crypto.h"
|
||||
@@ -63,12 +63,6 @@ namespace cryptonote
|
||||
bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id);
|
||||
bool append_mm_tag_to_extra(std::vector<uint8_t>& tx_extra, const tx_extra_merge_mining_tag& mm_tag);
|
||||
bool get_mm_tag_from_extra(const std::vector<uint8_t>& tx_extra, tx_extra_merge_mining_tag& mm_tag);
|
||||
bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, size_t output_index);
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<size_t>& outs, uint64_t& money_transfered);
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered);
|
||||
bool get_tx_fee(const transaction& tx, uint64_t & fee);
|
||||
uint64_t get_tx_fee(const transaction& tx);
|
||||
bool generate_key_image_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki);
|
||||
void get_blob_hash(const blobdata& blob, crypto::hash& res);
|
||||
crypto::hash get_blob_hash(const blobdata& blob);
|
||||
std::string short_hash_str(const crypto::hash& h);
|
||||
@@ -84,16 +78,9 @@ namespace cryptonote
|
||||
bool get_block_header_hash(const block& b, crypto::hash& res);
|
||||
bool get_bytecoin_block_longhash(const block& blk, crypto::hash& res);
|
||||
bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b);
|
||||
bool get_inputs_money_amount(const transaction& tx, uint64_t& money);
|
||||
//uint64_t get_outs_money_amount(const transaction& tx);
|
||||
std::map<std::string, uint64_t> get_outs_money_amount(const transaction& tx);
|
||||
bool check_inputs_types_supported(const transaction& tx);
|
||||
bool check_outs_valid(const transaction& tx);
|
||||
|
||||
bool check_money_overflow(const transaction& tx);
|
||||
bool check_outs_overflow(const transaction& tx);
|
||||
bool check_inputs_overflow(const transaction& tx);
|
||||
uint64_t get_block_height(const block& b);
|
||||
std::vector<uint64_t> relative_output_offsets_to_absolute(const std::vector<uint64_t>& off);
|
||||
std::vector<uint64_t> absolute_output_offsets_to_relative(const std::vector<uint64_t>& off);
|
||||
//---------------------------------------------------------------
|
||||
@@ -138,16 +125,6 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template <typename T>
|
||||
std::string obj_to_json_str(T& obj)
|
||||
{
|
||||
std::stringstream ss;
|
||||
json_archive<true> ar(ss, true);
|
||||
bool r = ::serialization::serialize(ar, obj);
|
||||
CHECK_AND_ASSERT_MES(r, "", "obj_to_json_str failed: serialization::serialize returned false");
|
||||
return ss.str();
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
// 62387455827 -> 455827 + 7000000 + 80000000 + 300000000 + 2000000000 + 60000000000, where 455827 <= dust_threshold
|
||||
template<typename chunk_handler_t, typename dust_handler_t>
|
||||
void decompose_amount_into_digits(uint64_t amount, uint64_t dust_threshold, const chunk_handler_t& chunk_handler, const dust_handler_t& dust_handler)
|
||||
@@ -1,21 +1,21 @@
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
@@ -25,35 +25,48 @@
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#pragma once
|
||||
|
||||
#define TX_EXTRA_PADDING_MAX_COUNT 255
|
||||
#define TX_EXTRA_NONCE_MAX_COUNT 255
|
||||
#define TX_EXTRA_OFFSHORE_MAX_COUNT 255
|
||||
#define TX_EXTRA_MEMO_MAX_COUNT 255
|
||||
#define TX_EXTRA_PADDING_MAX_COUNT 255
|
||||
#define TX_EXTRA_NONCE_MAX_COUNT 255
|
||||
#define TX_EXTRA_OFFSHORE_MAX_COUNT 255
|
||||
#define TX_EXTRA_MEMO_MAX_COUNT 255
|
||||
|
||||
#define TX_EXTRA_TAG_PADDING 0x00
|
||||
#define TX_EXTRA_TAG_PUBKEY 0x01
|
||||
#define TX_EXTRA_NONCE 0x02
|
||||
#define TX_EXTRA_MERGE_MINING_TAG 0x03
|
||||
#define TX_EXTRA_TAG_ADDITIONAL_PUBKEYS 0x04
|
||||
#define TX_EXTRA_TAG_OFFSHORE 0x17
|
||||
#define TX_EXTRA_TAG_MEMO 0x18
|
||||
#define TX_EXTRA_TAG_SERVICE_NODE_REGISTER 0x70
|
||||
#define TX_EXTRA_TAG_SERVICE_NODE_DEREGISTER 0x71
|
||||
#define TX_EXTRA_TAG_SERVICE_NODE_WINNER 0x72
|
||||
#define TX_EXTRA_TAG_SERVICE_NODE_CONTRIBUTOR 0x73
|
||||
#define TX_EXTRA_TAG_SERVICE_NODE_PUBKEY 0x74
|
||||
#define TX_EXTRA_TAG_TX_SECRET_KEY 0x75
|
||||
#define TX_EXTRA_TAG_TX_KEY_IMAGE_PROOFS 0x76
|
||||
#define TX_EXTRA_TAG_TX_KEY_IMAGE_UNLOCK 0x77
|
||||
#define TX_EXTRA_MYSTERIOUS_MINERGATE_TAG 0xDE
|
||||
#define TX_EXTRA_TAG_PADDING 0x00
|
||||
#define TX_EXTRA_TAG_PUBKEY 0x01
|
||||
#define TX_EXTRA_NONCE 0x02
|
||||
#define TX_EXTRA_MERGE_MINING_TAG 0x03
|
||||
#define TX_EXTRA_TAG_ADDITIONAL_PUBKEYS 0x04
|
||||
#define TX_EXTRA_TAG_OFFSHORE 0x17
|
||||
#define TX_EXTRA_TAG_MEMO 0x18
|
||||
#define TX_EXTRA_TAG_SERVICE_NODE_REGISTER 0x70
|
||||
#define TX_EXTRA_TAG_SERVICE_NODE_STATE_CHANGE 0x71
|
||||
#define TX_EXTRA_TAG_SERVICE_NODE_WINNER 0x72
|
||||
#define TX_EXTRA_TAG_SERVICE_NODE_CONTRIBUTOR 0x73
|
||||
#define TX_EXTRA_TAG_SERVICE_NODE_PUBKEY 0x74
|
||||
#define TX_EXTRA_TAG_TX_SECRET_KEY 0x75
|
||||
#define TX_EXTRA_TAG_TX_KEY_IMAGE_PROOFS 0x76
|
||||
#define TX_EXTRA_TAG_TX_KEY_IMAGE_UNLOCK 0x77
|
||||
#define TX_EXTRA_TAG_SERVICE_NODE_DEREGISTER 0x78
|
||||
#define TX_EXTRA_MYSTERIOUS_MINERGATE_TAG 0xDE
|
||||
|
||||
#define TX_EXTRA_NONCE_PAYMENT_ID 0x00
|
||||
#define TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID 0x01
|
||||
#define TX_EXTRA_NONCE_PAYMENT_ID 0x00
|
||||
#define TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID 0x01
|
||||
|
||||
namespace service_nodes
|
||||
{
|
||||
enum class new_state : uint16_t
|
||||
{
|
||||
deregister = 0,
|
||||
decommission,
|
||||
recommission,
|
||||
ip_change_penalty,
|
||||
_count,
|
||||
};
|
||||
};
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
@@ -208,7 +221,7 @@ namespace cryptonote
|
||||
FIELD(data)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
|
||||
struct tx_extra_service_node_winner
|
||||
{
|
||||
crypto::public_key m_service_node_key;
|
||||
@@ -277,6 +290,45 @@ namespace cryptonote
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct tx_extra_service_node_state_change
|
||||
{
|
||||
struct vote
|
||||
{
|
||||
vote() = default;
|
||||
vote(crypto::signature const &signature, uint32_t validator_index) : signature(signature), validator_index(validator_index) {}
|
||||
crypto::signature signature;
|
||||
uint32_t validator_index;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
VARINT_FIELD(validator_index)
|
||||
FIELD(signature)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
service_nodes::new_state state;
|
||||
uint64_t block_height;
|
||||
uint32_t service_node_index;
|
||||
std::vector<vote> votes;
|
||||
|
||||
tx_extra_service_node_state_change() = default;
|
||||
|
||||
template<typename... VotesArgs>
|
||||
tx_extra_service_node_state_change(service_nodes::new_state state, uint64_t block_height, uint32_t service_node_index, VotesArgs &&...votes)
|
||||
: state{state}, block_height{block_height}, service_node_index{service_node_index}, votes{std::forward<VotesArgs>(votes)...} {}
|
||||
|
||||
bool operator==(const tx_extra_service_node_state_change &sc) const
|
||||
{
|
||||
return state == sc.state && block_height == sc.block_height && service_node_index == sc.service_node_index;
|
||||
}
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
ENUM_FIELD(state, state < service_nodes::new_state::_count)
|
||||
FIELD(block_height)
|
||||
FIELD(service_node_index)
|
||||
FIELD(votes)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct tx_extra_tx_secret_key
|
||||
{
|
||||
crypto::secret_key key;
|
||||
@@ -324,35 +376,37 @@ namespace cryptonote
|
||||
tx_extra_merge_mining_tag,
|
||||
tx_extra_additional_pub_keys,
|
||||
tx_extra_mysterious_minergate,
|
||||
tx_extra_offshore,
|
||||
tx_extra_memo,
|
||||
tx_extra_offshore,
|
||||
tx_extra_memo,
|
||||
tx_extra_service_node_pubkey,
|
||||
tx_extra_service_node_register,
|
||||
tx_extra_service_node_contributor,
|
||||
tx_extra_service_node_winner,
|
||||
tx_extra_service_node_deregister,
|
||||
tx_extra_service_node_state_change,
|
||||
tx_extra_tx_secret_key,
|
||||
tx_extra_tx_key_image_proofs,
|
||||
tx_extra_tx_key_image_unlock
|
||||
tx_extra_tx_key_image_unlock,
|
||||
tx_extra_service_node_deregister
|
||||
> tx_extra_field;
|
||||
}
|
||||
|
||||
BLOB_SERIALIZER(cryptonote::tx_extra_service_node_deregister::vote);
|
||||
BLOB_SERIALIZER(cryptonote::tx_extra_tx_key_image_proofs::proof);
|
||||
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_padding, TX_EXTRA_TAG_PADDING);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_pub_key, TX_EXTRA_TAG_PUBKEY);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_nonce, TX_EXTRA_NONCE);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_merge_mining_tag, TX_EXTRA_MERGE_MINING_TAG);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_additional_pub_keys, TX_EXTRA_TAG_ADDITIONAL_PUBKEYS);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_mysterious_minergate, TX_EXTRA_MYSTERIOUS_MINERGATE_TAG);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_offshore, TX_EXTRA_TAG_OFFSHORE);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_memo, TX_EXTRA_TAG_MEMO);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_register, TX_EXTRA_TAG_SERVICE_NODE_REGISTER);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_deregister, TX_EXTRA_TAG_SERVICE_NODE_DEREGISTER);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_contributor, TX_EXTRA_TAG_SERVICE_NODE_CONTRIBUTOR);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_winner, TX_EXTRA_TAG_SERVICE_NODE_WINNER);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_pubkey, TX_EXTRA_TAG_SERVICE_NODE_PUBKEY);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_tx_secret_key, TX_EXTRA_TAG_TX_SECRET_KEY);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_tx_key_image_proofs, TX_EXTRA_TAG_TX_KEY_IMAGE_PROOFS);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_tx_key_image_unlock, TX_EXTRA_TAG_TX_KEY_IMAGE_UNLOCK);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_padding, TX_EXTRA_TAG_PADDING);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_pub_key, TX_EXTRA_TAG_PUBKEY);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_nonce, TX_EXTRA_NONCE);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_merge_mining_tag, TX_EXTRA_MERGE_MINING_TAG);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_additional_pub_keys, TX_EXTRA_TAG_ADDITIONAL_PUBKEYS);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_mysterious_minergate, TX_EXTRA_MYSTERIOUS_MINERGATE_TAG);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_offshore, TX_EXTRA_TAG_OFFSHORE);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_memo, TX_EXTRA_TAG_MEMO);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_register, TX_EXTRA_TAG_SERVICE_NODE_REGISTER);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_state_change, TX_EXTRA_TAG_SERVICE_NODE_STATE_CHANGE);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_contributor, TX_EXTRA_TAG_SERVICE_NODE_CONTRIBUTOR);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_winner, TX_EXTRA_TAG_SERVICE_NODE_WINNER);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_pubkey, TX_EXTRA_TAG_SERVICE_NODE_PUBKEY);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_tx_secret_key, TX_EXTRA_TAG_TX_SECRET_KEY);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_tx_key_image_proofs, TX_EXTRA_TAG_TX_KEY_IMAGE_PROOFS);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_tx_key_image_unlock, TX_EXTRA_TAG_TX_KEY_IMAGE_UNLOCK);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_deregister, TX_EXTRA_TAG_SERVICE_NODE_DEREGISTER);
|
||||
+26
-4
@@ -1,9 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#define CURRENT_TRANSACTION_VERSION 1
|
||||
#define OFFSHORE_TRANSACTION_VERSION 3
|
||||
#define HF_VERSION_XASSET_FEES_V2 17
|
||||
#define HF_VERSION_HAVEN2 18
|
||||
#define CURRENT_TRANSACTION_VERSION 1
|
||||
#define POU_TRANSACTION_VERSION 6
|
||||
#define COLLATERAL_TRANSACTION_VERSION 7
|
||||
#define HAVEN_TYPES_TRANSACTION_VERSION 8
|
||||
#define OFFSHORE_TRANSACTION_VERSION 3
|
||||
#define HF_VERSION_XASSET_FEES_V2 17
|
||||
#define HF_VERSION_HAVEN2 18
|
||||
#define HF_VERSION_USE_COLLATERAL 20
|
||||
#define HF_VERSION_ENABLE_N_OUTS 2
|
||||
#define TRANSACTION_VERSION_N_OUTS 3
|
||||
#define TRANSACTION_VERSION_CARROT 4
|
||||
|
||||
// UNLOCK TIMES
|
||||
#define TX_V6_OFFSHORE_UNLOCK_BLOCKS 21*720 // 21 day unlock time
|
||||
#define TX_V6_ONSHORE_UNLOCK_BLOCKS 360 // 12 hour unlock time
|
||||
#define TX_V7_ONSHORE_UNLOCK_BLOCKS 21*720 // 21 day unlock time
|
||||
#define TX_V6_XASSET_UNLOCK_BLOCKS 1440 // 2 day unlock time
|
||||
#define TX_V6_OFFSHORE_UNLOCK_BLOCKS_TESTNET 60 // 2 hour unlock time - FOR TESTING ONLY
|
||||
#define TX_V6_ONSHORE_UNLOCK_BLOCKS_TESTNET 30 // 1 hour unlock time - FOR TESTING ONLY
|
||||
#define TX_V6_XASSET_UNLOCK_BLOCKS_TESTNET 60 // 2 hour unlock time - FOR TESTING ONLY
|
||||
|
||||
#define PRICING_RECORD_VALID_TIME_DIFF_FROM_BLOCK 120 // seconds
|
||||
|
||||
enum BLOB_TYPE {
|
||||
BLOB_TYPE_CRYPTONOTE = 0,
|
||||
@@ -19,4 +37,8 @@ enum BLOB_TYPE {
|
||||
BLOB_TYPE_CRYPTONOTE_TUBE = 10, // TUBE
|
||||
BLOB_TYPE_CRYPTONOTE_XHV = 11, // Haven
|
||||
BLOB_TYPE_CRYPTONOTE_XTA = 12, // ITALO
|
||||
BLOB_TYPE_CRYPTONOTE_ZEPHYR = 13, // ZEPHYR
|
||||
BLOB_TYPE_CRYPTONOTE_XLA = 14, // XLA
|
||||
BLOB_TYPE_CRYPTONOTE_SALVIUM= 15, // Salvium
|
||||
BLOB_TYPE_CRYPTONOTE_ARQMA = 16 // Arqma
|
||||
};
|
||||
|
||||
@@ -1,683 +0,0 @@
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
#include <boost/functional/hash/hash.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <cstring> // memcmp
|
||||
#include <sstream>
|
||||
#include "serialization/serialization.h"
|
||||
#include "serialization/variant.h"
|
||||
#include "serialization/vector.h"
|
||||
#include "serialization/binary_archive.h"
|
||||
#include "serialization/json_archive.h"
|
||||
#include "serialization/debug_archive.h"
|
||||
#include "serialization/crypto.h"
|
||||
#include "serialization/pricing_record.h"
|
||||
#include "serialization/keyvalue_serialization.h" // eepe named serialization
|
||||
#include "string_tools.h"
|
||||
#include "cryptonote_config.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "misc_language.h"
|
||||
#include "tx_extra.h"
|
||||
#include "ringct/rctTypes.h"
|
||||
#include "cryptonote_protocol/blobdatatype.h"
|
||||
#include "offshore/pricing_record.h"
|
||||
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
struct block;
|
||||
class transaction;
|
||||
class transaction_prefix;
|
||||
struct tx_extra_merge_mining_tag;
|
||||
|
||||
// Implemented in cryptonote_format_utils.cpp
|
||||
bool get_transaction_hash(const transaction& t, crypto::hash& res);
|
||||
void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h);
|
||||
void get_blob_hash(const blobdata& blob, crypto::hash& res);
|
||||
bool get_mm_tag_from_extra(const std::vector<uint8_t>& tx, tx_extra_merge_mining_tag& mm_tag);
|
||||
|
||||
const static crypto::hash null_hash = AUTO_VAL_INIT(null_hash);
|
||||
const static crypto::public_key null_pkey = AUTO_VAL_INIT(null_pkey);
|
||||
|
||||
typedef std::vector<crypto::signature> ring_signature;
|
||||
|
||||
|
||||
/* outputs */
|
||||
|
||||
struct txout_to_script
|
||||
{
|
||||
std::vector<crypto::public_key> keys;
|
||||
std::vector<uint8_t> script;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(keys)
|
||||
FIELD(script)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct txout_to_scripthash
|
||||
{
|
||||
crypto::hash hash;
|
||||
};
|
||||
|
||||
struct txout_to_key
|
||||
{
|
||||
txout_to_key() { }
|
||||
txout_to_key(const crypto::public_key &_key) : key(_key) { }
|
||||
crypto::public_key key;
|
||||
};
|
||||
|
||||
struct txout_offshore
|
||||
{
|
||||
txout_offshore() { }
|
||||
txout_offshore(const crypto::public_key &_key) : key(_key) { }
|
||||
crypto::public_key key;
|
||||
};
|
||||
|
||||
struct txout_xasset
|
||||
{
|
||||
txout_xasset() { }
|
||||
txout_xasset(const crypto::public_key &_key, const std::string &_asset_type) : key(_key), asset_type(_asset_type) { }
|
||||
crypto::public_key key;
|
||||
std::string asset_type;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(key)
|
||||
FIELD(asset_type)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
/* inputs */
|
||||
|
||||
struct txin_gen
|
||||
{
|
||||
size_t height;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD(height)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct txin_to_script
|
||||
{
|
||||
crypto::hash prev;
|
||||
size_t prevout;
|
||||
std::vector<uint8_t> sigset;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(prev)
|
||||
VARINT_FIELD(prevout)
|
||||
FIELD(sigset)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct txin_to_scripthash
|
||||
{
|
||||
crypto::hash prev;
|
||||
size_t prevout;
|
||||
txout_to_script script;
|
||||
std::vector<uint8_t> sigset;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(prev)
|
||||
VARINT_FIELD(prevout)
|
||||
FIELD(script)
|
||||
FIELD(sigset)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct txin_to_key
|
||||
{
|
||||
uint64_t amount;
|
||||
std::vector<uint64_t> key_offsets;
|
||||
crypto::key_image k_image; // double spending protection
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD(amount)
|
||||
FIELD(key_offsets)
|
||||
FIELD(k_image)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct txin_offshore
|
||||
{
|
||||
uint64_t amount;
|
||||
std::vector<uint64_t> key_offsets;
|
||||
crypto::key_image k_image;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD(amount)
|
||||
FIELD(key_offsets)
|
||||
FIELD(k_image)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct txin_onshore
|
||||
{
|
||||
uint64_t amount;
|
||||
std::vector<uint64_t> key_offsets;
|
||||
crypto::key_image k_image;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD(amount)
|
||||
FIELD(key_offsets)
|
||||
FIELD(k_image)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct txin_xasset
|
||||
{
|
||||
uint64_t amount;
|
||||
std::string asset_type;
|
||||
std::vector<uint64_t> key_offsets;
|
||||
crypto::key_image k_image; // double spending protection
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD(amount)
|
||||
FIELD(asset_type)
|
||||
FIELD(key_offsets)
|
||||
FIELD(k_image)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
typedef boost::variant<txin_gen, txin_to_script, txin_to_scripthash, txin_to_key, txin_offshore, txin_onshore, txin_xasset> txin_v;
|
||||
|
||||
typedef boost::variant<txout_to_script, txout_to_scripthash, txout_to_key, txout_offshore, txout_xasset> txout_target_v;
|
||||
|
||||
//typedef std::pair<uint64_t, txout> out_t;
|
||||
struct tx_out
|
||||
{
|
||||
uint64_t amount;
|
||||
txout_target_v target;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD(amount)
|
||||
FIELD(target)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
enum loki_version
|
||||
{
|
||||
loki_version_0 = 0,
|
||||
loki_version_1,
|
||||
loki_version_2,
|
||||
loki_version_3_per_output_unlock_times,
|
||||
loki_version_4_tx_types,
|
||||
};
|
||||
|
||||
class transaction_prefix
|
||||
{
|
||||
|
||||
public:
|
||||
enum BLOB_TYPE blob_type;
|
||||
// tx information
|
||||
size_t version;
|
||||
uint64_t unlock_time; //number of block (or time), used as a limitation like: spend this tx not early then block/time
|
||||
|
||||
std::vector<txin_v> vin;
|
||||
std::vector<tx_out> vout;
|
||||
//extra
|
||||
std::vector<uint8_t> extra;
|
||||
// Block height to use PR from
|
||||
uint64_t pricing_record_height;
|
||||
// Circulating supply information
|
||||
std::vector<uint8_t> offshore_data;
|
||||
uint64_t amount_burnt;
|
||||
uint64_t amount_minted;
|
||||
|
||||
//
|
||||
// NOTE: Loki specific
|
||||
//
|
||||
std::vector<uint64_t> output_unlock_times;
|
||||
enum loki_type_t
|
||||
{
|
||||
loki_type_standard,
|
||||
loki_type_deregister,
|
||||
loki_type_key_image_unlock,
|
||||
loki_type_count,
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
bool is_deregister;
|
||||
uint16_t type;
|
||||
};
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
VARINT_FIELD(version)
|
||||
if (version > loki_version_2 && (blob_type == BLOB_TYPE_CRYPTONOTE_LOKI || blob_type == BLOB_TYPE_CRYPTONOTE_XTNC))
|
||||
{
|
||||
FIELD(output_unlock_times)
|
||||
if (version == loki_version_3_per_output_unlock_times)
|
||||
FIELD(is_deregister)
|
||||
}
|
||||
VARINT_FIELD(unlock_time)
|
||||
FIELD(vin)
|
||||
FIELD(vout)
|
||||
if (blob_type == BLOB_TYPE_CRYPTONOTE_LOKI || blob_type == BLOB_TYPE_CRYPTONOTE_XTNC)
|
||||
{
|
||||
if (version >= loki_version_3_per_output_unlock_times && vout.size() != output_unlock_times.size()) return false;
|
||||
}
|
||||
FIELD(extra)
|
||||
if ((blob_type == BLOB_TYPE_CRYPTONOTE_LOKI || blob_type == BLOB_TYPE_CRYPTONOTE_XTNC) && version >= loki_version_4_tx_types)
|
||||
{
|
||||
VARINT_FIELD(type)
|
||||
if (static_cast<uint16_t>(type) >= loki_type_count) return false;
|
||||
}
|
||||
if (blob_type == BLOB_TYPE_CRYPTONOTE_XHV && version >= OFFSHORE_TRANSACTION_VERSION) {
|
||||
VARINT_FIELD(pricing_record_height)
|
||||
if (version < 5)
|
||||
FIELD(offshore_data)
|
||||
VARINT_FIELD(amount_burnt)
|
||||
VARINT_FIELD(amount_minted)
|
||||
}
|
||||
END_SERIALIZE()
|
||||
|
||||
|
||||
protected:
|
||||
transaction_prefix() : blob_type(BLOB_TYPE_CRYPTONOTE) {}
|
||||
};
|
||||
|
||||
class transaction: public transaction_prefix
|
||||
{
|
||||
public:
|
||||
std::vector<std::vector<crypto::signature> > signatures; //count signatures always the same as inputs count
|
||||
rct::rctSig rct_signatures;
|
||||
|
||||
transaction();
|
||||
virtual ~transaction();
|
||||
void set_null();
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELDS(*static_cast<transaction_prefix *>(this))
|
||||
|
||||
if (version == 1 && blob_type != BLOB_TYPE_CRYPTONOTE2 && blob_type != BLOB_TYPE_CRYPTONOTE3)
|
||||
{
|
||||
ar.tag("signatures");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(vin.size(), signatures);
|
||||
bool signatures_not_expected = signatures.empty();
|
||||
if (!signatures_not_expected && vin.size() != signatures.size())
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < vin.size(); ++i)
|
||||
{
|
||||
size_t signature_size = get_signature_size(vin[i]);
|
||||
if (signatures_not_expected)
|
||||
{
|
||||
if (0 == signature_size)
|
||||
continue;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(signature_size, signatures[i]);
|
||||
if (signature_size != signatures[i].size())
|
||||
return false;
|
||||
|
||||
FIELDS(signatures[i]);
|
||||
|
||||
if (vin.size() - i > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
}
|
||||
else
|
||||
{
|
||||
ar.tag("rct_signatures");
|
||||
if (!vin.empty())
|
||||
{
|
||||
ar.begin_object();
|
||||
bool r = rct_signatures.serialize_rctsig_base(ar, vin.size(), vout.size());
|
||||
if (!r || !ar.stream().good()) return false;
|
||||
ar.end_object();
|
||||
if (rct_signatures.type != rct::RCTTypeNull)
|
||||
{
|
||||
ar.tag("rctsig_prunable");
|
||||
ar.begin_object();
|
||||
if (blob_type != BLOB_TYPE_CRYPTONOTE_XHV) {
|
||||
r = rct_signatures.p.serialize_rctsig_prunable(ar, rct_signatures.type, vin.size(), vout.size(),
|
||||
vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(vin[0]).key_offsets.size() - 1 : 0);
|
||||
} else {
|
||||
r = rct_signatures.p.serialize_rctsig_prunable(ar, rct_signatures.type, vin.size(), vout.size(),
|
||||
vin.size() > 0 && vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(vin[0]).key_offsets.size() - 1 :
|
||||
vin.size() > 0 && vin[0].type() == typeid(txin_offshore) ? boost::get<txin_offshore>(vin[0]).key_offsets.size() - 1 :
|
||||
vin.size() > 0 && vin[0].type() == typeid(txin_onshore) ? boost::get<txin_onshore>(vin[0]).key_offsets.size() - 1 :
|
||||
vin.size() > 0 && vin[0].type() == typeid(txin_xasset) ? boost::get<txin_xasset>(vin[0]).key_offsets.size() - 1 :
|
||||
0);
|
||||
}
|
||||
if (!r || !ar.stream().good()) return false;
|
||||
ar.end_object();
|
||||
}
|
||||
}
|
||||
}
|
||||
END_SERIALIZE()
|
||||
|
||||
private:
|
||||
static size_t get_signature_size(const txin_v& tx_in);
|
||||
};
|
||||
|
||||
inline
|
||||
transaction::transaction()
|
||||
{
|
||||
set_null();
|
||||
}
|
||||
|
||||
inline
|
||||
transaction::~transaction()
|
||||
{
|
||||
//set_null();
|
||||
}
|
||||
|
||||
inline
|
||||
void transaction::set_null()
|
||||
{
|
||||
version = 0;
|
||||
unlock_time = 0;
|
||||
vin.clear();
|
||||
vout.clear();
|
||||
extra.clear();
|
||||
signatures.clear();
|
||||
pricing_record_height = 0;
|
||||
offshore_data.clear();
|
||||
amount_burnt = 0;
|
||||
amount_minted = 0;
|
||||
}
|
||||
|
||||
inline
|
||||
size_t transaction::get_signature_size(const txin_v& tx_in)
|
||||
{
|
||||
struct txin_signature_size_visitor : public boost::static_visitor<size_t>
|
||||
{
|
||||
size_t operator()(const txin_gen& txin) const{return 0;}
|
||||
size_t operator()(const txin_to_script& txin) const{return 0;}
|
||||
size_t operator()(const txin_to_scripthash& txin) const{return 0;}
|
||||
size_t operator()(const txin_to_key& txin) const {return txin.key_offsets.size();}
|
||||
size_t operator()(const txin_offshore& txin) const {return txin.key_offsets.size();}
|
||||
size_t operator()(const txin_onshore& txin) const {return txin.key_offsets.size();}
|
||||
size_t operator()(const txin_xasset& txin) const {return txin.key_offsets.size();}
|
||||
};
|
||||
|
||||
return boost::apply_visitor(txin_signature_size_visitor(), tx_in);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
|
||||
const uint8_t CURRENT_BYTECOIN_BLOCK_MAJOR_VERSION = 1;
|
||||
|
||||
struct bytecoin_block
|
||||
{
|
||||
uint8_t major_version;
|
||||
uint8_t minor_version;
|
||||
crypto::hash prev_id;
|
||||
uint32_t nonce;
|
||||
size_t number_of_transactions;
|
||||
std::vector<crypto::hash> miner_tx_branch;
|
||||
transaction miner_tx;
|
||||
std::vector<crypto::hash> blockchain_branch;
|
||||
};
|
||||
|
||||
struct serializable_bytecoin_block
|
||||
{
|
||||
bytecoin_block& b;
|
||||
uint64_t& timestamp;
|
||||
bool hashing_serialization;
|
||||
bool header_only;
|
||||
|
||||
serializable_bytecoin_block(bytecoin_block& b_, uint64_t& timestamp_, bool hashing_serialization_, bool header_only_) :
|
||||
b(b_), timestamp(timestamp_), hashing_serialization(hashing_serialization_), header_only(header_only_)
|
||||
{
|
||||
}
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD_N("major_version", b.major_version);
|
||||
VARINT_FIELD_N("minor_version", b.minor_version);
|
||||
VARINT_FIELD(timestamp);
|
||||
FIELD_N("prev_id", b.prev_id);
|
||||
FIELD_N("nonce", b.nonce);
|
||||
|
||||
if (hashing_serialization)
|
||||
{
|
||||
crypto::hash miner_tx_hash;
|
||||
|
||||
if (b.miner_tx.version < 2) {
|
||||
if (!get_transaction_hash(b.miner_tx, miner_tx_hash))
|
||||
return false;
|
||||
} else {
|
||||
get_transaction_prefix_hash(static_cast<const transaction_prefix&>(b.miner_tx), miner_tx_hash);
|
||||
const uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x36, 0x78, 0x9e, 0x7a, 0x1e, 0x28, 0x14, 0x36, 0x46, 0x42, 0x29, 0x82, 0x8f, 0x81, 0x7d, 0x66, 0x12, 0xf7, 0xb4, 0x77, 0xd6, 0x65, 0x91, 0xff, 0x96, 0xa9, 0xe0, 0x64, 0xbc, 0xc9, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
blobdata blobdata((char*)data, sizeof(data));
|
||||
const unsigned char* p = (unsigned char*)&miner_tx_hash;
|
||||
for (int i = 0; i != crypto::HASH_SIZE; ++ i, ++ p) blobdata[i] = *p;
|
||||
get_blob_hash(blobdata, miner_tx_hash);
|
||||
}
|
||||
|
||||
crypto::hash merkle_root;
|
||||
crypto::tree_hash_from_branch(b.miner_tx_branch.data(), b.miner_tx_branch.size(), miner_tx_hash, 0, merkle_root);
|
||||
|
||||
FIELD(merkle_root);
|
||||
}
|
||||
|
||||
VARINT_FIELD_N("number_of_transactions", b.number_of_transactions);
|
||||
if (b.number_of_transactions < 1)
|
||||
return false;
|
||||
|
||||
if (!header_only)
|
||||
{
|
||||
ar.tag("miner_tx_branch");
|
||||
ar.begin_array();
|
||||
size_t branch_size = crypto::tree_depth(b.number_of_transactions);
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(branch_size, const_cast<bytecoin_block&>(b).miner_tx_branch);
|
||||
if (b.miner_tx_branch.size() != branch_size)
|
||||
return false;
|
||||
for (size_t i = 0; i < branch_size; ++i)
|
||||
{
|
||||
FIELDS(b.miner_tx_branch[i]);
|
||||
if (i + 1 < branch_size)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
|
||||
FIELD(b.miner_tx);
|
||||
|
||||
tx_extra_merge_mining_tag mm_tag;
|
||||
if (!get_mm_tag_from_extra(b.miner_tx.extra, mm_tag))
|
||||
return false;
|
||||
|
||||
ar.tag("blockchain_branch");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mm_tag.depth, const_cast<bytecoin_block&>(b).blockchain_branch);
|
||||
if (mm_tag.depth != b.blockchain_branch.size())
|
||||
return false;
|
||||
for (size_t i = 0; i < mm_tag.depth; ++i)
|
||||
{
|
||||
FIELDS(b.blockchain_branch[i]);
|
||||
if (i + 1 < mm_tag.depth)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
}
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
// Implemented below
|
||||
inline serializable_bytecoin_block make_serializable_bytecoin_block(const block& b, bool hashing_serialization, bool header_only);
|
||||
|
||||
struct block_header
|
||||
{
|
||||
enum BLOB_TYPE blob_type;
|
||||
|
||||
uint8_t major_version;
|
||||
uint8_t minor_version;
|
||||
uint64_t timestamp;
|
||||
crypto::hash prev_id;
|
||||
uint64_t nonce;
|
||||
uint64_t nonce8;
|
||||
offshore::pricing_record pricing_record;
|
||||
crypto::cycle cycle;
|
||||
crypto::cycle40 cycle40;
|
||||
crypto::cycle48 cycle48;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
VARINT_FIELD(major_version)
|
||||
VARINT_FIELD(minor_version)
|
||||
if (blob_type != BLOB_TYPE_FORKNOTE2) VARINT_FIELD(timestamp)
|
||||
FIELD(prev_id)
|
||||
if (blob_type == BLOB_TYPE_CRYPTONOTE_CUCKOO || blob_type == BLOB_TYPE_CRYPTONOTE_TUBE || blob_type == BLOB_TYPE_CRYPTONOTE_XTA) FIELD(nonce8)
|
||||
if (blob_type != BLOB_TYPE_FORKNOTE2) {
|
||||
if (blob_type == BLOB_TYPE_AEON) {
|
||||
FIELD(nonce)
|
||||
} else {
|
||||
uint32_t nonce32;
|
||||
if (typename Archive<W>::is_saving()) nonce32 = (uint32_t)nonce;
|
||||
FIELD_N("nonce", nonce32);
|
||||
if (!typename Archive<W>::is_saving()) nonce = nonce32;
|
||||
}
|
||||
}
|
||||
if (blob_type == BLOB_TYPE_CRYPTONOTE_XTNC || blob_type == BLOB_TYPE_CRYPTONOTE_CUCKOO) FIELD(cycle)
|
||||
if (blob_type == BLOB_TYPE_CRYPTONOTE_TUBE) FIELD(cycle40)
|
||||
if (blob_type == BLOB_TYPE_CRYPTONOTE_XTA) FIELD(cycle48)
|
||||
if (blob_type == BLOB_TYPE_CRYPTONOTE_XHV) FIELD(pricing_record)
|
||||
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct block: public block_header
|
||||
{
|
||||
bytecoin_block parent_block;
|
||||
|
||||
transaction miner_tx;
|
||||
std::vector<crypto::hash> tx_hashes;
|
||||
mutable crypto::hash uncle = cryptonote::null_hash;
|
||||
|
||||
void set_blob_type(enum BLOB_TYPE bt) { miner_tx.blob_type = blob_type = bt; }
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELDS(*static_cast<block_header *>(this))
|
||||
if (blob_type == BLOB_TYPE_FORKNOTE2)
|
||||
{
|
||||
auto sbb = make_serializable_bytecoin_block(*this, false, false);
|
||||
FIELD_N("parent_block", sbb);
|
||||
}
|
||||
FIELD(miner_tx)
|
||||
FIELD(tx_hashes)
|
||||
if (blob_type == BLOB_TYPE_CRYPTONOTE3)
|
||||
{
|
||||
FIELD(uncle)
|
||||
}
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
inline serializable_bytecoin_block make_serializable_bytecoin_block(const block& b, bool hashing_serialization, bool header_only)
|
||||
{
|
||||
block& block_ref = const_cast<block&>(b);
|
||||
return serializable_bytecoin_block(block_ref.parent_block, block_ref.timestamp, hashing_serialization, header_only);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct account_public_address
|
||||
{
|
||||
crypto::public_key m_spend_public_key;
|
||||
crypto::public_key m_view_public_key;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(m_spend_public_key)
|
||||
FIELD(m_view_public_key)
|
||||
END_SERIALIZE()
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_spend_public_key)
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_view_public_key)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct integrated_address {
|
||||
account_public_address adr;
|
||||
crypto::hash8 payment_id;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(adr)
|
||||
FIELD(payment_id)
|
||||
END_SERIALIZE()
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(adr)
|
||||
KV_SERIALIZE(payment_id)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct keypair
|
||||
{
|
||||
crypto::public_key pub;
|
||||
crypto::secret_key sec;
|
||||
|
||||
static inline keypair generate()
|
||||
{
|
||||
keypair k;
|
||||
generate_keys(k.pub, k.sec);
|
||||
return k;
|
||||
}
|
||||
};
|
||||
//---------------------------------------------------------------
|
||||
|
||||
}
|
||||
|
||||
BLOB_SERIALIZER(cryptonote::txout_to_key);
|
||||
BLOB_SERIALIZER(cryptonote::txout_offshore);
|
||||
BLOB_SERIALIZER(cryptonote::txout_to_scripthash);
|
||||
|
||||
VARIANT_TAG(binary_archive, cryptonote::txin_gen, 0xff);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txin_to_script, 0x0);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txin_to_scripthash, 0x1);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txin_to_key, 0x2);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txin_offshore, 0x3);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txin_onshore, 0x4);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txin_xasset, 0x5);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txout_to_script, 0x0);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txout_to_scripthash, 0x1);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txout_to_key, 0x2);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txout_offshore, 0x3);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txout_xasset, 0x5);
|
||||
VARIANT_TAG(binary_archive, cryptonote::transaction, 0xcc);
|
||||
VARIANT_TAG(binary_archive, cryptonote::block, 0xbb);
|
||||
|
||||
VARIANT_TAG(json_archive, cryptonote::txin_gen, "gen");
|
||||
VARIANT_TAG(json_archive, cryptonote::txin_to_script, "script");
|
||||
VARIANT_TAG(json_archive, cryptonote::txin_to_scripthash, "scripthash");
|
||||
VARIANT_TAG(json_archive, cryptonote::txin_to_key, "key");
|
||||
VARIANT_TAG(json_archive, cryptonote::txin_offshore, "offshore");
|
||||
VARIANT_TAG(json_archive, cryptonote::txin_onshore, "onshore");
|
||||
VARIANT_TAG(json_archive, cryptonote::txin_xasset, "xasset");
|
||||
VARIANT_TAG(json_archive, cryptonote::txout_to_script, "script");
|
||||
VARIANT_TAG(json_archive, cryptonote::txout_to_scripthash, "scripthash");
|
||||
VARIANT_TAG(json_archive, cryptonote::txout_to_key, "key");
|
||||
VARIANT_TAG(json_archive, cryptonote::txout_offshore, "offshore");
|
||||
VARIANT_TAG(json_archive, cryptonote::txout_xasset, "xasset");
|
||||
VARIANT_TAG(json_archive, cryptonote::transaction, "tx");
|
||||
VARIANT_TAG(json_archive, cryptonote::block, "block");
|
||||
|
||||
VARIANT_TAG(debug_archive, cryptonote::txin_gen, "gen");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txin_to_script, "script");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txin_to_scripthash, "scripthash");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txin_to_key, "key");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txin_offshore, "offshore");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txin_onshore, "onshore");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txin_xasset, "xasset");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txout_to_script, "script");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txout_to_scripthash, "scripthash");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txout_to_key, "key");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txout_offshore, "offshore");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txout_xasset, "xasset");
|
||||
VARIANT_TAG(debug_archive, cryptonote::transaction, "tx");
|
||||
VARIANT_TAG(debug_archive, cryptonote::block, "block");
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include <list>
|
||||
#include "serialization/keyvalue_serialization.h"
|
||||
#include "cryptonote_core/cryptonote_basic.h"
|
||||
#include "cryptonote_basic/cryptonote_basic.h"
|
||||
#include "cryptonote_protocol/blobdatatype.h"
|
||||
namespace cryptonote
|
||||
{
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
#ifndef CRYPTONOTE_ENUMS_H
|
||||
#define CRYPTONOTE_ENUMS_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
enum salvium_transaction_type
|
||||
{
|
||||
UNSET = 0,
|
||||
MINER = 1,
|
||||
PROTOCOL = 2,
|
||||
TRANSFER = 3,
|
||||
CONVERT = 4,
|
||||
BURN = 5,
|
||||
STAKE = 6,
|
||||
RETURN = 7,
|
||||
AUDIT = 8,
|
||||
MAX = 8
|
||||
};
|
||||
}
|
||||
|
||||
#endif // CRYPTONOTE_ENUMS_H
|
||||
+12
-7
@@ -5,8 +5,9 @@
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include "cryptonote_core/cryptonote_basic.h"
|
||||
#include "cryptonote_core/cryptonote_format_utils.h"
|
||||
#include "cryptonote_basic/cryptonote_basic.h"
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
#include "cryptonote_basic/tx_extra.h"
|
||||
#include "common/base58.h"
|
||||
#include "serialization/binary_utils.h"
|
||||
#include <nan.h>
|
||||
@@ -32,7 +33,7 @@ blobdata uint64be_to_blob(uint64_t num) {
|
||||
res[7] = num & 0xff;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static bool fillExtra(cryptonote::block& block1, const cryptonote::block& block2) {
|
||||
cryptonote::tx_extra_merge_mining_tag mm_tag;
|
||||
mm_tag.depth = 0;
|
||||
@@ -145,7 +146,7 @@ NAN_METHOD(convert_blob) { // (parentBlockBuffer, cnBlobType)
|
||||
|
||||
block b = AUTO_VAL_INIT(b);
|
||||
b.set_blob_type(blob_type);
|
||||
if (!parse_and_validate_block_from_blob(input, b)) return THROW_ERROR_EXCEPTION("Failed to parse block");
|
||||
if (!parse_and_validate_block_from_blob(input, b)) return THROW_ERROR_EXCEPTION("Failed to parse block 2");
|
||||
|
||||
if (blob_type == BLOB_TYPE_FORKNOTE2) {
|
||||
block parent_block;
|
||||
@@ -250,7 +251,7 @@ NAN_METHOD(address_decode) {
|
||||
Local<Object> target = info[0]->ToObject(isolate->GetCurrentContext()).ToLocalChecked();
|
||||
|
||||
if (!Buffer::HasInstance(target)) return THROW_ERROR_EXCEPTION("Argument should be a buffer object.");
|
||||
|
||||
|
||||
blobdata input = std::string(Buffer::Data(target), Buffer::Length(target));
|
||||
|
||||
blobdata data;
|
||||
@@ -330,7 +331,11 @@ NAN_METHOD(construct_mm_parent_block_blob) { // (parentBlockTemplate, blob_type,
|
||||
b.set_blob_type(blob_type);
|
||||
if (!parse_and_validate_block_from_blob(input, b)) return THROW_ERROR_EXCEPTION("construct_mm_parent_block_blob: Failed to parse prent block");
|
||||
if (blob_type == BLOB_TYPE_CRYPTONOTE_LOKI || blob_type == BLOB_TYPE_CRYPTONOTE_XTNC) b.miner_tx.version = cryptonote::loki_version_2;
|
||||
|
||||
if (blob_type == BLOB_TYPE_CRYPTONOTE_ARQMA) {
|
||||
b.miner_tx.version = static_cast<size_t>(cryptonote_arq::txversion::v3);
|
||||
b.miner_tx.arq_tx_type = cryptonote_arq::txtype::standard;
|
||||
}
|
||||
|
||||
block b2 = AUTO_VAL_INIT(b2);
|
||||
b2.set_blob_type(BLOB_TYPE_FORKNOTE2);
|
||||
if (!parse_and_validate_block_from_blob(child_input, b2)) return THROW_ERROR_EXCEPTION("construct_mm_parent_block_blob: Failed to parse child block");
|
||||
@@ -369,7 +374,7 @@ NAN_METHOD(construct_mm_child_block_blob) { // (shareBuffer, blob_type, childBlo
|
||||
if (!parse_and_validate_block_from_blob(child_block_template_blob, b2)) return THROW_ERROR_EXCEPTION("construct_mm_child_block_blob: Failed to parse child block");
|
||||
|
||||
if (!mergeBlocks(b, b2, std::vector<crypto::hash>())) return THROW_ERROR_EXCEPTION("construct_mm_child_block_blob: Failed to postprocess mining block");
|
||||
|
||||
|
||||
blobdata output = "";
|
||||
if (!block_to_blob(b2, output)) return THROW_ERROR_EXCEPTION("construct_mm_child_block_blob: Failed to convert child block to blob");
|
||||
|
||||
|
||||
@@ -33,10 +33,6 @@
|
||||
#include "storages/portable_storage.h"
|
||||
|
||||
#include "string_tools.h"
|
||||
|
||||
#define PRICING_RECORD_VALID_BLOCKS 10
|
||||
#define PRICING_RECORD_VALID_TIME_DIFF_FROM_BLOCK 120 // seconds
|
||||
|
||||
namespace offshore
|
||||
{
|
||||
|
||||
@@ -262,27 +258,8 @@ namespace offshore
|
||||
return (*this).equal(empty_pr);
|
||||
}
|
||||
|
||||
bool pricing_record::verifySignature() const
|
||||
bool pricing_record::verifySignature(const std::string& public_key) const
|
||||
{
|
||||
// Oracle public keys
|
||||
std::string const mainnet_public_key = "-----BEGIN PUBLIC KEY-----\n"
|
||||
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5YBxWx1AZCA9jTUk8Pr2uZ9jpfRt\n"
|
||||
"KWv3Vo1/Gny+1vfaxsXhBQiG1KlHkafNGarzoL0WHW4ocqaaqF5iv8i35A==\n"
|
||||
"-----END PUBLIC KEY-----\n";
|
||||
std::string const testnet_public_key = "-----BEGIN PUBLIC KEY-----\n"
|
||||
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEtWqvQh7OdXrdgXcDeBMRVfLWTW3F\n"
|
||||
"wByeoVJFBfZymScJIJl46j66xG6ngnyj4ai4/QPFnSZ1I9jjMRlTWC4EPA==\n"
|
||||
"-----END PUBLIC KEY-----\n";
|
||||
std::string const stagenet_public_key = "-----BEGIN PUBLIC KEY-----\n"
|
||||
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEtWqvQh7OdXrdgXcDeBMRVfLWTW3F\n"
|
||||
"wByeoVJFBfZymScJIJl46j66xG6ngnyj4ai4/QPFnSZ1I9jjMRlTWC4EPA==\n"
|
||||
"-----END PUBLIC KEY-----\n";
|
||||
|
||||
// Comment out all but 1 of the following lines to select the correct Oracle PK
|
||||
std::string const public_key = mainnet_public_key;
|
||||
//std::string const public_key = testnet_public_key;
|
||||
//std::string const public_key = stagenet_public_key;
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(!public_key.empty(), "Pricing record verification failed. NULL public key. PK Size: " << public_key.size()); // TODO: is this necessary or the one below already covers this case, meannin it will produce empty pubkey?
|
||||
|
||||
// extract the key
|
||||
@@ -432,8 +409,27 @@ namespace offshore
|
||||
}
|
||||
}
|
||||
|
||||
// Oracle public keys
|
||||
std::string const mainnet_public_key = "-----BEGIN PUBLIC KEY-----\n"
|
||||
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5YBxWx1AZCA9jTUk8Pr2uZ9jpfRt\n"
|
||||
"KWv3Vo1/Gny+1vfaxsXhBQiG1KlHkafNGarzoL0WHW4ocqaaqF5iv8i35A==\n"
|
||||
"-----END PUBLIC KEY-----\n";
|
||||
std::string const testnet_public_key = "-----BEGIN PUBLIC KEY-----\n"
|
||||
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEtWqvQh7OdXrdgXcDeBMRVfLWTW3F\n"
|
||||
"wByeoVJFBfZymScJIJl46j66xG6ngnyj4ai4/QPFnSZ1I9jjMRlTWC4EPA==\n"
|
||||
"-----END PUBLIC KEY-----\n";
|
||||
std::string const stagenet_public_key = "-----BEGIN PUBLIC KEY-----\n"
|
||||
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEtWqvQh7OdXrdgXcDeBMRVfLWTW3F\n"
|
||||
"wByeoVJFBfZymScJIJl46j66xG6ngnyj4ai4/QPFnSZ1I9jjMRlTWC4EPA==\n"
|
||||
"-----END PUBLIC KEY-----\n";
|
||||
|
||||
// Comment out all but 1 of the following lines to select the correct Oracle PK
|
||||
std::string const public_key = mainnet_public_key;
|
||||
//std::string const public_key = testnet_public_key;
|
||||
//std::string const public_key = stagenet_public_key;
|
||||
|
||||
// verify the signature
|
||||
if (!verifySignature()) {
|
||||
if (!verifySignature(public_key)) {
|
||||
LOG_ERROR("Invalid pricing record signature.");
|
||||
return false;
|
||||
}
|
||||
@@ -453,4 +449,4 @@ namespace offshore
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -116,7 +116,7 @@ namespace offshore
|
||||
void set_for_height_821428();
|
||||
bool equal(const pricing_record& other) const noexcept;
|
||||
bool empty() const noexcept;
|
||||
bool verifySignature() const;
|
||||
bool verifySignature(const std::string& public_key) const;
|
||||
bool valid(uint32_t hf_version, uint64_t bl_timestamp, uint64_t last_bl_timestamp) const;
|
||||
|
||||
pricing_record& operator=(const pricing_record& orig) noexcept;
|
||||
|
||||
+307
-156
@@ -50,9 +50,9 @@ extern "C" {
|
||||
#include "span.h"
|
||||
#include "memwipe.h"
|
||||
#include "serialization/vector.h"
|
||||
#include "serialization/debug_archive.h"
|
||||
#include "serialization/binary_archive.h"
|
||||
#include "serialization/json_archive.h"
|
||||
|
||||
#include "cryptonote_protocol/enums.h"
|
||||
|
||||
|
||||
//Define this flag when debugging to get additional info on the console
|
||||
@@ -89,6 +89,18 @@ namespace rct {
|
||||
typedef std::vector<key> keyV; //vector of keys
|
||||
typedef std::vector<keyV> keyM; //matrix of keys (indexed by column first)
|
||||
|
||||
struct zk_proof {
|
||||
key R; // Commitment
|
||||
key z1; // Response
|
||||
key z2; // Response
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(R)
|
||||
FIELD(z1)
|
||||
FIELD(z2)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
//containers For CT operations
|
||||
//if it's representing a private ctkey then "dest" contains the secret key of the address
|
||||
// while "mask" contains a where C = aG + bH is CT pedersen commitment and b is the amount
|
||||
@@ -101,6 +113,22 @@ namespace rct {
|
||||
typedef std::vector<ctkey> ctkeyV;
|
||||
typedef std::vector<ctkeyV> ctkeyM;
|
||||
|
||||
struct carrot_ctkey {
|
||||
key x;
|
||||
key y;
|
||||
key mask; //C here if public
|
||||
|
||||
bool operator==(const carrot_ctkey &other) const {
|
||||
return (x == other.x) && (y == other.y) && (mask == other.mask);
|
||||
}
|
||||
|
||||
bool operator!=(const carrot_ctkey &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
typedef std::vector<carrot_ctkey> carrot_ctkeyV;
|
||||
typedef std::vector<carrot_ctkey> carrot_ctkeyM;
|
||||
|
||||
//used for multisig data
|
||||
struct multisig_kLRki {
|
||||
key k;
|
||||
@@ -149,12 +177,12 @@ namespace rct {
|
||||
key64 s1;
|
||||
key ee;
|
||||
};
|
||||
|
||||
|
||||
//Container for precomp
|
||||
struct geDsmp {
|
||||
ge_dsmp k;
|
||||
};
|
||||
|
||||
|
||||
//just contains the necessary keys to represent MLSAG sigs
|
||||
//c.f. https://eprint.iacr.org/2015/1098
|
||||
struct mgSig {
|
||||
@@ -185,6 +213,24 @@ namespace rct {
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
// TCLSAG signature
|
||||
struct tclsag {
|
||||
keyV sx; // x scalars(responses)
|
||||
keyV sy; // y scalars(responses)
|
||||
key c1;
|
||||
|
||||
key I; // signing key image
|
||||
key D; // commitment key image
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(sx)
|
||||
FIELD(sy)
|
||||
FIELD(c1)
|
||||
// FIELD(I) - not serialized, it can be reconstructed
|
||||
FIELD(D)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
//contains the data for an Borromean sig
|
||||
// also contains the "Ci" values such that
|
||||
// \sum Ci = C
|
||||
@@ -238,11 +284,48 @@ namespace rct {
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct BulletproofPlus
|
||||
{
|
||||
rct::keyV V;
|
||||
rct::key A, A1, B;
|
||||
rct::key r1, s1, d1;
|
||||
rct::keyV L, R;
|
||||
|
||||
BulletproofPlus() {}
|
||||
BulletproofPlus(const rct::key &V, const rct::key &A, const rct::key &A1, const rct::key &B, const rct::key &r1, const rct::key &s1, const rct::key &d1, const rct::keyV &L, const rct::keyV &R):
|
||||
V({V}), A(A), A1(A1), B(B), r1(r1), s1(s1), d1(d1), L(L), R(R) {}
|
||||
BulletproofPlus(const rct::keyV &V, const rct::key &A, const rct::key &A1, const rct::key &B, const rct::key &r1, const rct::key &s1, const rct::key &d1, const rct::keyV &L, const rct::keyV &R):
|
||||
V(V), A(A), A1(A1), B(B), r1(r1), s1(s1), d1(d1), L(L), R(R) {}
|
||||
|
||||
bool operator==(const BulletproofPlus &other) const { return V == other.V && A == other.A && A1 == other.A1 && B == other.B && r1 == other.r1 && s1 == other.s1 && d1 == other.d1 && L == other.L && R == other.R; }
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
// Commitments aren't saved, they're restored via outPk
|
||||
// FIELD(V)
|
||||
FIELD(A)
|
||||
FIELD(A1)
|
||||
FIELD(B)
|
||||
FIELD(r1)
|
||||
FIELD(s1)
|
||||
FIELD(d1)
|
||||
FIELD(L)
|
||||
FIELD(R)
|
||||
|
||||
if (L.empty() || L.size() != R.size())
|
||||
return false;
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
size_t n_bulletproof_amounts(const Bulletproof &proof);
|
||||
size_t n_bulletproof_max_amounts(const Bulletproof &proof);
|
||||
size_t n_bulletproof_amounts(const std::vector<Bulletproof> &proofs);
|
||||
size_t n_bulletproof_max_amounts(const std::vector<Bulletproof> &proofs);
|
||||
|
||||
size_t n_bulletproof_plus_amounts(const BulletproofPlus &proof);
|
||||
size_t n_bulletproof_plus_max_amounts(const BulletproofPlus &proof);
|
||||
size_t n_bulletproof_plus_amounts(const std::vector<BulletproofPlus> &proofs);
|
||||
size_t n_bulletproof_plus_max_amounts(const std::vector<BulletproofPlus> &proofs);
|
||||
|
||||
//A container to hold all signatures necessary for RingCT
|
||||
// rangeSigs holds all the rangeproof data of a transaction
|
||||
// MG holds the MLSAG signature of a transaction
|
||||
@@ -257,14 +340,67 @@ namespace rct {
|
||||
RCTTypeBulletproof = 3,
|
||||
RCTTypeBulletproof2 = 4,
|
||||
RCTTypeCLSAG = 5,
|
||||
RCTTypeCLSAGN = 6,
|
||||
RCTTypeHaven2 = 7, // Add public mask sum terms, remove extraneous fields (txnFee_usd,txnFee_xasset,txnOffshoreFee_usd,txnOffshoreFee_xasset)
|
||||
RCTTypeBulletproofPlus = 6,
|
||||
RCTTypeFullProofs = 7,
|
||||
RCTTypeSalviumZero = 8,
|
||||
RCTTypeSalviumOne = 9
|
||||
};
|
||||
enum RangeProofType { RangeProofBorromean, RangeProofBulletproof, RangeProofMultiOutputBulletproof, RangeProofPaddedBulletproof };
|
||||
struct RCTConfig {
|
||||
RangeProofType range_proof_type;
|
||||
int bp_version;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VERSION_FIELD(0)
|
||||
VARINT_FIELD(range_proof_type)
|
||||
VARINT_FIELD(bp_version)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
enum SalviumDataType { SalviumZero=0, SalviumZeroAudit=1, SalviumOne=2 };
|
||||
struct salvium_input_data_t {
|
||||
crypto::key_derivation aR;
|
||||
xmr_amount amount;
|
||||
size_t i;
|
||||
uint8_t origin_tx_type;
|
||||
crypto::key_derivation aR_stake;
|
||||
size_t i_stake;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(aR)
|
||||
VARINT_FIELD(amount)
|
||||
VARINT_FIELD(i)
|
||||
VARINT_FIELD(origin_tx_type)
|
||||
if (origin_tx_type != cryptonote::salvium_transaction_type::UNSET) {
|
||||
FIELD(aR_stake)
|
||||
FIELD(i_stake)
|
||||
}
|
||||
END_SERIALIZE()
|
||||
};
|
||||
struct salvium_data_t {
|
||||
|
||||
uint8_t salvium_data_type; // flag to indicate what type of data is valid
|
||||
zk_proof pr_proof; // p_r
|
||||
zk_proof sa_proof; // spend authority proof
|
||||
zk_proof cz_proof; // change is zero proof
|
||||
std::vector<salvium_input_data_t> input_verification_data;
|
||||
crypto::public_key spend_pubkey;
|
||||
std::string enc_view_privkey_str;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD(salvium_data_type)
|
||||
FIELD(pr_proof)
|
||||
FIELD(sa_proof)
|
||||
if (salvium_data_type == SalviumZeroAudit)
|
||||
{
|
||||
FIELD(cz_proof)
|
||||
FIELD(input_verification_data)
|
||||
FIELD(spend_pubkey)
|
||||
FIELD(enc_view_privkey_str)
|
||||
}
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct rctSigBase {
|
||||
uint8_t type;
|
||||
key message;
|
||||
@@ -273,15 +409,15 @@ namespace rct {
|
||||
keyV pseudoOuts; //C - for simple rct
|
||||
std::vector<ecdhTuple> ecdhInfo;
|
||||
ctkeyV outPk;
|
||||
ctkeyV outPk_usd;
|
||||
ctkeyV outPk_xasset;
|
||||
xmr_amount txnFee = 0; // contains b
|
||||
xmr_amount txnFee_usd = 0;
|
||||
xmr_amount txnFee_xasset = 0;
|
||||
xmr_amount txnOffshoreFee = 0;
|
||||
xmr_amount txnOffshoreFee_usd = 0;
|
||||
xmr_amount txnOffshoreFee_xasset = 0;
|
||||
keyV maskSums; // contains 2 elements. 1. is the sum of masks of inputs. 2. is the sum of masks of changes.
|
||||
key p_r;
|
||||
zk_proof pr_proof; // p_r
|
||||
zk_proof sa_proof; // spend authority proof
|
||||
salvium_data_t salvium_data;
|
||||
|
||||
rctSigBase() :
|
||||
type(RCTTypeNull), message{}, mixRing{}, pseudoOuts{}, ecdhInfo{}, outPk{}, txnFee(0), p_r{}, pr_proof{}, sa_proof{}
|
||||
{}
|
||||
|
||||
template<bool W, template <bool> class Archive>
|
||||
bool serialize_rctsig_base(Archive<W> &ar, size_t inputs, size_t outputs)
|
||||
@@ -289,50 +425,12 @@ namespace rct {
|
||||
FIELD(type)
|
||||
if (type == RCTTypeNull)
|
||||
return ar.stream().good();
|
||||
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG && type != RCTTypeCLSAGN && type != RCTTypeHaven2)
|
||||
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG && type != RCTTypeBulletproofPlus && type != RCTTypeFullProofs && type != RCTTypeSalviumZero && type != RCTTypeSalviumOne)
|
||||
return false;
|
||||
VARINT_FIELD(txnFee)
|
||||
if (type == RCTTypeHaven2) {
|
||||
// serialize offshore fee
|
||||
VARINT_FIELD(txnOffshoreFee)
|
||||
} else if (type == RCTTypeCLSAG || type == RCTTypeCLSAGN) {
|
||||
VARINT_FIELD(txnFee_usd)
|
||||
if (type == RCTTypeCLSAGN)
|
||||
{
|
||||
VARINT_FIELD(txnFee_xasset)
|
||||
}
|
||||
VARINT_FIELD(txnOffshoreFee)
|
||||
VARINT_FIELD(txnOffshoreFee_usd)
|
||||
if (type == RCTTypeCLSAGN)
|
||||
{
|
||||
VARINT_FIELD(txnOffshoreFee_xasset)
|
||||
}
|
||||
} else {
|
||||
txnFee_usd = 0;
|
||||
txnFee_xasset = 0;
|
||||
txnOffshoreFee = 0;
|
||||
txnOffshoreFee_usd = 0;
|
||||
txnOffshoreFee_xasset = 0;
|
||||
}
|
||||
// inputs/outputs not saved, only here for serialization help
|
||||
// FIELD(message) - not serialized, it can be reconstructed
|
||||
// FIELD(mixRing) - not serialized, it can be reconstructed
|
||||
if (type == RCTTypeSimple) // moved to prunable with bulletproofs
|
||||
{
|
||||
ar.tag("pseudoOuts");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(inputs, pseudoOuts);
|
||||
if (pseudoOuts.size() != inputs)
|
||||
return false;
|
||||
for (size_t i = 0; i < inputs; ++i)
|
||||
{
|
||||
FIELDS(pseudoOuts[i])
|
||||
if (inputs - i > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
}
|
||||
|
||||
ar.tag("ecdhInfo");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, ecdhInfo);
|
||||
@@ -340,21 +438,23 @@ namespace rct {
|
||||
return false;
|
||||
for (size_t i = 0; i < outputs; ++i)
|
||||
{
|
||||
if (type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeCLSAGN || type == RCTTypeHaven2)
|
||||
{
|
||||
ar.begin_object();
|
||||
if (!typename Archive<W>::is_saving())
|
||||
memset(ecdhInfo[i].amount.bytes, 0, sizeof(ecdhInfo[i].amount.bytes));
|
||||
crypto::hash8 &amount = (crypto::hash8&)ecdhInfo[i].amount;
|
||||
FIELD(amount);
|
||||
ar.end_object();
|
||||
}
|
||||
else
|
||||
{
|
||||
FIELDS(ecdhInfo[i])
|
||||
}
|
||||
if (outputs - i > 1)
|
||||
ar.delimit_array();
|
||||
if (type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs || type == RCTTypeSalviumZero || type == RCTTypeSalviumOne)
|
||||
{
|
||||
// Since RCTTypeBulletproof2 enote types, we don't serialize the blinding factor, and only serialize the
|
||||
// first 8 bytes of ecdhInfo[i].amount
|
||||
ar.begin_object();
|
||||
if (!typename Archive<W>::is_saving())
|
||||
memset(ecdhInfo[i].amount.bytes, 0, sizeof(ecdhInfo[i].amount.bytes));
|
||||
crypto::hash8 &amount = (crypto::hash8&)ecdhInfo[i].amount;
|
||||
FIELD(amount);
|
||||
ar.end_object();
|
||||
}
|
||||
else
|
||||
{
|
||||
FIELDS(ecdhInfo[i])
|
||||
}
|
||||
if (outputs - i > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
|
||||
@@ -366,78 +466,89 @@ namespace rct {
|
||||
for (size_t i = 0; i < outputs; ++i)
|
||||
{
|
||||
FIELDS(outPk[i].mask)
|
||||
if (outputs - i > 1)
|
||||
ar.delimit_array();
|
||||
if (outputs - i > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
|
||||
if (type == RCTTypeHaven2) {
|
||||
|
||||
ar.tag("maskSums");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(2, maskSums);
|
||||
if (maskSums.size() != 2)
|
||||
return false;
|
||||
FIELDS(maskSums[0])
|
||||
ar.delimit_array();
|
||||
FIELDS(maskSums[1])
|
||||
ar.end_array();
|
||||
|
||||
} else {
|
||||
|
||||
if ((type == RCTTypeCLSAG) || (type == RCTTypeCLSAGN))
|
||||
{
|
||||
ar.tag("outPk_usd");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, outPk_usd);
|
||||
if (outPk_usd.size() != outputs)
|
||||
return false;
|
||||
for (size_t i = 0; i < outputs; ++i)
|
||||
{
|
||||
FIELDS(outPk_usd[i].mask)
|
||||
if (outputs - i > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
}
|
||||
if (type == RCTTypeCLSAGN)
|
||||
{
|
||||
ar.tag("outPk_xasset");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, outPk_xasset);
|
||||
if (outPk_xasset.size() != outputs)
|
||||
return false;
|
||||
for (size_t i = 0; i < outputs; ++i)
|
||||
{
|
||||
FIELDS(outPk_xasset[i].mask)
|
||||
if (outputs - i > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
}
|
||||
FIELD(p_r)
|
||||
if (type == RCTTypeSalviumZero || type == RCTTypeSalviumOne)
|
||||
{
|
||||
FIELD(salvium_data)
|
||||
}
|
||||
else if (type == RCTTypeFullProofs)
|
||||
{
|
||||
FIELD(pr_proof)
|
||||
FIELD(sa_proof)
|
||||
}
|
||||
return ar.stream().good();
|
||||
}
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(type)
|
||||
FIELD(message)
|
||||
FIELD(mixRing)
|
||||
FIELD(pseudoOuts)
|
||||
FIELD(ecdhInfo)
|
||||
FIELD(outPk)
|
||||
VARINT_FIELD(txnFee)
|
||||
FIELD(p_r)
|
||||
if (type == RCTTypeSalviumZero || type == RCTTypeSalviumOne)
|
||||
{
|
||||
FIELD(salvium_data)
|
||||
}
|
||||
else if (type == RCTTypeFullProofs) {
|
||||
FIELD(pr_proof)
|
||||
FIELD(sa_proof)
|
||||
}
|
||||
END_SERIALIZE()
|
||||
};
|
||||
struct rctSigPrunable {
|
||||
std::vector<rangeSig> rangeSigs;
|
||||
std::vector<Bulletproof> bulletproofs;
|
||||
std::vector<BulletproofPlus> bulletproofs_plus;
|
||||
std::vector<mgSig> MGs; // simple rct has N, full has 1
|
||||
std::vector<clsag> CLSAGs;
|
||||
std::vector<tclsag> TCLSAGs;
|
||||
keyV pseudoOuts; //C - for simple rct
|
||||
|
||||
// when changing this function, update cryptonote::get_pruned_transaction_weight
|
||||
template<bool W, template <bool> class Archive>
|
||||
bool serialize_rctsig_prunable(Archive<W> &ar, uint8_t type, size_t inputs, size_t outputs, size_t mixin)
|
||||
{
|
||||
if (inputs >= 0xffffffff)
|
||||
return false;
|
||||
if (outputs >= 0xffffffff)
|
||||
return false;
|
||||
if (mixin >= 0xffffffff)
|
||||
return false;
|
||||
if (type == RCTTypeNull)
|
||||
return ar.stream().good();
|
||||
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG && type != RCTTypeCLSAGN && type != RCTTypeHaven2)
|
||||
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG && type != RCTTypeBulletproofPlus && type != RCTTypeFullProofs && type != RCTTypeSalviumZero && type != RCTTypeSalviumOne)
|
||||
return false;
|
||||
if (type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeCLSAGN || type == RCTTypeHaven2)
|
||||
if (type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs || type == RCTTypeSalviumZero || type == RCTTypeSalviumOne)
|
||||
{
|
||||
uint32_t nbp = bulletproofs_plus.size();
|
||||
VARINT_FIELD(nbp)
|
||||
ar.tag("bpp");
|
||||
ar.begin_array();
|
||||
if (nbp > outputs)
|
||||
return false;
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(nbp, bulletproofs_plus);
|
||||
for (size_t i = 0; i < nbp; ++i)
|
||||
{
|
||||
FIELDS(bulletproofs_plus[i])
|
||||
if (nbp - i > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
if (n_bulletproof_plus_max_amounts(bulletproofs_plus) < outputs)
|
||||
return false;
|
||||
ar.end_array();
|
||||
}
|
||||
else if (type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG)
|
||||
{
|
||||
uint32_t nbp = bulletproofs.size();
|
||||
if (type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeCLSAGN || type == RCTTypeHaven2)
|
||||
if (type == RCTTypeBulletproof2 || type == RCTTypeCLSAG)
|
||||
VARINT_FIELD(nbp)
|
||||
else
|
||||
FIELD(nbp)
|
||||
@@ -472,7 +583,60 @@ namespace rct {
|
||||
ar.end_array();
|
||||
}
|
||||
|
||||
if ((type == RCTTypeCLSAG) || (type == RCTTypeCLSAGN) || (type == RCTTypeHaven2))
|
||||
if (type == RCTTypeSalviumOne)
|
||||
{
|
||||
ar.tag("TCLSAGs");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(inputs, TCLSAGs);
|
||||
if (TCLSAGs.size() != inputs)
|
||||
return false;
|
||||
for (size_t i = 0; i < inputs; ++i)
|
||||
{
|
||||
// we save the TCLSAGs contents directly, because we want it to save its
|
||||
// arrays without the size prefixes, and the load can't know what size
|
||||
// to expect if it's not in the data
|
||||
ar.begin_object();
|
||||
ar.tag("sx");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mixin + 1, TCLSAGs[i].sx);
|
||||
if (TCLSAGs[i].sx.size() != mixin + 1)
|
||||
return false;
|
||||
for (size_t j = 0; j <= mixin; ++j)
|
||||
{
|
||||
FIELDS(TCLSAGs[i].sx[j])
|
||||
if (mixin + 1 - j > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
|
||||
ar.tag("sy");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mixin + 1, TCLSAGs[i].sy);
|
||||
if (TCLSAGs[i].sy.size() != mixin + 1)
|
||||
return false;
|
||||
for (size_t j = 0; j <= mixin; ++j)
|
||||
{
|
||||
FIELDS(TCLSAGs[i].sy[j])
|
||||
if (mixin + 1 - j > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
|
||||
ar.tag("c1");
|
||||
FIELDS(TCLSAGs[i].c1)
|
||||
|
||||
// CLSAGs[i].I not saved, it can be reconstructed
|
||||
ar.tag("D");
|
||||
FIELDS(TCLSAGs[i].D)
|
||||
ar.end_object();
|
||||
|
||||
if (inputs - i > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
|
||||
ar.end_array();
|
||||
|
||||
} else if (type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs || type == RCTTypeSalviumZero)
|
||||
{
|
||||
ar.tag("CLSAGs");
|
||||
ar.begin_array();
|
||||
@@ -547,7 +711,7 @@ namespace rct {
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
|
||||
|
||||
if (mixin + 1 - j > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
@@ -563,7 +727,7 @@ namespace rct {
|
||||
}
|
||||
ar.end_array();
|
||||
}
|
||||
if (type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeCLSAGN || type == RCTTypeHaven2)
|
||||
if (type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs || type == RCTTypeSalviumZero || type == RCTTypeSalviumOne)
|
||||
{
|
||||
ar.tag("pseudoOuts");
|
||||
ar.begin_array();
|
||||
@@ -581,19 +745,33 @@ namespace rct {
|
||||
return ar.stream().good();
|
||||
}
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(rangeSigs)
|
||||
FIELD(bulletproofs)
|
||||
FIELD(bulletproofs_plus)
|
||||
FIELD(MGs)
|
||||
FIELD(CLSAGs)
|
||||
FIELD(TCLSAGs)
|
||||
FIELD(pseudoOuts)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
struct rctSig: public rctSigBase {
|
||||
rctSigPrunable p;
|
||||
|
||||
keyV& get_pseudo_outs()
|
||||
{
|
||||
return type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeCLSAGN || type == RCTTypeHaven2 ? p.pseudoOuts : pseudoOuts;
|
||||
return type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs || type == RCTTypeSalviumZero || type == RCTTypeSalviumOne ? p.pseudoOuts : pseudoOuts;
|
||||
}
|
||||
|
||||
keyV const& get_pseudo_outs() const
|
||||
{
|
||||
return type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeCLSAGN || type == RCTTypeHaven2 ? p.pseudoOuts : pseudoOuts;
|
||||
return type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs || type == RCTTypeSalviumZero || type == RCTTypeSalviumOne ? p.pseudoOuts : pseudoOuts;
|
||||
}
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELDS((rctSigBase&)*this)
|
||||
FIELD(p)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
//other basepoint H = toPoint(cn_fast_hash(G)), G the basepoint
|
||||
@@ -699,7 +877,9 @@ namespace rct {
|
||||
|
||||
bool is_rct_simple(int type);
|
||||
bool is_rct_bulletproof(int type);
|
||||
bool is_rct_bulletproof_plus(int type);
|
||||
bool is_rct_borromean(int type);
|
||||
bool is_rct_clsag(int type);
|
||||
|
||||
static inline const rct::key &pk2rct(const crypto::public_key &pk) { return (const rct::key&)pk; }
|
||||
static inline const rct::key &sk2rct(const crypto::secret_key &sk) { return (const rct::key&)sk; }
|
||||
@@ -739,23 +919,6 @@ BLOB_SERIALIZER(rct::ctkey);
|
||||
BLOB_SERIALIZER(rct::multisig_kLRki);
|
||||
BLOB_SERIALIZER(rct::boroSig);
|
||||
|
||||
VARIANT_TAG(debug_archive, rct::key, "rct::key");
|
||||
VARIANT_TAG(debug_archive, rct::key64, "rct::key64");
|
||||
VARIANT_TAG(debug_archive, rct::keyV, "rct::keyV");
|
||||
VARIANT_TAG(debug_archive, rct::keyM, "rct::keyM");
|
||||
VARIANT_TAG(debug_archive, rct::ctkey, "rct::ctkey");
|
||||
VARIANT_TAG(debug_archive, rct::ctkeyV, "rct::ctkeyV");
|
||||
VARIANT_TAG(debug_archive, rct::ctkeyM, "rct::ctkeyM");
|
||||
VARIANT_TAG(debug_archive, rct::ecdhTuple, "rct::ecdhTuple");
|
||||
VARIANT_TAG(debug_archive, rct::mgSig, "rct::mgSig");
|
||||
VARIANT_TAG(debug_archive, rct::rangeSig, "rct::rangeSig");
|
||||
VARIANT_TAG(debug_archive, rct::boroSig, "rct::boroSig");
|
||||
VARIANT_TAG(debug_archive, rct::rctSig, "rct::rctSig");
|
||||
VARIANT_TAG(debug_archive, rct::Bulletproof, "rct::bulletproof");
|
||||
VARIANT_TAG(debug_archive, rct::multisig_kLRki, "rct::multisig_kLRki");
|
||||
VARIANT_TAG(debug_archive, rct::multisig_out, "rct::multisig_out");
|
||||
VARIANT_TAG(debug_archive, rct::clsag, "rct::clsag");
|
||||
|
||||
VARIANT_TAG(binary_archive, rct::key, 0x90);
|
||||
VARIANT_TAG(binary_archive, rct::key64, 0x91);
|
||||
VARIANT_TAG(binary_archive, rct::keyV, 0x92);
|
||||
@@ -772,22 +935,10 @@ VARIANT_TAG(binary_archive, rct::Bulletproof, 0x9c);
|
||||
VARIANT_TAG(binary_archive, rct::multisig_kLRki, 0x9d);
|
||||
VARIANT_TAG(binary_archive, rct::multisig_out, 0x9e);
|
||||
VARIANT_TAG(binary_archive, rct::clsag, 0x9f);
|
||||
|
||||
VARIANT_TAG(json_archive, rct::key, "rct_key");
|
||||
VARIANT_TAG(json_archive, rct::key64, "rct_key64");
|
||||
VARIANT_TAG(json_archive, rct::keyV, "rct_keyV");
|
||||
VARIANT_TAG(json_archive, rct::keyM, "rct_keyM");
|
||||
VARIANT_TAG(json_archive, rct::ctkey, "rct_ctkey");
|
||||
VARIANT_TAG(json_archive, rct::ctkeyV, "rct_ctkeyV");
|
||||
VARIANT_TAG(json_archive, rct::ctkeyM, "rct_ctkeyM");
|
||||
VARIANT_TAG(json_archive, rct::ecdhTuple, "rct_ecdhTuple");
|
||||
VARIANT_TAG(json_archive, rct::mgSig, "rct_mgSig");
|
||||
VARIANT_TAG(json_archive, rct::rangeSig, "rct_rangeSig");
|
||||
VARIANT_TAG(json_archive, rct::boroSig, "rct_boroSig");
|
||||
VARIANT_TAG(json_archive, rct::rctSig, "rct_rctSig");
|
||||
VARIANT_TAG(json_archive, rct::Bulletproof, "rct_bulletproof");
|
||||
VARIANT_TAG(json_archive, rct::multisig_kLRki, "rct_multisig_kLR");
|
||||
VARIANT_TAG(json_archive, rct::multisig_out, "rct_multisig_out");
|
||||
VARIANT_TAG(json_archive, rct::clsag, "rct_clsag");
|
||||
VARIANT_TAG(binary_archive, rct::BulletproofPlus, 0xa0);
|
||||
VARIANT_TAG(binary_archive, rct::zk_proof, 0xa1);
|
||||
VARIANT_TAG(binary_archive, rct::salvium_input_data_t, 0xa2);
|
||||
VARIANT_TAG(binary_archive, rct::salvium_data_t, 0xa3);
|
||||
VARIANT_TAG(binary_archive, rct::tclsag, 0xa4);
|
||||
|
||||
#endif /* RCTTYPES_H */
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
// Copyright (c) 2021, Haven Protocol
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace salvium_oracle {
|
||||
|
||||
const std::vector<std::string> ASSET_TYPES = {"SAL", "VSD", "BURN"};
|
||||
|
||||
class asset_type_counts
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
// Fields
|
||||
uint64_t SAL;
|
||||
uint64_t VSD;
|
||||
uint64_t BURN;
|
||||
|
||||
asset_type_counts() noexcept
|
||||
: SAL(0)
|
||||
, VSD(0)
|
||||
, BURN(0)
|
||||
{
|
||||
}
|
||||
|
||||
uint64_t operator[](const std::string asset_type) const noexcept
|
||||
{
|
||||
if (asset_type == "SAL") {
|
||||
return SAL;
|
||||
} else if (asset_type == "VSD") {
|
||||
return VSD;
|
||||
} else if (asset_type == "BURN") {
|
||||
return BURN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void add(const std::string asset_type, const uint64_t val)
|
||||
{
|
||||
if (asset_type == "SAL") {
|
||||
SAL += val;
|
||||
} else if (asset_type == "VSD") {
|
||||
VSD += val;
|
||||
} else if (asset_type == "BURN") {
|
||||
BURN += val;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
// Copyright (c) 2019, Haven Protocol
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Portions of this code based upon code Copyright (c) 2019, The Monero Project
|
||||
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
#include "pricing_record.h"
|
||||
|
||||
#include "serialization/keyvalue_serialization.h"
|
||||
#include "storages/portable_storage.h"
|
||||
|
||||
#include "string_tools.h"
|
||||
namespace salvium_oracle
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
struct asset_data_serialized
|
||||
{
|
||||
std::string asset_type;
|
||||
uint64_t spot_price;
|
||||
uint64_t ma_price;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(asset_type)
|
||||
KV_SERIALIZE(spot_price)
|
||||
KV_SERIALIZE(ma_price)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct supply_data_serialized
|
||||
{
|
||||
uint64_t SAL;
|
||||
uint64_t VSD;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(SAL)
|
||||
KV_SERIALIZE(VSD)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct pr_serialized
|
||||
{
|
||||
uint64_t pr_version;
|
||||
uint64_t height;
|
||||
supply_data supply;
|
||||
std::vector<asset_data> assets;
|
||||
uint64_t timestamp;
|
||||
std::string signature;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(pr_version)
|
||||
KV_SERIALIZE(height)
|
||||
KV_SERIALIZE(supply)
|
||||
KV_SERIALIZE(assets)
|
||||
KV_SERIALIZE(timestamp)
|
||||
KV_SERIALIZE(signature)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
}
|
||||
|
||||
pricing_record::pricing_record() noexcept
|
||||
: pr_version(0)
|
||||
, height(0)
|
||||
, supply()
|
||||
, assets()
|
||||
, timestamp(0)
|
||||
, signature()
|
||||
{
|
||||
}
|
||||
|
||||
pricing_record::~pricing_record() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
bool supply_data::_load(epee::serialization::portable_storage& src, epee::serialization::section* hparent)
|
||||
{
|
||||
supply_data_serialized in{};
|
||||
if (in._load(src, hparent))
|
||||
{
|
||||
// Copy everything into the local instance
|
||||
sal = in.SAL;
|
||||
vsd = in.VSD;
|
||||
return true;
|
||||
}
|
||||
// Report error here?
|
||||
return false;
|
||||
}
|
||||
|
||||
bool supply_data::store(epee::serialization::portable_storage& dest, epee::serialization::section* hparent) const
|
||||
{
|
||||
const supply_data_serialized out{sal, vsd};
|
||||
return out.store(dest, hparent);
|
||||
}
|
||||
|
||||
bool asset_data::_load(epee::serialization::portable_storage& src, epee::serialization::section* hparent)
|
||||
{
|
||||
asset_data_serialized in{};
|
||||
if (in._load(src, hparent))
|
||||
{
|
||||
// Copy everything into the local instance
|
||||
asset_type = in.asset_type;
|
||||
spot_price = in.spot_price;
|
||||
ma_price = in.ma_price;
|
||||
return true;
|
||||
}
|
||||
// Report error here?
|
||||
return false;
|
||||
}
|
||||
|
||||
bool asset_data::store(epee::serialization::portable_storage& dest, epee::serialization::section* hparent) const
|
||||
{
|
||||
const asset_data_serialized out{asset_type, spot_price, ma_price};
|
||||
return out.store(dest, hparent);
|
||||
}
|
||||
|
||||
bool pricing_record::_load(epee::serialization::portable_storage& src, epee::serialization::section* hparent)
|
||||
{
|
||||
pr_serialized in{};
|
||||
if (in._load(src, hparent))
|
||||
{
|
||||
// Copy everything into the local instance
|
||||
pr_version = in.pr_version;
|
||||
height = in.height;
|
||||
supply = in.supply;
|
||||
assets = in.assets;
|
||||
timestamp = in.timestamp;
|
||||
|
||||
// Signature arrives in HEX format, but needs to be used in BINARY format - convert it here
|
||||
signature.resize(0);
|
||||
assert(in.signature.size()%2 == 0);
|
||||
signature.reserve(in.signature.size() >> 1);
|
||||
for (unsigned int i = 0; i < in.signature.size(); i += 2) {
|
||||
std::string byteString = in.signature.substr(i, 2);
|
||||
signature.emplace_back((uint8_t)strtol(byteString.c_str(), NULL, 16));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Report error here?
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pricing_record::store(epee::serialization::portable_storage& dest, epee::serialization::section* hparent) const
|
||||
{
|
||||
std::string sig_hex;
|
||||
for (size_t i=0; i<signature.size(); ++i) {
|
||||
std::stringstream ss;
|
||||
ss << std::hex << std::setw(2) << std::setfill('0') << (0xff & signature.at(i));
|
||||
sig_hex += ss.str();
|
||||
}
|
||||
const pr_serialized out{pr_version, height, supply, assets, timestamp, sig_hex};
|
||||
return out.store(dest, hparent);
|
||||
}
|
||||
|
||||
pricing_record::pricing_record(const pricing_record& orig) noexcept
|
||||
: pr_version(orig.pr_version)
|
||||
, height(orig.height)
|
||||
, supply(orig.supply)
|
||||
, assets(orig.assets)
|
||||
, timestamp(orig.timestamp)
|
||||
, signature(orig.signature)
|
||||
{
|
||||
}
|
||||
|
||||
pricing_record& pricing_record::operator=(const pricing_record& orig) noexcept
|
||||
{
|
||||
pr_version = orig.pr_version;
|
||||
height = orig.height;
|
||||
supply = orig.supply;
|
||||
assets = orig.assets;
|
||||
timestamp = orig.timestamp;
|
||||
signature = orig.signature;
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint64_t pricing_record::operator[](const std::string& asset_type) const
|
||||
{
|
||||
for (const auto& asset: assets) {
|
||||
if (asset.asset_type != asset_type) continue;
|
||||
return asset.spot_price;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool pricing_record::equal(const pricing_record& other) const noexcept
|
||||
{
|
||||
return ((pr_version == other.pr_version) &&
|
||||
(height == other.height) &&
|
||||
(supply == other.supply) &&
|
||||
(assets == other.assets) &&
|
||||
(timestamp == other.timestamp) &&
|
||||
(signature == other.signature));
|
||||
}
|
||||
|
||||
bool pricing_record::empty() const noexcept
|
||||
{
|
||||
const pricing_record empty_pr = salvium_oracle::pricing_record();
|
||||
return (*this).equal(empty_pr);
|
||||
}
|
||||
|
||||
// overload for pr validation for block
|
||||
bool pricing_record::valid(uint32_t hf_version, uint64_t bl_timestamp, uint64_t last_bl_timestamp) const
|
||||
{
|
||||
if (this->empty())
|
||||
return true;
|
||||
|
||||
// validate the timestmap
|
||||
if (this->timestamp > bl_timestamp + PRICING_RECORD_VALID_TIME_DIFF_FROM_BLOCK) {
|
||||
LOG_ERROR("Pricing record timestamp is too far in the future.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->timestamp <= last_bl_timestamp) {
|
||||
LOG_ERROR("Pricing record timestamp: " << this->timestamp << ", block timestamp: " << bl_timestamp);
|
||||
LOG_ERROR("Pricing record timestamp is too old.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
// Copyright (c) 2019, Haven Protocol
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Portions of this code based upon code Copyright (c) 2019, The Monero Project
|
||||
|
||||
#pragma once
|
||||
#include "common/pod-class.h"
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/ecdsa.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include "serialization/vector.h"
|
||||
|
||||
#include "cryptonote_config.h"
|
||||
#include "crypto/hash.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
class portable_storage;
|
||||
struct section;
|
||||
}
|
||||
}
|
||||
|
||||
namespace salvium_oracle
|
||||
{
|
||||
#pragma pack(push, 1)
|
||||
POD_CLASS pricing_record_pre {
|
||||
uint64_t pr_version;
|
||||
uint64_t price;
|
||||
uint64_t timestamp;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
struct supply_data {
|
||||
uint64_t sal;
|
||||
uint64_t vsd;
|
||||
|
||||
//! Load from epee p2p format
|
||||
bool _load(epee::serialization::portable_storage& src, epee::serialization::section* hparent);
|
||||
//! Store in epee p2p format
|
||||
bool store(epee::serialization::portable_storage& dest, epee::serialization::section* hparent) const;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD(sal)
|
||||
VARINT_FIELD(vsd)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
inline bool operator==(const supply_data& a, const supply_data& b) noexcept
|
||||
{
|
||||
return (a.sal == b.sal &&
|
||||
a.vsd == b.vsd);
|
||||
}
|
||||
|
||||
struct asset_data {
|
||||
std::string asset_type;
|
||||
uint64_t spot_price;
|
||||
uint64_t ma_price;
|
||||
|
||||
//! Load from epee p2p format
|
||||
bool _load(epee::serialization::portable_storage& src, epee::serialization::section* hparent);
|
||||
//! Store in epee p2p format
|
||||
bool store(epee::serialization::portable_storage& dest, epee::serialization::section* hparent) const;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(asset_type)
|
||||
VARINT_FIELD(spot_price)
|
||||
VARINT_FIELD(ma_price)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
inline bool operator==(const asset_data& a, const asset_data& b) noexcept
|
||||
{
|
||||
return (a.asset_type == b.asset_type &&
|
||||
a.spot_price == b.spot_price &&
|
||||
a.ma_price == b.ma_price);
|
||||
}
|
||||
|
||||
struct pricing_record
|
||||
{
|
||||
// Fields
|
||||
uint64_t pr_version;
|
||||
uint64_t height;
|
||||
supply_data supply;
|
||||
std::vector<asset_data> assets;
|
||||
uint64_t timestamp;
|
||||
std::vector<uint8_t> signature;
|
||||
|
||||
// Default c'tor
|
||||
pricing_record() noexcept;
|
||||
//! Load from epee p2p format
|
||||
bool _load(epee::serialization::portable_storage& src, epee::serialization::section* hparent);
|
||||
//! Store in epee p2p format
|
||||
bool store(epee::serialization::portable_storage& dest, epee::serialization::section* hparent) const;
|
||||
pricing_record(const pricing_record& orig) noexcept;
|
||||
~pricing_record() noexcept;
|
||||
bool equal(const pricing_record& other) const noexcept;
|
||||
bool empty() const noexcept;
|
||||
bool valid(uint32_t hf_version, uint64_t bl_timestamp, uint64_t last_bl_timestamp) const;
|
||||
|
||||
pricing_record& operator=(const pricing_record& orig) noexcept;
|
||||
uint64_t operator[](const std::string& asset_type) const;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD(pr_version)
|
||||
VARINT_FIELD(height)
|
||||
FIELD(supply)
|
||||
FIELD(assets)
|
||||
VARINT_FIELD(timestamp)
|
||||
FIELD(signature)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
inline bool operator==(const pricing_record& a, const pricing_record& b) noexcept
|
||||
{
|
||||
return a.equal(b);
|
||||
}
|
||||
|
||||
inline bool operator!=(const pricing_record& a, const pricing_record& b) noexcept
|
||||
{
|
||||
return !a.equal(b);
|
||||
}
|
||||
|
||||
} // salvium_oracle
|
||||
@@ -48,7 +48,7 @@ template <>
|
||||
struct binary_archive<false> : public binary_archive_base<std::istream, false>
|
||||
{
|
||||
explicit binary_archive(stream_type &s) : base_type(s) {
|
||||
stream_type::streampos pos = stream_.tellg();
|
||||
auto pos = stream_.tellg();
|
||||
stream_.seekg(0, std::ios_base::end);
|
||||
eof_pos_ = stream_.tellg();
|
||||
stream_.seekg(pos);
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
#include <vector>
|
||||
|
||||
#include "serialization.h"
|
||||
#include "debug_archive.h"
|
||||
#include "crypto/chacha8.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "carrot_core/core_types.h"
|
||||
|
||||
// read
|
||||
template <template <bool> class Archive>
|
||||
@@ -62,13 +62,6 @@ BLOB_SERIALIZER(crypto::secret_key);
|
||||
BLOB_SERIALIZER(crypto::key_derivation);
|
||||
BLOB_SERIALIZER(crypto::key_image);
|
||||
BLOB_SERIALIZER(crypto::signature);
|
||||
VARIANT_TAG(debug_archive, crypto::cycle, "cycle");
|
||||
VARIANT_TAG(debug_archive, crypto::cycle40, "cycle40");
|
||||
VARIANT_TAG(debug_archive, crypto::cycle48, "cycle48");
|
||||
VARIANT_TAG(debug_archive, crypto::hash, "hash");
|
||||
VARIANT_TAG(debug_archive, crypto::hash8, "hash8");
|
||||
VARIANT_TAG(debug_archive, crypto::public_key, "public_key");
|
||||
VARIANT_TAG(debug_archive, crypto::secret_key, "secret_key");
|
||||
VARIANT_TAG(debug_archive, crypto::key_derivation, "key_derivation");
|
||||
VARIANT_TAG(debug_archive, crypto::key_image, "key_image");
|
||||
VARIANT_TAG(debug_archive, crypto::signature, "signature");
|
||||
BLOB_SERIALIZER(crypto::view_tag);
|
||||
BLOB_SERIALIZER(carrot::view_tag_t);
|
||||
BLOB_SERIALIZER(carrot::janus_anchor_t);
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "json_archive.h"
|
||||
#include "variant.h"
|
||||
|
||||
template <bool W>
|
||||
struct debug_archive : public json_archive<W> {
|
||||
typedef typename json_archive<W>::stream_type stream_type;
|
||||
|
||||
debug_archive(stream_type &s) : json_archive<W>(s) { }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct serializer<debug_archive<true>, T>
|
||||
{
|
||||
static void serialize(debug_archive<true> &ar, T &v)
|
||||
{
|
||||
ar.begin_object();
|
||||
ar.tag(variant_serialization_traits<debug_archive<true>, T>::get_tag());
|
||||
serializer<json_archive<true>, T>::serialize(ar, v);
|
||||
ar.end_object();
|
||||
ar.stream() << std::endl;
|
||||
}
|
||||
};
|
||||
@@ -1,145 +0,0 @@
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
/* json_archive.h
|
||||
*
|
||||
* JSON archive */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "serialization.h"
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
template <class Stream, bool IsSaving>
|
||||
struct json_archive_base
|
||||
{
|
||||
typedef Stream stream_type;
|
||||
typedef json_archive_base<Stream, IsSaving> base_type;
|
||||
typedef boost::mpl::bool_<IsSaving> is_saving;
|
||||
|
||||
typedef const char *variant_tag_type;
|
||||
|
||||
json_archive_base(stream_type &s, bool indent = false) : stream_(s), indent_(indent), object_begin(false), depth_(0) { }
|
||||
|
||||
void tag(const char *tag) {
|
||||
if (!object_begin)
|
||||
stream_ << ", ";
|
||||
make_indent();
|
||||
stream_ << '"' << tag << "\": ";
|
||||
object_begin = false;
|
||||
}
|
||||
|
||||
void begin_object()
|
||||
{
|
||||
stream_ << "{";
|
||||
++depth_;
|
||||
object_begin = true;
|
||||
}
|
||||
|
||||
void end_object()
|
||||
{
|
||||
--depth_;
|
||||
make_indent();
|
||||
stream_ << "}";
|
||||
}
|
||||
|
||||
void begin_variant() { begin_object(); }
|
||||
void end_variant() { end_object(); }
|
||||
Stream &stream() { return stream_; }
|
||||
|
||||
protected:
|
||||
void make_indent()
|
||||
{
|
||||
if (indent_)
|
||||
{
|
||||
stream_ << '\n' << std::string(2 * depth_, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
stream_type &stream_;
|
||||
bool indent_;
|
||||
bool object_begin;
|
||||
size_t depth_;
|
||||
};
|
||||
|
||||
template <bool W>
|
||||
struct json_archive;
|
||||
|
||||
template <>
|
||||
struct json_archive<true> : public json_archive_base<std::ostream, true>
|
||||
{
|
||||
json_archive(stream_type &s, bool indent = false) : base_type(s, indent) { }
|
||||
|
||||
template<typename T>
|
||||
static auto promote_to_printable_integer_type(T v) -> decltype(+v)
|
||||
{
|
||||
// Unary operator '+' performs integral promotion on type T [expr.unary.op].
|
||||
// If T is signed or unsigned char, it's promoted to int and printed as number.
|
||||
return +v;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void serialize_int(T v)
|
||||
{
|
||||
stream_ << std::dec << promote_to_printable_integer_type(v);
|
||||
}
|
||||
|
||||
void serialize_blob(void *buf, size_t len, const char *delimiter="\"") {
|
||||
begin_string(delimiter);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
unsigned char c = ((unsigned char *)buf)[i];
|
||||
stream_ << std::hex << std::setw(2) << std::setfill('0') << (int)c;
|
||||
}
|
||||
end_string(delimiter);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void serialize_varint(T &v)
|
||||
{
|
||||
stream_ << std::dec << promote_to_printable_integer_type(v);
|
||||
}
|
||||
|
||||
void begin_string(const char *delimiter="\"")
|
||||
{
|
||||
stream_ << delimiter;
|
||||
}
|
||||
|
||||
void end_string(const char *delimiter="\"")
|
||||
{
|
||||
stream_ << delimiter;
|
||||
}
|
||||
|
||||
void begin_array(size_t s=0)
|
||||
{
|
||||
inner_array_size_ = s;
|
||||
++depth_;
|
||||
stream_ << "[ ";
|
||||
}
|
||||
|
||||
void delimit_array()
|
||||
{
|
||||
stream_ << ", ";
|
||||
}
|
||||
|
||||
void end_array()
|
||||
{
|
||||
--depth_;
|
||||
if (0 < inner_array_size_)
|
||||
{
|
||||
make_indent();
|
||||
}
|
||||
stream_ << "]";
|
||||
}
|
||||
|
||||
void write_variant_tag(const char *t)
|
||||
{
|
||||
tag(t);
|
||||
}
|
||||
|
||||
private:
|
||||
size_t inner_array_size_;
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sstream>
|
||||
#include "json_archive.h"
|
||||
|
||||
namespace serialization {
|
||||
|
||||
template<class T>
|
||||
std::string dump_json(T &v)
|
||||
{
|
||||
std::stringstream ostr;
|
||||
json_archive<true> oar(ostr);
|
||||
assert(serialization::serialize(oar, v));
|
||||
return ostr.str();
|
||||
};
|
||||
|
||||
} // namespace serialization
|
||||
@@ -33,7 +33,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "serialization.h"
|
||||
#include "debug_archive.h"
|
||||
#include "offshore/pricing_record.h"
|
||||
#include "cryptonote_config.h"
|
||||
|
||||
|
||||
@@ -97,6 +97,29 @@ inline bool do_serialize(Archive &ar, bool &v)
|
||||
bool r = ::do_serialize(ar, f); \
|
||||
if (!r || !ar.stream().good()) return false; \
|
||||
} while(0);
|
||||
/*! \macro ENUM_FIELD(f, test)
|
||||
* \brief tags and serializes (as a varint) the scoped enum \a f with a requirement that expression\
|
||||
* \a test be true(typically for range testing).
|
||||
*/
|
||||
#define ENUM_FIELD(f, test) ENUM_FIELD_N(#f, f, test)
|
||||
/*! \macro ENUM_FIELD_N(t, f, begin, end)
|
||||
*
|
||||
* \brief tags (as \a t) and serializes (as a varint) the scoped enum \a f with a requirement that
|
||||
* expression \a test be true (typically for range testing).
|
||||
*/
|
||||
#define ENUM_FIELD_N(t, f, test) \
|
||||
do { \
|
||||
using enum_t = decltype(f); \
|
||||
using int_t = typename std::underlying_type<enum_t>::type; \
|
||||
int_t int_value = W ? static_cast<int_t>(f) : 0; \
|
||||
ar.tag(t); \
|
||||
ar.serialize_varint(int_value); \
|
||||
if(!ar.stream().good()) return false; \
|
||||
if(!W) { \
|
||||
f = static_cast<enum_t>(int_value); \
|
||||
if(!(test)) return false; \
|
||||
} \
|
||||
} while(0);
|
||||
#define VARINT_FIELD(f) \
|
||||
do { \
|
||||
ar.tag(#f); \
|
||||
@@ -109,6 +132,13 @@ inline bool do_serialize(Archive &ar, bool &v)
|
||||
ar.serialize_varint(f); \
|
||||
if (!ar.stream().good()) return false; \
|
||||
} while(0);
|
||||
#define VERSION_FIELD(v) \
|
||||
uint32_t version = v; \
|
||||
do { \
|
||||
ar.tag("version"); \
|
||||
ar.serialize_varint(version); \
|
||||
if (!ar.stream().good()) return false; \
|
||||
} while(0);
|
||||
|
||||
namespace serialization {
|
||||
namespace detail
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
// Copyright (c) 2019, Haven Protocol
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "serialization.h"
|
||||
#include "zephyr_oracle/pricing_record.h"
|
||||
#include "cryptonote_config.h"
|
||||
|
||||
// read
|
||||
template <template <bool> class Archive>
|
||||
bool do_serialize(Archive<false> &ar, zephyr_oracle::pricing_record &pr, uint8_t version)
|
||||
{
|
||||
|
||||
if (version >= 6)
|
||||
{
|
||||
// very basic sanity check
|
||||
if (ar.remaining_bytes() < sizeof(zephyr_oracle::pricing_record)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ar.serialize_blob(&pr, sizeof(zephyr_oracle::pricing_record), "");
|
||||
if (!ar.good())
|
||||
return false;
|
||||
}
|
||||
else if (version >= 4)
|
||||
{
|
||||
// very basic sanity check
|
||||
if (ar.remaining_bytes() < sizeof(zephyr_oracle::pricing_record_v3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
zephyr_oracle::pricing_record_v3 pr_v3;
|
||||
ar.serialize_blob(&pr_v3, sizeof(zephyr_oracle::pricing_record_v3), "");
|
||||
if (!ar.good())
|
||||
return false;
|
||||
|
||||
if (!pr_v3.write_to_pr(pr))
|
||||
return false;
|
||||
}
|
||||
else if (version >= 3)
|
||||
{
|
||||
// very basic sanity check
|
||||
if (ar.remaining_bytes() < sizeof(zephyr_oracle::pricing_record_v2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
zephyr_oracle::pricing_record_v2 pr_v2;
|
||||
ar.serialize_blob(&pr_v2, sizeof(zephyr_oracle::pricing_record_v2), "");
|
||||
if (!ar.good())
|
||||
return false;
|
||||
|
||||
if (!pr_v2.write_to_pr(pr))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// very basic sanity check
|
||||
if (ar.remaining_bytes() < sizeof(zephyr_oracle::pricing_record_v1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
zephyr_oracle::pricing_record_v1 pr_v1;
|
||||
ar.serialize_blob(&pr_v1, sizeof(zephyr_oracle::pricing_record_v1), "");
|
||||
if (!ar.good())
|
||||
return false;
|
||||
|
||||
if (!pr_v1.write_to_pr(pr))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// write
|
||||
template <template <bool> class Archive>
|
||||
bool do_serialize(Archive<true> &ar, zephyr_oracle::pricing_record &pr, uint8_t version)
|
||||
{
|
||||
ar.begin_string();
|
||||
|
||||
if (version >= 6)
|
||||
{
|
||||
ar.serialize_blob(&pr, sizeof(zephyr_oracle::pricing_record), "");
|
||||
}
|
||||
else if (version >= 4)
|
||||
{
|
||||
zephyr_oracle::pricing_record_v3 pr_v3;
|
||||
if (!pr_v3.read_from_pr(pr))
|
||||
return false;
|
||||
ar.serialize_blob(&pr_v3, sizeof(zephyr_oracle::pricing_record_v3), "");
|
||||
}
|
||||
else if (version >= 3)
|
||||
{
|
||||
zephyr_oracle::pricing_record_v2 pr_v2;
|
||||
if (!pr_v2.read_from_pr(pr))
|
||||
return false;
|
||||
ar.serialize_blob(&pr_v2, sizeof(zephyr_oracle::pricing_record_v2), "");
|
||||
}
|
||||
else
|
||||
{
|
||||
zephyr_oracle::pricing_record_v1 pr_v1;
|
||||
if (!pr_v1.read_from_pr(pr))
|
||||
return false;
|
||||
ar.serialize_blob(&pr_v1, sizeof(zephyr_oracle::pricing_record_v1), "");
|
||||
}
|
||||
|
||||
if (!ar.good())
|
||||
return false;
|
||||
ar.end_string();
|
||||
return true;
|
||||
}
|
||||
|
||||
// read
|
||||
template <template <bool> class Archive>
|
||||
bool do_serialize(Archive<false> &ar, zephyr_oracle::pricing_record_v1 &pr, uint8_t version)
|
||||
{
|
||||
// very basic sanity check
|
||||
if (ar.remaining_bytes() < sizeof(zephyr_oracle::pricing_record_v1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ar.serialize_blob(&pr, sizeof(zephyr_oracle::pricing_record_v1), "");
|
||||
if (!ar.good())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// write
|
||||
template <template <bool> class Archive>
|
||||
bool do_serialize(Archive<true> &ar, zephyr_oracle::pricing_record_v1 &pr, uint8_t version)
|
||||
{
|
||||
ar.begin_string();
|
||||
ar.serialize_blob(&pr, sizeof(zephyr_oracle::pricing_record_v1), "");
|
||||
if (!ar.good())
|
||||
return false;
|
||||
ar.end_string();
|
||||
return true;
|
||||
}
|
||||
|
||||
// read
|
||||
template <template <bool> class Archive>
|
||||
bool do_serialize(Archive<false> &ar, zephyr_oracle::pricing_record_v2 &pr, uint8_t version)
|
||||
{
|
||||
// very basic sanity check
|
||||
if (ar.remaining_bytes() < sizeof(zephyr_oracle::pricing_record_v2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ar.serialize_blob(&pr, sizeof(zephyr_oracle::pricing_record_v2), "");
|
||||
if (!ar.good())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// write
|
||||
template <template <bool> class Archive>
|
||||
bool do_serialize(Archive<true> &ar, zephyr_oracle::pricing_record_v2 &pr, uint8_t version)
|
||||
{
|
||||
ar.begin_string();
|
||||
ar.serialize_blob(&pr, sizeof(zephyr_oracle::pricing_record_v2), "");
|
||||
if (!ar.good())
|
||||
return false;
|
||||
ar.end_string();
|
||||
return true;
|
||||
}
|
||||
|
||||
// read
|
||||
template <template <bool> class Archive>
|
||||
bool do_serialize(Archive<false> &ar, zephyr_oracle::pricing_record_v3 &pr, uint8_t version)
|
||||
{
|
||||
// very basic sanity check
|
||||
if (ar.remaining_bytes() < sizeof(zephyr_oracle::pricing_record_v3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ar.serialize_blob(&pr, sizeof(zephyr_oracle::pricing_record_v3), "");
|
||||
if (!ar.good())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// write
|
||||
template <template <bool> class Archive>
|
||||
bool do_serialize(Archive<true> &ar, zephyr_oracle::pricing_record_v3 &pr, uint8_t version)
|
||||
{
|
||||
ar.begin_string();
|
||||
ar.serialize_blob(&pr, sizeof(zephyr_oracle::pricing_record_v3), "");
|
||||
if (!ar.good())
|
||||
return false;
|
||||
ar.end_string();
|
||||
return true;
|
||||
}
|
||||
|
||||
BLOB_SERIALIZER(zephyr_oracle::pricing_record);
|
||||
BLOB_SERIALIZER(zephyr_oracle::pricing_record_v1);
|
||||
BLOB_SERIALIZER(zephyr_oracle::pricing_record_v2);
|
||||
BLOB_SERIALIZER(zephyr_oracle::pricing_record_v3);
|
||||
@@ -0,0 +1,113 @@
|
||||
// Copyright (c) 2021, Haven Protocol
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace zephyr_oracle {
|
||||
|
||||
const std::vector<std::string> ASSET_TYPES = {"ZEPH", "ZEPHUSD", "ZEPHRSV", "ZYIELD"};
|
||||
const std::vector<std::string> RESERVE_TYPES = {"ZEPH", "ZEPHUSD", "ZEPHRSV", "ZYIELD", "ZYIELDRSV"};
|
||||
|
||||
const std::vector<std::string> ASSET_TYPES_V2 = {"ZPH", "ZSD", "ZRS", "ZYS"};
|
||||
const std::vector<std::string> RESERVE_TYPES_V2 = {"DJED", "YIELD"};
|
||||
|
||||
class asset_type_counts
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
// Fields
|
||||
uint64_t ZEPH;
|
||||
uint64_t ZEPHUSD;
|
||||
uint64_t ZEPHRSV;
|
||||
uint64_t ZYIELD;
|
||||
|
||||
// v2 fields
|
||||
uint64_t ZPH;
|
||||
uint64_t ZSD;
|
||||
uint64_t ZRS;
|
||||
uint64_t ZYS;
|
||||
|
||||
asset_type_counts() noexcept
|
||||
: ZEPH(0)
|
||||
, ZEPHUSD(0)
|
||||
, ZEPHRSV(0)
|
||||
, ZYIELD(0)
|
||||
, ZPH(0)
|
||||
, ZSD(0)
|
||||
, ZRS(0)
|
||||
, ZYS(0)
|
||||
{
|
||||
}
|
||||
|
||||
uint64_t operator[](const std::string asset_type) const noexcept
|
||||
{
|
||||
if (asset_type == "ZEPH") {
|
||||
return ZEPH;
|
||||
} else if (asset_type == "ZEPHUSD") {
|
||||
return ZEPHUSD;
|
||||
} else if (asset_type == "ZEPHRSV") {
|
||||
return ZEPHRSV;
|
||||
} else if (asset_type == "ZYIELD") {
|
||||
return ZYIELD;
|
||||
} else if (asset_type == "ZPH") {
|
||||
return ZPH;
|
||||
} else if (asset_type == "ZSD") {
|
||||
return ZSD;
|
||||
} else if (asset_type == "ZRS") {
|
||||
return ZRS;
|
||||
} else if (asset_type == "ZYS") {
|
||||
return ZYS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void add(const std::string asset_type, const uint64_t val)
|
||||
{
|
||||
if (asset_type == "ZEPH") {
|
||||
ZEPH += val;
|
||||
} else if (asset_type == "ZEPHUSD") {
|
||||
ZEPHUSD += val;
|
||||
} else if (asset_type == "ZEPHRSV") {
|
||||
ZEPHRSV += val;
|
||||
} else if (asset_type == "ZYIELD") {
|
||||
ZYIELD += val;
|
||||
} else if (asset_type == "ZPH") {
|
||||
ZPH += val;
|
||||
} else if (asset_type == "ZSD") {
|
||||
ZSD += val;
|
||||
} else if (asset_type == "ZRS") {
|
||||
ZRS += val;
|
||||
} else if (asset_type == "ZYS") {
|
||||
ZYS += val;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
// Copyright (c) 2019, Haven Protocol
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Portions of this code based upon code Copyright (c) 2019, The Monero Project
|
||||
|
||||
#include "pricing_record.h"
|
||||
|
||||
#include "serialization/keyvalue_serialization.h"
|
||||
#include "storages/portable_storage.h"
|
||||
|
||||
#include "string_tools.h"
|
||||
namespace zephyr_oracle
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
struct pr_serialized
|
||||
{
|
||||
uint64_t spot;
|
||||
uint64_t moving_average;
|
||||
uint64_t stable;
|
||||
uint64_t stable_ma;
|
||||
uint64_t reserve;
|
||||
uint64_t reserve_ma;
|
||||
uint64_t reserve_ratio;
|
||||
uint64_t reserve_ratio_ma;
|
||||
uint64_t yield_price;
|
||||
uint64_t timestamp;
|
||||
std::string signature;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(spot)
|
||||
KV_SERIALIZE(moving_average)
|
||||
KV_SERIALIZE(stable)
|
||||
KV_SERIALIZE(stable_ma)
|
||||
KV_SERIALIZE(reserve)
|
||||
KV_SERIALIZE(reserve_ma)
|
||||
KV_SERIALIZE(reserve_ratio)
|
||||
KV_SERIALIZE(reserve_ratio_ma)
|
||||
KV_SERIALIZE(yield_price)
|
||||
KV_SERIALIZE(timestamp)
|
||||
KV_SERIALIZE(signature)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
}
|
||||
|
||||
pricing_record::pricing_record() noexcept
|
||||
: spot(0)
|
||||
, moving_average(0)
|
||||
, stable(0)
|
||||
, stable_ma(0)
|
||||
, reserve(0)
|
||||
, reserve_ma(0)
|
||||
, reserve_ratio(0)
|
||||
, reserve_ratio_ma(0)
|
||||
, yield_price(0)
|
||||
, timestamp(0)
|
||||
{
|
||||
std::memset(signature, 0, sizeof(signature));
|
||||
}
|
||||
|
||||
bool pricing_record::_load(epee::serialization::portable_storage& src, epee::serialization::section* hparent)
|
||||
{
|
||||
pr_serialized in{};
|
||||
if (in._load(src, hparent))
|
||||
{
|
||||
// Copy everything into the local instance
|
||||
spot = in.spot;
|
||||
moving_average = in.moving_average;
|
||||
stable = in.stable;
|
||||
stable_ma = in.stable_ma;
|
||||
reserve = in.reserve;
|
||||
reserve_ma = in.reserve_ma;
|
||||
reserve_ratio = in.reserve_ratio;
|
||||
reserve_ratio_ma = in.reserve_ratio_ma;
|
||||
yield_price = in.yield_price;
|
||||
timestamp = in.timestamp;
|
||||
for (unsigned int i = 0; i < in.signature.length(); i += 2) {
|
||||
std::string byteString = in.signature.substr(i, 2);
|
||||
signature[i>>1] = (char) strtol(byteString.c_str(), NULL, 16);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Report error here?
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pricing_record::store(epee::serialization::portable_storage& dest, epee::serialization::section* hparent) const
|
||||
{
|
||||
std::string sig_hex;
|
||||
for (unsigned int i=0; i<64; i++) {
|
||||
std::stringstream ss;
|
||||
ss << std::hex << std::setw(2) << std::setfill('0') << (0xff & signature[i]);
|
||||
sig_hex += ss.str();
|
||||
}
|
||||
const pr_serialized out{spot,moving_average,stable,stable_ma,reserve,reserve_ma,reserve_ratio,reserve_ratio_ma,yield_price,timestamp,sig_hex};
|
||||
return out.store(dest, hparent);
|
||||
}
|
||||
|
||||
pricing_record::pricing_record(const pricing_record& orig) noexcept
|
||||
: spot(orig.spot)
|
||||
, moving_average(orig.moving_average)
|
||||
, stable(orig.stable)
|
||||
, stable_ma(orig.stable_ma)
|
||||
, reserve(orig.reserve)
|
||||
, reserve_ma(orig.reserve_ma)
|
||||
, reserve_ratio(orig.reserve_ratio)
|
||||
, reserve_ratio_ma(orig.reserve_ratio_ma)
|
||||
, yield_price(orig.yield_price)
|
||||
, timestamp(orig.timestamp)
|
||||
{
|
||||
std::memcpy(signature, orig.signature, sizeof(signature));
|
||||
}
|
||||
|
||||
pricing_record& pricing_record::operator=(const pricing_record& orig) noexcept
|
||||
{
|
||||
spot = orig.spot;
|
||||
moving_average = orig.moving_average;
|
||||
stable = orig.stable;
|
||||
stable_ma = orig.stable_ma;
|
||||
reserve = orig.reserve;
|
||||
reserve_ma = orig.reserve_ma;
|
||||
reserve_ratio = orig.reserve_ratio;
|
||||
reserve_ratio_ma = orig.reserve_ratio_ma;
|
||||
yield_price = orig.yield_price;
|
||||
timestamp = orig.timestamp;
|
||||
::memcpy(signature, orig.signature, sizeof(signature));
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool pricing_record::equal(const pricing_record& other) const noexcept
|
||||
{
|
||||
return ((spot == other.spot) &&
|
||||
(moving_average == other.moving_average) &&
|
||||
(stable == other.stable) &&
|
||||
(stable_ma == other.stable_ma) &&
|
||||
(reserve == other.reserve) &&
|
||||
(reserve_ma == other.reserve_ma) &&
|
||||
(reserve_ratio == other.reserve_ratio) &&
|
||||
(reserve_ratio_ma == other.reserve_ratio_ma) &&
|
||||
(yield_price == other.yield_price) &&
|
||||
(timestamp == other.timestamp) &&
|
||||
!::memcmp(signature, other.signature, sizeof(signature)));
|
||||
}
|
||||
|
||||
bool pricing_record::empty() const noexcept
|
||||
{
|
||||
const pricing_record empty_pr = zephyr_oracle::pricing_record();
|
||||
return (*this).equal(empty_pr);
|
||||
}
|
||||
|
||||
bool pricing_record::verifySignature(const std::string& public_key, const uint8_t hf_version) const
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(!public_key.empty(), "Pricing record verification failed. NULL public key. PK Size: " << public_key.size()); // TODO: is this necessary or the one below already covers this case, meannin it will produce empty pubkey?
|
||||
|
||||
// extract the key
|
||||
EVP_PKEY* pubkey;
|
||||
BIO* bio = BIO_new_mem_buf(public_key.c_str(), public_key.size());
|
||||
if (!bio) {
|
||||
return false;
|
||||
}
|
||||
pubkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
|
||||
BIO_free(bio);
|
||||
CHECK_AND_ASSERT_THROW_MES(pubkey != NULL, "Pricing record verification failed. NULL public key.");
|
||||
|
||||
// Convert our internal 64-byte binary representation into 128-byte hex string
|
||||
std::string sig_hex;
|
||||
for (unsigned int i=0; i<64; i++) {
|
||||
std::stringstream ss;
|
||||
ss << std::hex << std::setw(2) << std::setfill('0') << (0xff & signature[i]);
|
||||
sig_hex += ss.str();
|
||||
}
|
||||
|
||||
// Build the JSON string, so that we can verify the signature
|
||||
std::ostringstream oss;
|
||||
oss << "{\"spot\":" << spot;
|
||||
if (hf_version <= 4) {
|
||||
oss << ",\"moving_average\":" << moving_average;
|
||||
}
|
||||
oss << ",\"timestamp\":" << timestamp;
|
||||
oss << "}";
|
||||
std::string message = oss.str();
|
||||
|
||||
// Create a verify digest from the message
|
||||
EVP_MD_CTX *ctx = EVP_MD_CTX_create();
|
||||
int ret = 0;
|
||||
if (ctx) {
|
||||
ret = EVP_DigestVerifyInit(ctx, NULL, EVP_sha256(), NULL, pubkey);
|
||||
if (ret == 1) {
|
||||
ret = EVP_DigestVerifyUpdate(ctx, message.data(), message.length());
|
||||
if (ret == 1) {
|
||||
ret = EVP_DigestVerifyFinal(ctx, (const unsigned char *)signature, 64);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup the context we created
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
// Cleanup the openssl stuff
|
||||
EVP_PKEY_free(pubkey);
|
||||
|
||||
if (ret == 1)
|
||||
return true;
|
||||
|
||||
// Get the errors from OpenSSL
|
||||
// ERR_print_errors_fp (stderr);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pricing_record::has_missing_rates(const uint8_t hf_version) const noexcept
|
||||
{
|
||||
bool missing_rates = (spot == 0) || (moving_average == 0) || (stable == 0) || (stable_ma == 0) || (reserve == 0) || (reserve_ma == 0);
|
||||
if (hf_version <= 3) {
|
||||
return missing_rates;
|
||||
} else if (hf_version <= 4) {
|
||||
return missing_rates || (reserve_ratio == 0);
|
||||
} else if (hf_version == 5) {
|
||||
return missing_rates || (reserve_ratio == 0) || (reserve_ratio_ma == 0);
|
||||
}
|
||||
return missing_rates || (reserve_ratio == 0) || (reserve_ratio_ma == 0) || (yield_price == 0);
|
||||
}
|
||||
|
||||
bool pricing_record::has_essential_rates(const uint8_t hf_version) const noexcept
|
||||
{
|
||||
bool essential_rates = (spot != 0) && (stable != 0) && (reserve != 0);
|
||||
if (hf_version <= 3) {
|
||||
return essential_rates;
|
||||
}
|
||||
return essential_rates && (reserve_ratio != 0);
|
||||
}
|
||||
|
||||
// overload for pr validation for block
|
||||
bool pricing_record::valid(uint32_t hf_version, uint64_t bl_timestamp, uint64_t last_bl_timestamp) const
|
||||
{
|
||||
if (hf_version < 3) {
|
||||
if (!this->empty())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->empty())
|
||||
return true;
|
||||
|
||||
if (this->has_missing_rates(hf_version)) {
|
||||
if (hf_version < 4 || !this->has_essential_rates(hf_version)) {
|
||||
LOG_ERROR("Pricing record has missing rates.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string const MAINNET_ORACLE_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\n"
|
||||
"MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAO5hVuc6ylYMbj3WhqOMoAcJ0SD4e3zW\n"
|
||||
"edsUmhQeYwBkelAaFyxhX4ZotP+b/cFr2mX5iuND1znEnMZkyg+YmtkCAwEAAQ==\n"
|
||||
"-----END PUBLIC KEY-----\n";
|
||||
|
||||
if (!verifySignature(MAINNET_ORACLE_PUBLIC_KEY, hf_version)) {
|
||||
LOG_ERROR("Invalid pricing record signature.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// validate the timestmap
|
||||
if (this->timestamp > bl_timestamp + PRICING_RECORD_VALID_TIME_DIFF_FROM_BLOCK) {
|
||||
LOG_ERROR("Pricing record timestamp is too far in the future.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->timestamp <= last_bl_timestamp) {
|
||||
LOG_ERROR("Pricing record timestamp: " << this->timestamp << ", block timestamp: " << bl_timestamp);
|
||||
LOG_ERROR("Pricing record timestamp is too old.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
// Copyright (c) 2019, Haven Protocol
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Portions of this code based upon code Copyright (c) 2019, The Monero Project
|
||||
|
||||
#pragma once
|
||||
#include "common/pod-class.h"
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/ecdsa.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
#include "cryptonote_config.h"
|
||||
#include "crypto/hash.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
class portable_storage;
|
||||
struct section;
|
||||
}
|
||||
}
|
||||
|
||||
namespace zephyr_oracle
|
||||
{
|
||||
#pragma pack(push, 1)
|
||||
POD_CLASS pricing_record_pre {
|
||||
uint64_t zEPHUSD;
|
||||
uint64_t zEPHRSV;
|
||||
uint64_t timestamp;
|
||||
};
|
||||
POD_CLASS pricing_record_pre_v2 {
|
||||
uint64_t spot;
|
||||
uint64_t moving_average;
|
||||
uint64_t stable;
|
||||
uint64_t stable_ma;
|
||||
uint64_t reserve;
|
||||
uint64_t reserve_ma;
|
||||
uint64_t timestamp;
|
||||
unsigned char signature[64];
|
||||
};
|
||||
POD_CLASS pricing_record_pre_v3 {
|
||||
uint64_t spot;
|
||||
uint64_t moving_average;
|
||||
uint64_t stable;
|
||||
uint64_t stable_ma;
|
||||
uint64_t reserve;
|
||||
uint64_t reserve_ma;
|
||||
uint64_t reserve_ratio;
|
||||
uint64_t reserve_ratio_ma;
|
||||
uint64_t timestamp;
|
||||
unsigned char signature[64];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
class pricing_record
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
// Fields
|
||||
uint64_t spot;
|
||||
uint64_t moving_average;
|
||||
uint64_t stable;
|
||||
uint64_t stable_ma;
|
||||
uint64_t reserve;
|
||||
uint64_t reserve_ma;
|
||||
uint64_t reserve_ratio;
|
||||
uint64_t reserve_ratio_ma;
|
||||
uint64_t yield_price;
|
||||
uint64_t timestamp;
|
||||
unsigned char signature[64];
|
||||
|
||||
// Default c'tor
|
||||
pricing_record() noexcept;
|
||||
//! Load from epee p2p format
|
||||
bool _load(epee::serialization::portable_storage& src, epee::serialization::section* hparent);
|
||||
//! Store in epee p2p format
|
||||
bool store(epee::serialization::portable_storage& dest, epee::serialization::section* hparent) const;
|
||||
pricing_record(const pricing_record& orig) noexcept;
|
||||
~pricing_record() = default;
|
||||
bool equal(const pricing_record& other) const noexcept;
|
||||
bool empty() const noexcept;
|
||||
bool verifySignature(const std::string& public_key, const uint8_t hf_version) const;
|
||||
bool has_missing_rates(const uint8_t hf_version) const noexcept;
|
||||
bool has_essential_rates(const uint8_t hf_version) const noexcept;
|
||||
bool valid(uint32_t hf_version, uint64_t bl_timestamp, uint64_t last_bl_timestamp) const;
|
||||
|
||||
pricing_record& operator=(const pricing_record& orig) noexcept;
|
||||
uint64_t operator[](const std::string& asset_type) const;
|
||||
};
|
||||
|
||||
inline bool operator==(const pricing_record& a, const pricing_record& b) noexcept
|
||||
{
|
||||
return a.equal(b);
|
||||
}
|
||||
|
||||
inline bool operator!=(const pricing_record& a, const pricing_record& b) noexcept
|
||||
{
|
||||
return !a.equal(b);
|
||||
}
|
||||
|
||||
class pricing_record_v1
|
||||
{
|
||||
|
||||
public:
|
||||
uint64_t zEPHUSD;
|
||||
uint64_t zEPHRSV;
|
||||
uint64_t timestamp;
|
||||
|
||||
bool write_to_pr(zephyr_oracle::pricing_record &pr)
|
||||
{
|
||||
pr.spot = 0;
|
||||
pr.moving_average = 0;
|
||||
pr.stable = 0;
|
||||
pr.stable_ma = 0;
|
||||
pr.reserve = 0;
|
||||
pr.reserve_ma = 0;
|
||||
pr.timestamp = 0;
|
||||
std::memset(pr.signature, 0, sizeof(zephyr_oracle::pricing_record::signature));
|
||||
return true;
|
||||
};
|
||||
|
||||
bool read_from_pr(zephyr_oracle::pricing_record &pr)
|
||||
{
|
||||
zEPHUSD = 0;
|
||||
zEPHRSV = 0;
|
||||
timestamp = 0;
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
class pricing_record_v2
|
||||
{
|
||||
|
||||
public:
|
||||
uint64_t spot;
|
||||
uint64_t moving_average;
|
||||
uint64_t stable;
|
||||
uint64_t stable_ma;
|
||||
uint64_t reserve;
|
||||
uint64_t reserve_ma;
|
||||
uint64_t timestamp;
|
||||
unsigned char signature[64];
|
||||
|
||||
bool write_to_pr(zephyr_oracle::pricing_record &pr)
|
||||
{
|
||||
pr.spot = spot;
|
||||
pr.moving_average = moving_average;
|
||||
pr.stable = stable;
|
||||
pr.stable_ma = stable_ma;
|
||||
pr.reserve = reserve;
|
||||
pr.reserve_ma = reserve_ma;
|
||||
pr.reserve_ratio = 0;
|
||||
pr.reserve_ratio_ma = 0;
|
||||
pr.timestamp = timestamp;
|
||||
std::memcpy(pr.signature, signature, sizeof(pr.signature));
|
||||
return true;
|
||||
};
|
||||
|
||||
bool read_from_pr(zephyr_oracle::pricing_record &pr)
|
||||
{
|
||||
spot = pr.spot;
|
||||
moving_average = pr.moving_average;
|
||||
stable = pr.stable;
|
||||
stable_ma = pr.stable_ma;
|
||||
reserve = pr.reserve;
|
||||
reserve_ma = pr.reserve_ma;
|
||||
timestamp = pr.timestamp;
|
||||
std::memcpy(signature, pr.signature, sizeof(signature));
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
class pricing_record_v3
|
||||
{
|
||||
|
||||
public:
|
||||
uint64_t spot;
|
||||
uint64_t moving_average;
|
||||
uint64_t stable;
|
||||
uint64_t stable_ma;
|
||||
uint64_t reserve;
|
||||
uint64_t reserve_ma;
|
||||
uint64_t reserve_ratio;
|
||||
uint64_t reserve_ratio_ma;
|
||||
uint64_t timestamp;
|
||||
unsigned char signature[64];
|
||||
|
||||
bool write_to_pr(zephyr_oracle::pricing_record &pr)
|
||||
{
|
||||
pr.spot = spot;
|
||||
pr.moving_average = moving_average;
|
||||
pr.stable = stable;
|
||||
pr.stable_ma = stable_ma;
|
||||
pr.reserve = reserve;
|
||||
pr.reserve_ma = reserve_ma;
|
||||
pr.reserve_ratio = reserve_ratio;
|
||||
pr.reserve_ratio_ma = reserve_ratio_ma;
|
||||
pr.yield_price = 0;
|
||||
pr.timestamp = timestamp;
|
||||
std::memcpy(pr.signature, signature, sizeof(pr.signature));
|
||||
return true;
|
||||
};
|
||||
|
||||
bool read_from_pr(zephyr_oracle::pricing_record &pr)
|
||||
{
|
||||
spot = pr.spot;
|
||||
moving_average = pr.moving_average;
|
||||
stable = pr.stable;
|
||||
stable_ma = pr.stable_ma;
|
||||
reserve = pr.reserve;
|
||||
reserve_ma = pr.reserve_ma;
|
||||
reserve_ratio = pr.reserve_ratio;
|
||||
reserve_ratio_ma = pr.reserve_ratio_ma;
|
||||
timestamp = pr.timestamp;
|
||||
std::memcpy(signature, pr.signature, sizeof(signature));
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
} // zephyr_oracle
|
||||
@@ -0,0 +1,14 @@
|
||||
"use strict";
|
||||
let u = require('../build/Release/cryptoforknote');
|
||||
|
||||
const b = Buffer.from(
|
||||
'1010c59099c206028309f83a444da29afb16cc97126b0d82a0ef9dacdc5f5384e4d14f2bed221f00000000030005bbd769abd769abd769abd769abd769abd76901ff99d7690580c8afa02502c7a7d056ac171af27f081eb7113ee31eb6eac4c523960f31bc54ae4150fd087a80c8afa025022a74a3c4c36d32e95633d44ba9a7b8188297b2ac91afecab826b86fabaa7091680bcc1960b02a42e0bf2c44c7c5f43798f4be091a04d36e21b7a2f85008ff939dc028c1d14e980bcc1960b02c8b180ae1eef14bb14953eb6b0f8d66111c80067dfe9e689fdf72cf1b0d9d58580bcc1960b027d3ab388e3e7844bc42562edf05fb34d4b30b281b1307c75d7d3acfc90ed69b57601a15624111f421a5b16fd3350b5b234d288aa9e369a090fcdaeab7079361a74600211000000228f09650000000000000000000001cb6e8a28b50d5427f24dd6ede582e5eb895d739ad2cfe7eb7df31d7dcf1531c47200000000000000000000000000000000000000000000000000000000000000000000', 'hex');
|
||||
const b2 = u.convert_blob(b, 16);
|
||||
const h1 = b2.toString('hex');
|
||||
|
||||
if (h1 === '1010c59099c206028309f83a444da29afb16cc97126b0d82a0ef9dacdc5f5384e4d14f2bed221f000000006ebc660a5f50595d256087798e91ff9184878de2db66d791108ec4149dcd01fc01') {
|
||||
console.log('PASSED');
|
||||
} else {
|
||||
console.log('FAILED: ' + h1);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
let u = require('../build/Release/cryptoforknote');
|
||||
|
||||
const b = Buffer.from(
|
||||
'0500ecb2ecb40646f61cfb8f3eb6f3527297eadd29125668008dc74c1ebb177cfb7d5c7c498dcd000000000199b25c01ffe7b15c043c02e42fc85c385aa98b9e83a75481a3fcd2ad049d59f3535c2775a15fae521aa37fc8010259fe9bb8bddfabed25331c90c1b478edb76fd9a94ced48c7b220498936f63268a01f02cbb7bf2ea054b438040c70bf8ba6c530b9890c0c8ca7019fef1c49d010321f61a08d060214c04c168d52662ac27d43c08c4941c4d7db9955bff0ec7e7ce1f0cd5f3bc68034014574cd7358bdee9f682543d2fa0cc23b207bf676688f40fd425d4f0477110cab02110000000000000000000000000000000000010df5931907c66fac569c743451aad0936db4d70f4d0fbcec44c504a2e02bd260'
|
||||
, 'hex');
|
||||
const b2 = u.convert_blob(b, 1);
|
||||
const h1 = b2.toString('hex');
|
||||
|
||||
if (h1 === '0500ecb2ecb40646f61cfb8f3eb6f3527297eadd29125668008dc74c1ebb177cfb7d5c7c498dcd000000004baf51b919538baa7bdbad14d2b63817df2d301f6e7ccd9cf78ff95adad647a702') {
|
||||
console.log('PASSED');
|
||||
} else {
|
||||
console.log('FAILED: ' + h1);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
let u = require('../build/Release/cryptoforknote');
|
||||
|
||||
const b = Buffer.from(
|
||||
'0500d073b1220184edacc32f2186e7d8ed46ffa5473628d9388f1624e80e9c0e9a10000085b7ecb406000000000000000000000000000000000000000000000000000000000000000000000000010000000023032100000000000000000000000000000000000000000000000000000000000000000001b5e34501ffa1e34506ee240215b84a8550c5fd6d91c6d062b03eae5b2a6a20f080730d1fc44e2a94af6e3ecde0d403028001f4b155617d81db4d827c81898d11487e9bd047365843928bd0b01d317d5280ea30028091199c6ab679ca5e92a488ebe0c74175d1492a6477e35c3f27970358c29c8cc0843d024fe9895a4b8108f2ea4db2c1efabbb91fe0f9495cbc66b3905e37a61fb1942d180dac4090255b17d1462c3be7b994d91959a24112c55910e69d88a4eab539dab297355129980c2d72f02dca4f2d185fdf90d2255aa1801d5b5003df01587f17656862ec71b68b3b95b3434015706f2bc147c91ab357c5783c355967557df13d474844f0e0a0af8a2ae93f85b0211000000000000000000000000000000000000'
|
||||
, 'hex');
|
||||
const b2 = u.convert_blob(b, 2);
|
||||
const h1 = b2.toString('hex');
|
||||
|
||||
if (h1 === '010085b7ecb406d073b1220184edacc32f2186e7d8ed46ffa5473628d9388f1624e80e9c0e9a10000000007f6c5d24796ce8a92079a8e6a93c1599b53bc48fa7654765512f1dc1060dcf5d01') {
|
||||
console.log('PASSED');
|
||||
} else {
|
||||
console.log('FAILED: ' + h1);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
let u = require('../build/Release/cryptoforknote');
|
||||
|
||||
const b = Buffer.from(
|
||||
'08089eb3ecb406b35852af53db5ed822f0c51cfcfeb36a0c83fa55230a791add87087d221308c70000000001abd2c30101ffefd1c30101f7d7c0c084110220323306fc36cf0fed316f4d90f6ce0e04ec5b8e26b52886025f7a77957676cc340165706e1dd751a5bd9a72e58caf30104216b60fba751e8d681af90bc4df00cdd40211000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
|
||||
, 'hex');
|
||||
const b2 = u.convert_blob(b, 6);
|
||||
const h1 = b2.toString('hex');
|
||||
|
||||
if (h1 === '08089eb3ecb406b35852af53db5ed822f0c51cfcfeb36a0c83fa55230a791add87087d221308c700000000ab937b64d0d1087c03155686ae5bdd27b79233f43dae45977f620b863590596c010000000000000000000000000000000000000000000000000000000000000000') {
|
||||
console.log('PASSED');
|
||||
} else {
|
||||
console.log('FAILED: ' + h1);
|
||||
process.exit(1);
|
||||
}
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash -x
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
cd $DIR
|
||||
node arq.js || exit 1
|
||||
node bloc.js || exit 1
|
||||
node ird.js || exit 1
|
||||
node msr.js || exit 1
|
||||
node ryo.js || exit 1
|
||||
node sal.js || exit 1
|
||||
node tube.js || exit 1
|
||||
node xeq.js || exit 1
|
||||
node xhv.js || exit 1
|
||||
node xla.js || exit 1
|
||||
node xmr.js || exit 1
|
||||
node xmv.js || exit 1
|
||||
node xtnc.js || exit 1
|
||||
node zeph.js || exit 1
|
||||
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
let u = require('../build/Release/cryptoforknote');
|
||||
|
||||
const b = Buffer.from(
|
||||
'0909bcb7ecb406e417dd02e55e8c3f6368749df3e761b000f87001e28ccb9c24f1d65f2cc848d70000000003e5f93701ffa9f9370181a0f693710231510ef639f6848581cc3df0ab1783f73fd401d4ab03df62dfad68f8557bad943401f3cc08c30d31a225b46514edfccc4b3c0d429cac30b23e1e4fd9e1c514f5b350021100000000000000000000000000000000000000'
|
||||
, 'hex');
|
||||
const b2 = u.convert_blob(b, 4);
|
||||
const h1 = b2.toString('hex');
|
||||
|
||||
if (h1 === '0909bcb7ecb406e417dd02e55e8c3f6368749df3e761b000f87001e28ccb9c24f1d65f2cc848d7000000008c95c259fa076f11347c4129bf1020da140d44f3948410c0f3a77d1b4d18a21f01') {
|
||||
console.log('PASSED');
|
||||
} else {
|
||||
console.log('FAILED: ' + h1);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
let u = require('../build/Release/cryptoforknote');
|
||||
|
||||
const b = Buffer.from(
|
||||
'0a0ad3efb6c706668aaad0289b8bf3bf8cd109d6da4107b48f4242185fa6d50b78575c55e728b400000000043c01ffdcb91401bac68dc22104fd2c8f800bd4c33b96cde12515224a403ea052736d98cf8c5d5a5ff4a66dddc00453414c3151042efafd5871735ab1f3dcb6c380e595b2d0340136a86969f8e7a0c4bd739cd6163b38e3c76f1fb443f7a552e755b305b11c53510211000000000000000000000000000000000001ceb1c3b00800043c01ffdcb91400020200020001c0d11e47cd1d4ef51d152f6f186f76a91623b8ce922687ce8c907a5dfda26237'
|
||||
, 'hex');
|
||||
const b2 = u.convert_blob(b, 15);
|
||||
const h1 = b2.toString('hex');
|
||||
|
||||
if (h1 === '0a0ad3efb6c706668aaad0289b8bf3bf8cd109d6da4107b48f4242185fa6d50b78575c55e728b4000000003dc5e186a15e0b48571088e8b3c0a04597ff88a3dc3661cae2f0a2a8a2a81d7403') {
|
||||
console.log('PASSED');
|
||||
} else {
|
||||
console.log('FAILED: ' + h1);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
let u = require('../build/Release/cryptoforknote');
|
||||
|
||||
const b = Buffer.from(
|
||||
'0d0df9baecb4060567fc85623e264062d2d0593b8d63a956249d0b2588fd53111f446694b02110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000282b1d00301ffc6b0d00301b798fdd01602cee1a6bd4cce3cab8daccc0cef76dea2302af21e576c00957f8f7fd4bace7d4b34018571692c36ef35b1802ccc87b968684fa2581d7f6f634312bf4d66e2347a6c49021100000000000000000000000000000000000000'
|
||||
, 'hex');
|
||||
const b2 = u.convert_blob(b, 10);
|
||||
const h1 = b2.toString('hex');
|
||||
|
||||
if (h1 === '0d0d791d9b66000000000567fc85623e264062d2d0593b8d63a956249d0b2588fd53111f446694b02110beef88d4195143229591bb6efd2d40780d7da377d165a39afadead64e4add0b1010000000000000000') {
|
||||
console.log('PASSED');
|
||||
} else {
|
||||
console.log('FAILED: ' + h1);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
let u = require('../build/Release/cryptoforknote');
|
||||
|
||||
const b = Buffer.from(
|
||||
'151593b6ecb406b4018d3e3a5d07eb8af63e106bd53c773d6a46957758d8e6aba76c8744fe2536000000000403b8a353b8a353b8a353b8a35301fffca25303d6960302cb745225654660476da30e1f2e120a45d253ec764f37b68789f43dba417c6c90ff79026de51b2d1226d359075b5d1ae4d62658976598d4b1d8ac6780b01aaa6d47156cf9c90802dffece08e302c8258e61d55e8788a10804b0ca0276c8036709dee77d1a0f22627601bcab5b456bf3c2f097ca6b719c29d51766acaec6b9694da2234a02f6f466a1130211000000000000000000000000000000000001ecbaeea4421709ed164473327633de0fb7c4180dc805afa388e7fc5c45a7a0c87299d794018183ea0fa1e697647f7bc6f92bfec1d65ac1b4795527c86483a0ed4f000000'
|
||||
, 'hex');
|
||||
const b2 = u.convert_blob(b, 5);
|
||||
const h1 = b2.toString('hex');
|
||||
|
||||
if (h1 === '151593b6ecb406b4018d3e3a5d07eb8af63e106bd53c773d6a46957758d8e6aba76c8744fe253600000000775fb8dc7335f11e8c7f381effe8e94a1a7f0e5dca3b9c97b775de1ed434317101') {
|
||||
console.log('PASSED');
|
||||
} else {
|
||||
console.log('FAILED: ' + h1);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
let u = require('../build/Release/cryptoforknote');
|
||||
|
||||
const b = Buffer.from(
|
||||
'1717c3b0ecb40661bb2e3f4c03e0feb67a7a48a1739630d157da8b945a0f7de88fd12174073293000000009085dbf70700000060e5d3180000000070aac5495c010000f056e500000000000000000000000000003108edce000000b0254fc09b060000f0f49af4d5000000406eea2ab4000000d079eb28268f000000000000000000000300000000000000ac22ea6b06000000007073910800000050393df8220000000097727e2c00000044189b66000000001efdfe115f5b28a68f373b71720171f844f348676fed7ea239522b64d215af629909b820c571c282826fe024a4a44d3b86aa8848193ca1c3240f2335d971e5f30801ffa9cb6504ae9ecd82d62807ab26cbcc59cbb14ca430ba3a5b0bae8f6fc9f626c43f8989d6922e5e41cb13e503584856e5cb650000f0fbc491809202071ee8bb35868f6fa6c981446d1965e7e2ebbbf8b484858ec5102527f48e74aca303584856e5cb6500000e94ae8f5b070ec031da424efb260e3cbb9fc95aedd4f372a9a71d7b06213b3768fa085bf8d503584856e5cb650000729ceee5040709183028fb4169646a11fa6abacdf95b266c7ed29f8950fc219f215b7ae4f1ea03584856e5cb6500009c5501d1ee9ada2dadb688034c51d7b50ade575d4240628c3ca2f1ec27560f0587411d0211000000000000000000000000000000000001efa3c7bc5a333d0e37729347a844695dafada545f7817cdefbb53ebe624191eb0000000001a08b2344a3ab1756ef88d6d0e37565f114698ac6353b88629e059c74ebdb3bc6'
|
||||
, 'hex');
|
||||
const b2 = u.convert_blob(b, 11);
|
||||
const h1 = b2.toString('hex');
|
||||
|
||||
if (h1 === '1717c3b0ecb40661bb2e3f4c03e0feb67a7a48a1739630d157da8b945a0f7de88fd12174073293000000009085dbf70700000060e5d3180000000070aac5495c010000f056e500000000000000000000000000003108edce000000b0254fc09b060000f0f49af4d5000000406eea2ab4000000d079eb28268f000000000000000000000300000000000000ac22ea6b06000000007073910800000050393df8220000000097727e2c00000044189b66000000001efdfe115f5b28a68f373b71720171f844f348676fed7ea239522b64d215af629909b820c571c282826fe024a4a44d3b86aa8848193ca1c3240f2335d971e5f3961bdcdf2cada4fd0f498612e2680fedb0dbe06788ed69e60cfb465366f33f6402') {
|
||||
console.log('PASSED');
|
||||
} else {
|
||||
console.log('FAILED: ' + h1);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
let u = require('../build/Release/cryptoforknote');
|
||||
|
||||
const b = Buffer.from(
|
||||
'1010b9b7ecb4060404b45248c01f9a65d5b2e5ec3fd875de7e8bff8eb79453fd87c0d39e04546b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002b6ea3f01fffae93f01dcc50a0308686987f2c9643b5c20a29f1d124b4330b5e7c94f242f4be451303a82a2c635123401c2ea0da83a76b72a1e4b581143febf8f08155eeb3482955e2b4d0c43507ebba4021100000000000000000000000000000000000000'
|
||||
, 'hex');
|
||||
const b2 = u.convert_blob(b, 14);
|
||||
const h1 = b2.toString('hex');
|
||||
|
||||
if (h1 === '1010b9b7ecb4060404b45248c01f9a65d5b2e5ec3fd875de7e8bff8eb79453fd87c0d39e04546b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004fed0302f50f72bf1ac330a367b4ea32a24fb5de5b91a927392eaa318b342cca01') {
|
||||
console.log('PASSED');
|
||||
} else {
|
||||
console.log('FAILED: ' + h1);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
let u = require('../build/Release/cryptoforknote');
|
||||
|
||||
const b = Buffer.from(
|
||||
'1010f4b3ecb406a7e85c45ba044af4a16e0e790032f31727e3daef1a7da5ab12c9894c191713e30000000002a18ec30101ffe58dc30101c084aa98d21103d71cd8a7478f0c74e191f3dac85b4c396ec76a07311a94db04721676634ab49b1e34014f9b1e0434876de264409d8f024f5f61fdcb9297ef671518310e7add0e69bc270211000000000000000000000000000000000000238dc39cf2f9eef8084b911d6086075ea57b58793ec2a0a8683f5d890a5be1c92583892a3f5127cb3469da37719047fbdd5bc32034c996a9e3919485d36ac5f609c646379ca888796d7485d403f45ab2230b66920c8f0b1e160d4b6529f531ca95bc04dfc96e7643a9f86526ba4e899fa52d2279abf2cf8b60e4be19f9f9b293211f508353cb5496f04b7e9824395828385e7724a2e2fa42097962028fd7c5083fa3e827d9f46dbf3741181d4f4897aea254bbc2081a3455603c81bfd75961541cb3f1ad55fa277111b5e4b3b7ce10c1bbdca7e158d36deac6c09ef9827edea7d6dce44f1145831d29d7ac59e497050af0a19de855302ff70079e60761d6bae70dc45a766e7088e764e6950e5a9704e03e5a455b23a572af2950c613d6d109b2007a7c943e4b0c2513ced71179b0dd0388fa0c397b83d4ebeb616cbe89c6c2d12972bdbbe845f78189fd3b0494bcac392b8ec9a6c2d49d88c391c54fd2bf0ba45aded1dbff66fe6311c293b6ae1f47127ad936890cfc2379427be0360b68007ae3dd56083a4eb90d736370b23471dd5d2b7ee2107bd44016e20b9a948e745b2de2cbcd7780e981b0eeb646175137e8b42a9b9724263d9a84d9ba892caa209c73ca03ab832e504d309a6714e8554b13b3c05f306f0e46c06c801978e7f69727b8333709fe7c836286cefd36ef22a4681653d04a96ce91d5f97aee107f93cd5f57c3f5f553e435a910c60f426b3f3658754e72a55ea8b40eda985147558159296bfa23ab9cbbd2e8316a00b87ea81195d8b4a3d4ec2889a788af0d4ce53b4e261a1087eae0f54cc92132f87a5aadadd3ea70228df71a615b85a1d96bc031d08e6fafb41117b055c9db533d27fcacc14a251369654c377d451e2eeb7aa7d26ff12542c5b7194d2b783b493435c0bee44b9ee315aa373dd79ed7abebe2095e547867f0db8cda9a8544f306a74e96a7023e637642f63bc5fa27dcfae1a59655b7170fee88c7362f676b6b4e5aee6c94cdfda39075138bf4fb0da0f7490ea33d85d8d72a23695f30f14f65edd4715aacc897d6be2df0e6566c3d484945f2b4ac5e6dab45306d2e8704ba8590388d7d41620ed4171701c5d8eab8b0e1192075606b70dc00014089e31fee4ae2aaa3dc49c9018ec93497818eb1348bedf3b2d0af7ccc4bb5bb151a7e9b1759d46db0e3b4acb08f639ae61a43aff57f1f9f8baff9205d4350733a8bd2f99acb417ef81fd5affb56cf85019fc23bcc03359b0d57c62a94efae9028a7353f11edc5f304fd59cc24ecfcd40db5e5354ebb288d64934c4bf3e56a37c612043d49335e52a1788998cbf3a1cc09bc78c9ffbac1346a4fad340727ee9aa20c00ebf5131556fbdbf842469d31c8121feae78c3a56ba1eae5bde78c18371108601e8ae7f5698d0918be8e52afc500fa67c35b46e8011b686e9a5e20008b7dfd3eb85011f54a70832823611dc06373d1b98052a503313a6e4d0eab3ad97f04dac2305cbb4fa094c6634270289593f90ffcd460529d0835bdfe780074488d531ebb06558ba4b28ece031cfd981062beec659c6a50addfefaf2e4e1e11f95'
|
||||
, 'hex');
|
||||
const b2 = u.convert_blob(b, 0);
|
||||
const h1 = b2.toString('hex');
|
||||
|
||||
if (h1 === '1010f4b3ecb406a7e85c45ba044af4a16e0e790032f31727e3daef1a7da5ab12c9894c191713e300000000980c1b19961064ad5ceba387074e29030eac8378bcb38f5a50189f8892c4578324') {
|
||||
console.log('PASSED');
|
||||
} else {
|
||||
console.log('FAILED: ' + h1);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
let u = require('../build/Release/cryptoforknote');
|
||||
|
||||
const b = Buffer.from(
|
||||
'0d0d9ab8ecb406317c2fb5d01d1baccedab49650312ee4c5390f0f569a77f6703f9c617e9de92f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002d5ef8e0101ff99ef8e0101bea394bad10802a50df09ab1bbdb1e9be7e626b9746266c0a8193f649db53affe59ff69ff268843401ed630c83e0a68cc91762ba50312078e4299aff7eb9aa011c751c760c4ee15f2c021100000000000000000000000000000000000000'
|
||||
, 'hex');
|
||||
const b2 = u.convert_blob(b, 8);
|
||||
const h1 = b2.toString('hex');
|
||||
|
||||
if (h1 === '0d0d1a1c9b6600000000317c2fb5d01d1baccedab49650312ee4c5390f0f569a77f6703f9c617e9de92fe8e1af3e87d14e8aa51dd2cc397f8d455ac486ec069fb832b45fe7123dca5d42010000000000000000') {
|
||||
console.log('PASSED');
|
||||
} else {
|
||||
console.log('FAILED: ' + h1);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
let u = require('../build/Release/cryptoforknote');
|
||||
|
||||
const b = Buffer.from(
|
||||
'0c0cabb9ecb406eef6a95a820ac36c32f1903e87623cae5483806e8cfa5b3dd30847c6c8b1c0760000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000302b3e049b3e04900b3e04901ff95e04902a2a794f82e0213b0b305b676cf7df3dd4acec81b8a76cb11fa4afc2ddde258e8d18f8fe2f91aa4d6dd93340231b43a96d2a95423341311b94d1bf0e0a800900ed52969058cd18090d142d4437601122ea38d8e53fe2fd288c0e3f47842fd27b99229422b703dd7f2c0c4c15dec8c02110000000000000000000000000000000000018e08c827ececc945a2111283aed96225a00c67b8e549c22a557f15548bdb552b72c80438e83eb7bc50eda08e45a86c0f763d7120eb61185f2763377d24e0b4eaa90000'
|
||||
, 'hex');
|
||||
const b2 = u.convert_blob(b, 9);
|
||||
const h1 = b2.toString('hex');
|
||||
|
||||
if (h1 === '0c0cab1c9b6600000000eef6a95a820ac36c32f1903e87623cae5483806e8cfa5b3dd30847c6c8b1c076df4dfa482c794850801d547e98d954b0eae288c2cd74d7378de62fa44f83d2e301') {
|
||||
console.log('PASSED');
|
||||
} else {
|
||||
console.log('FAILED: ' + h1);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
let u = require('../build/Release/cryptoforknote');
|
||||
|
||||
const b = Buffer.from(
|
||||
'050592b8ecb406407f1bf945d1f437a1705b323f46a86e18d0882a516f7b0582a4b208bf577e710000000090cbdb40c1020000903f4ebcb9020000f0d8bbdd4c00000070b623b84d0000006045baf33701000070a2fd163701000040521b4fda05000010758b35c8050000131c9b66000000005f9669b40d9a190f51d226502bad1bbc8fea45e18f4c87dee8cd273efbfd69e27219defe1a6480b68f1a5205e72d63246d5565a2f19bbfc9816005bc8ebb89f703c99d1201ff8d9d1202b5c3c8a38099020208f52c744b1455ec58ab17ea0202a64b605ed1c6cffc88fd41eb3cc76b7d2abd045a455048cdfbfba6f1dd120235aebd0d4d356555503a5460b569a4e0e8b7ded8757b85531ed5b02fa2d998ba045a455048ce55014b0868384957bedcd9b70d6c141f3f811a41bcee8f44813f92fcc6cb428e037c021100000000000000000000000000000000000129cb6a3ab186d3fbccedb4fcc119931ab8e9aee73f4aea4e77778a0ba987a99e0000000000'
|
||||
, 'hex');
|
||||
const b2 = u.convert_blob(b, 13);
|
||||
const h1 = b2.toString('hex');
|
||||
|
||||
if (h1 === '050592b8ecb406407f1bf945d1f437a1705b323f46a86e18d0882a516f7b0582a4b208bf577e710000000090cbdb40c1020000903f4ebcb9020000f0d8bbdd4c00000070b623b84d0000006045baf33701000070a2fd163701000040521b4fda05000010758b35c8050000131c9b66000000005f9669b40d9a190f51d226502bad1bbc8fea45e18f4c87dee8cd273efbfd69e27219defe1a6480b68f1a5205e72d63246d5565a2f19bbfc9816005bc8ebb89f7220309a73319964e8560ce2be3f523d1cd4f36d366a503acb1d44dadeb9e8c8101') {
|
||||
console.log('PASSED');
|
||||
} else {
|
||||
console.log('FAILED: ' + h1);
|
||||
process.exit(1);
|
||||
}
|
||||
Reference in New Issue
Block a user