Loading .gitignore +4 −0 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ test/integration/documents-currency.d.ts test/integration/forwarding.js test/integration/branches_switch.js test/integration/branches2.js test/integration/transactions-chaining.js test/fast/modules/crawler/block_pulling.js* test/fast/modules/crawler/block_pulling.d.ts test/fast/fork*.js* Loading @@ -72,3 +73,6 @@ test/fast/modules/common/grammar.d.ts test/fast/prover/pow-1-cluster.d.ts test/fast/prover/pow-1-cluster.js test/fast/prover/pow-1-cluster.js.map test/fast/protocol-local-rule-chained-tx-depth.js test/fast/protocol-local-rule-chained-tx-depth.js.map test/fast/protocol-local-rule-chained-tx-depth.d.ts app/lib/common-libs/constants.ts +2 −0 Original line number Diff line number Diff line Loading @@ -285,6 +285,8 @@ export const CommonConstants = { BLOCK: find("Block: (" + INTEGER + "-" + FINGERPRINT + ")"), SPECIAL_BLOCK }, BLOCK_MAX_TX_CHAINING_DEPTH: 5 } function exact (regexpContent:string) { Loading app/lib/rules/index.ts +2 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ export const ALIAS = { await LOCAL_RULES_FUNCTIONS.checkTxRecipients(block); await LOCAL_RULES_FUNCTIONS.checkTxAmounts(block); await LOCAL_RULES_FUNCTIONS.checkTxSignature(block); await LOCAL_RULES_FUNCTIONS.checkMaxTransactionChainingDepth(block, conf, index); }, ALL_LOCAL_BUT_POW_AND_SIGNATURE: async (block:BlockDTO, conf:ConfDTO, index:IndexEntry[]) => { Loading Loading @@ -60,6 +61,7 @@ export const ALIAS = { await LOCAL_RULES_FUNCTIONS.checkTxRecipients(block); await LOCAL_RULES_FUNCTIONS.checkTxAmounts(block); await LOCAL_RULES_FUNCTIONS.checkTxSignature(block); await LOCAL_RULES_FUNCTIONS.checkMaxTransactionChainingDepth(block, conf, index); } } Loading app/lib/rules/local_rules.ts +62 −16 Original line number Diff line number Diff line Loading @@ -379,17 +379,61 @@ export const LOCAL_RULES_FUNCTIONS = { } } return true; }, checkMaxTransactionChainingDepth: async (block:BlockDTO, conf:ConfDTO, index:IndexEntry[]) => { const sindex = Indexer.sindex(index) const max = getMaxTransactionDepth(sindex) // const allowedMax = block.medianTime > 1517443200 ? CommonConstants.BLOCK_MAX_TX_CHAINING_DEPTH : 1 if (max > allowedMax) { throw "The maximum transaction chaining length per block is " + CommonConstants.BLOCK_MAX_TX_CHAINING_DEPTH } return true } } export interface SindexShortEntry { op:string, identifier:string, pos:number, tx:string|null } function getMaxTransactionDepth(sindex:SindexShortEntry[]) { const ids = _.uniq(_.pluck(sindex, 'tx')) let maxTxChainingDepth = 0 for (let id of ids) { maxTxChainingDepth = Math.max(maxTxChainingDepth, getTransactionDepth(id, sindex, 0)) } return maxTxChainingDepth } function getTransactionDepth(txHash:string, sindex:SindexShortEntry[], localDepth = 0) { const inputs = _.filter(sindex, (s:SindexShortEntry) => s.op === 'UPDATE' && s.tx === txHash) let depth = localDepth for (let input of inputs) { const consumedOutput = _.findWhere(sindex, { op: 'CREATE', identifier: input.identifier, pos: input.pos }) if (consumedOutput) { if (localDepth < 5) { const subTxDepth = getTransactionDepth(consumedOutput.tx, sindex, localDepth + 1) depth = Math.max(depth, subTxDepth) } else { depth++ } } } return depth } function checkSingleMembershipSignature(ms:any) { return verify(ms.getRaw(), ms.signature, ms.issuer); } function checkBunchOfTransactions(transactions:TransactionDTO[], done:any = undefined){ const block:any = { transactions }; function checkBunchOfTransactions(transactions:TransactionDTO[], conf:ConfDTO, options?:{ dontCareAboutChaining?:boolean }){ const block:any = { transactions, identities: [], joiners: [], actives: [], leavers: [], revoked: [], excluded: [], certifications: [] }; const index = Indexer.localIndex(block, conf) return (async () => { try { let local_rule = LOCAL_RULES_FUNCTIONS; await local_rule.checkTxLen(block); await local_rule.checkTxIssuers(block); Loading @@ -397,10 +441,8 @@ function checkBunchOfTransactions(transactions:TransactionDTO[], done:any = unde await local_rule.checkTxRecipients(block); await local_rule.checkTxAmounts(block); await local_rule.checkTxSignature(block); done && done(); } catch (err) { if (done) return done(err); throw err; if (!options || !options.dontCareAboutChaining) { await local_rule.checkMaxTransactionChainingDepth(block, conf, index); } })() } Loading @@ -411,9 +453,13 @@ export const LOCAL_RULES_HELPERS = { checkSingleMembershipSignature: checkSingleMembershipSignature, checkBunchOfTransactions: checkBunchOfTransactions, checkBunchOfTransactions, getTransactionDepth, getMaxTransactionDepth, checkSingleTransactionLocally: (tx:any, done:any = undefined) => checkBunchOfTransactions([tx], done), checkSingleTransactionLocally: (tx:any, conf:ConfDTO) => checkBunchOfTransactions([tx], conf), checkTxAmountsValidity: (tx:TransactionDTO) => { const inputs = tx.inputsAsObjects() Loading app/modules/prover/lib/blockGenerator.ts +5 −9 Original line number Diff line number Diff line Loading @@ -65,7 +65,7 @@ export class BlockGenerator { const wereExcludeds = await this.dal.getRevokedPubkeys(); const newCertsFromWoT = await generator.findNewCertsFromWoT(current); const newcomersLeavers = await this.findNewcomersAndLeavers(current, (joinersData:any) => generator.filterJoiners(joinersData)); const transactions = await this.findTransactions(current); const transactions = await this.findTransactions(current, manualValues); const joinData = newcomersLeavers[2]; const leaveData = newcomersLeavers[3]; const newCertsFromNewcomers = newcomersLeavers[4]; Loading Loading @@ -104,7 +104,8 @@ export class BlockGenerator { return [cur, newWoTMembers, finalJoinData, leavers, updates]; } private async findTransactions(current:DBBlock) { private async findTransactions(current:DBBlock, options:{ dontCareAboutChaining?:boolean }) { const ALSO_CHECK_PENDING_TXS = true const versionMin = current ? Math.min(CommonConstants.LAST_VERSION_FOR_TX, current.version) : CommonConstants.DOCUMENTS_VERSION; const txs = await this.dal.getTransactionsPending(versionMin); const transactions = []; Loading @@ -113,14 +114,9 @@ export class BlockGenerator { obj.currency = this.conf.currency const tx = TransactionDTO.fromJSONObject(obj); try { await new Promise((resolve, reject) => { LOCAL_RULES_HELPERS.checkBunchOfTransactions(passingTxs.concat(tx), (err:any, res:any) => { if (err) return reject(err) return resolve(res) }) }) await LOCAL_RULES_HELPERS.checkBunchOfTransactions(passingTxs.concat(tx), this.conf, options) const nextBlockWithFakeTimeVariation = { medianTime: current.medianTime + 1 }; await GLOBAL_RULES_HELPERS.checkSingleTransaction(tx, nextBlockWithFakeTimeVariation, this.conf, this.dal); await GLOBAL_RULES_HELPERS.checkSingleTransaction(tx, nextBlockWithFakeTimeVariation, this.conf, this.dal, ALSO_CHECK_PENDING_TXS); await GLOBAL_RULES_HELPERS.checkTxBlockStamp(tx, this.dal); transactions.push(tx); passingTxs.push(tx); Loading Loading
.gitignore +4 −0 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ test/integration/documents-currency.d.ts test/integration/forwarding.js test/integration/branches_switch.js test/integration/branches2.js test/integration/transactions-chaining.js test/fast/modules/crawler/block_pulling.js* test/fast/modules/crawler/block_pulling.d.ts test/fast/fork*.js* Loading @@ -72,3 +73,6 @@ test/fast/modules/common/grammar.d.ts test/fast/prover/pow-1-cluster.d.ts test/fast/prover/pow-1-cluster.js test/fast/prover/pow-1-cluster.js.map test/fast/protocol-local-rule-chained-tx-depth.js test/fast/protocol-local-rule-chained-tx-depth.js.map test/fast/protocol-local-rule-chained-tx-depth.d.ts
app/lib/common-libs/constants.ts +2 −0 Original line number Diff line number Diff line Loading @@ -285,6 +285,8 @@ export const CommonConstants = { BLOCK: find("Block: (" + INTEGER + "-" + FINGERPRINT + ")"), SPECIAL_BLOCK }, BLOCK_MAX_TX_CHAINING_DEPTH: 5 } function exact (regexpContent:string) { Loading
app/lib/rules/index.ts +2 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ export const ALIAS = { await LOCAL_RULES_FUNCTIONS.checkTxRecipients(block); await LOCAL_RULES_FUNCTIONS.checkTxAmounts(block); await LOCAL_RULES_FUNCTIONS.checkTxSignature(block); await LOCAL_RULES_FUNCTIONS.checkMaxTransactionChainingDepth(block, conf, index); }, ALL_LOCAL_BUT_POW_AND_SIGNATURE: async (block:BlockDTO, conf:ConfDTO, index:IndexEntry[]) => { Loading Loading @@ -60,6 +61,7 @@ export const ALIAS = { await LOCAL_RULES_FUNCTIONS.checkTxRecipients(block); await LOCAL_RULES_FUNCTIONS.checkTxAmounts(block); await LOCAL_RULES_FUNCTIONS.checkTxSignature(block); await LOCAL_RULES_FUNCTIONS.checkMaxTransactionChainingDepth(block, conf, index); } } Loading
app/lib/rules/local_rules.ts +62 −16 Original line number Diff line number Diff line Loading @@ -379,17 +379,61 @@ export const LOCAL_RULES_FUNCTIONS = { } } return true; }, checkMaxTransactionChainingDepth: async (block:BlockDTO, conf:ConfDTO, index:IndexEntry[]) => { const sindex = Indexer.sindex(index) const max = getMaxTransactionDepth(sindex) // const allowedMax = block.medianTime > 1517443200 ? CommonConstants.BLOCK_MAX_TX_CHAINING_DEPTH : 1 if (max > allowedMax) { throw "The maximum transaction chaining length per block is " + CommonConstants.BLOCK_MAX_TX_CHAINING_DEPTH } return true } } export interface SindexShortEntry { op:string, identifier:string, pos:number, tx:string|null } function getMaxTransactionDepth(sindex:SindexShortEntry[]) { const ids = _.uniq(_.pluck(sindex, 'tx')) let maxTxChainingDepth = 0 for (let id of ids) { maxTxChainingDepth = Math.max(maxTxChainingDepth, getTransactionDepth(id, sindex, 0)) } return maxTxChainingDepth } function getTransactionDepth(txHash:string, sindex:SindexShortEntry[], localDepth = 0) { const inputs = _.filter(sindex, (s:SindexShortEntry) => s.op === 'UPDATE' && s.tx === txHash) let depth = localDepth for (let input of inputs) { const consumedOutput = _.findWhere(sindex, { op: 'CREATE', identifier: input.identifier, pos: input.pos }) if (consumedOutput) { if (localDepth < 5) { const subTxDepth = getTransactionDepth(consumedOutput.tx, sindex, localDepth + 1) depth = Math.max(depth, subTxDepth) } else { depth++ } } } return depth } function checkSingleMembershipSignature(ms:any) { return verify(ms.getRaw(), ms.signature, ms.issuer); } function checkBunchOfTransactions(transactions:TransactionDTO[], done:any = undefined){ const block:any = { transactions }; function checkBunchOfTransactions(transactions:TransactionDTO[], conf:ConfDTO, options?:{ dontCareAboutChaining?:boolean }){ const block:any = { transactions, identities: [], joiners: [], actives: [], leavers: [], revoked: [], excluded: [], certifications: [] }; const index = Indexer.localIndex(block, conf) return (async () => { try { let local_rule = LOCAL_RULES_FUNCTIONS; await local_rule.checkTxLen(block); await local_rule.checkTxIssuers(block); Loading @@ -397,10 +441,8 @@ function checkBunchOfTransactions(transactions:TransactionDTO[], done:any = unde await local_rule.checkTxRecipients(block); await local_rule.checkTxAmounts(block); await local_rule.checkTxSignature(block); done && done(); } catch (err) { if (done) return done(err); throw err; if (!options || !options.dontCareAboutChaining) { await local_rule.checkMaxTransactionChainingDepth(block, conf, index); } })() } Loading @@ -411,9 +453,13 @@ export const LOCAL_RULES_HELPERS = { checkSingleMembershipSignature: checkSingleMembershipSignature, checkBunchOfTransactions: checkBunchOfTransactions, checkBunchOfTransactions, getTransactionDepth, getMaxTransactionDepth, checkSingleTransactionLocally: (tx:any, done:any = undefined) => checkBunchOfTransactions([tx], done), checkSingleTransactionLocally: (tx:any, conf:ConfDTO) => checkBunchOfTransactions([tx], conf), checkTxAmountsValidity: (tx:TransactionDTO) => { const inputs = tx.inputsAsObjects() Loading
app/modules/prover/lib/blockGenerator.ts +5 −9 Original line number Diff line number Diff line Loading @@ -65,7 +65,7 @@ export class BlockGenerator { const wereExcludeds = await this.dal.getRevokedPubkeys(); const newCertsFromWoT = await generator.findNewCertsFromWoT(current); const newcomersLeavers = await this.findNewcomersAndLeavers(current, (joinersData:any) => generator.filterJoiners(joinersData)); const transactions = await this.findTransactions(current); const transactions = await this.findTransactions(current, manualValues); const joinData = newcomersLeavers[2]; const leaveData = newcomersLeavers[3]; const newCertsFromNewcomers = newcomersLeavers[4]; Loading Loading @@ -104,7 +104,8 @@ export class BlockGenerator { return [cur, newWoTMembers, finalJoinData, leavers, updates]; } private async findTransactions(current:DBBlock) { private async findTransactions(current:DBBlock, options:{ dontCareAboutChaining?:boolean }) { const ALSO_CHECK_PENDING_TXS = true const versionMin = current ? Math.min(CommonConstants.LAST_VERSION_FOR_TX, current.version) : CommonConstants.DOCUMENTS_VERSION; const txs = await this.dal.getTransactionsPending(versionMin); const transactions = []; Loading @@ -113,14 +114,9 @@ export class BlockGenerator { obj.currency = this.conf.currency const tx = TransactionDTO.fromJSONObject(obj); try { await new Promise((resolve, reject) => { LOCAL_RULES_HELPERS.checkBunchOfTransactions(passingTxs.concat(tx), (err:any, res:any) => { if (err) return reject(err) return resolve(res) }) }) await LOCAL_RULES_HELPERS.checkBunchOfTransactions(passingTxs.concat(tx), this.conf, options) const nextBlockWithFakeTimeVariation = { medianTime: current.medianTime + 1 }; await GLOBAL_RULES_HELPERS.checkSingleTransaction(tx, nextBlockWithFakeTimeVariation, this.conf, this.dal); await GLOBAL_RULES_HELPERS.checkSingleTransaction(tx, nextBlockWithFakeTimeVariation, this.conf, this.dal, ALSO_CHECK_PENDING_TXS); await GLOBAL_RULES_HELPERS.checkTxBlockStamp(tx, this.dal); transactions.push(tx); passingTxs.push(tx); Loading