From a289a4b2ad9760c96574ee747c93bbbf1a7927f7 Mon Sep 17 00:00:00 2001 From: "luk.lu" Date: Thu, 11 Apr 2019 15:59:26 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E6=8A=8A=20validateMe=20=E5=88=86?= =?UTF-8?q?=E8=A7=A3=E6=88=90=20=E9=9D=99=E6=80=81=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=A3=80=E6=9F=A5=EF=BC=88=E7=BB=99=E5=AE=A2=E6=88=B7=E7=AB=AF?= =?UTF-8?q?=E8=B0=83=E7=94=A8=EF=BC=89validateMe=20=E5=92=8C=20=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E5=8F=AF=E6=89=A7=E8=A1=8C=E6=80=A7=E6=A3=80=E6=9F=A5?= =?UTF-8?q?=EF=BC=88=E7=BB=99=E9=93=BE=E8=8A=82=E7=82=B9=E8=B0=83=E7=94=A8?= =?UTF-8?q?=EF=BC=89executableMe.=202.=20=E5=9C=A8=20Action.api.prepare()?= =?UTF-8?q?=20=E9=87=8C=EF=BC=8C=E7=94=9F=E6=88=90=E5=8F=AF=E8=BF=90?= =?UTF-8?q?=E8=A1=8C=E7=9A=84=E5=AF=B9=E8=B1=A1=20typedAction=20=E5=AD=98?= =?UTF-8?q?=E5=85=A5=20ActionPool=EF=BC=8C=E8=80=8C=E4=B8=8D=E6=98=AF?= =?UTF-8?q?=E4=BB=85=E4=BB=85=E5=AD=98=E6=95=B0=E6=8D=AE=20option.Action?= =?UTF-8?q?=E8=BF=9B=E5=8E=BB=E3=80=82=203.=20=E5=88=A0=E9=99=A4=20Action.?= =?UTF-8?q?getJson()=EF=BC=8C=E6=8A=8A=20DAD.verifyXxx(action)=20=E9=83=BD?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=20MOM.verifyXxx().=204.=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E4=BA=86=20ActionRegisterChain.js=20=E4=BD=9C=E4=B8=BA=20?= =?UTF-8?q?=E5=BA=94=E7=94=A8=E9=93=BE=E6=B3=A8=E5=86=8C=E4=BA=8B=E5=8A=A1?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Action.js | 105 ++++++++++++++++++++++++++--------------- ActionMultisig.js | 25 +++++----- ActionRegisterChain.js | 36 ++++++++++++++ ActionStore.js | 8 +++- ActionTransfer.js | 10 ++-- 5 files changed, 129 insertions(+), 55 deletions(-) create mode 100644 ActionRegisterChain.js diff --git a/Action.js b/Action.js index bae21af..ba201ca 100644 --- a/Action.js +++ b/Action.js @@ -1,5 +1,5 @@ var Ling = require('fon.ling') -var Ticrypto = require('tic.crypto') +var ticCrypto = require('tic.crypto') /** ****************** Public of instance ********************/ @@ -35,7 +35,7 @@ MOM._model = { MOM.packMe = function (keypair) { // 由前端调用,后台不创建 this.actorPubkey = keypair.pubkey - this.actorAddress = Ticrypto.pubkey2address(keypair.pubkey) + this.actorAddress = ticCrypto.pubkey2address(keypair.pubkey) this.timestamp = new Date() this.signMe(keypair.seckey) @@ -45,61 +45,88 @@ MOM.packMe = function (keypair) { // 由前端调用,后台不创建 MOM.signMe = function (seckey) { // 由前端调用,后台不该进行签名 let json = this.getJson({ exclude: ['hash', 'blockHash', 'actorSignature'] }) // 是前端用户发起事务时签字,这时候还不知道进入哪个区块,所以不能计入blockHash - this.actorSignature = Ticrypto.sign(json, seckey) + this.actorSignature = ticCrypto.sign(json, seckey) return this } MOM.hashMe = function () { - this.hash = Ticrypto.hash(this.getJson({ exclude: ['hash', 'blockHash'] })) // block.hash 受到所包含的actionList影响,所以action不能受blockHash影响,否则循环了 + this.hash = ticCrypto.hash(this.getJson({ exclude: ['hash', 'blockHash'] })) // block.hash 受到所包含的actionList影响,所以action不能受blockHash影响,否则循环了 return this } -DAD.getJson = function (action, option = {}) { - let data = {} - let sortedKey = Object.keys(DAD.prototype._model).sort() - for (let exkey of option.exclude) { sortedKey.splice(sortedKey.indexOf(exkey), 1) } - for (let key of sortedKey) { // 忽略一些不需要签名的属性 - data[key] = action[key] +MOM.verifySig = function() { + let json = this.getJson({ exclude: ['hash', 'blockHash', 'actorSignature'] }) + let result = ticCrypto.verify(json, this.actorSignature, this.actorPubkey) + return result +} +DAD.verifySig = function (actionData) { + let typedAction = new wo[actionData.type](actionData) + return typedAction.verifySig() +} + +MOM.verifyAddress = function () { + return this.actorAddress === ticCrypto.pubkey2address(this.actorPubkey) +} +DAD.verifyAddress = function (actionData) { + let typedAction = new wo[actionData.type](actionData) + return typedAction.verifyAddress() +} + +MOM.verifyHash = function () { + return this.hash === ticCrypto.hash(this.getJson({ exclude: ['hash', 'blockHash'] })) +} +DAD.verifyHash = function (actionData) { + let typedAction = new wo[actionData.type](actionData) + return typedAction.verifyHash() +} + +DAD.build = function (action, keypair) { // Applicable on client. 客户端调用 Action.build,即可新建、并打包成一个完整的子事务,不需要亲自调用 constructor, packMe 等方法。 + if (action && action.type && keypair && keypair.seckey && keypair.pubkey) { + let typedAction = new wo[action.type](action) + if (typedAction.validateMe()) { + typedAction.packMe(keypair) + return typedAction + } } - let json = JSON.stringify(data) - return json + return null } -DAD.verifySig = function (action) { - let json = DAD.getJson(action, { exclude: ['hash', 'blockHash', 'actorSignature'] }) - let res = Ticrypto.verify(json, action.actorSignature, action.actorPubkey) - return res -} - -DAD.verifyAddress = function (action) { - return action.actorAddress === Ticrypto.pubkey2address(action.actorPubkey) -} - -DAD.verifyHash = function (action) { - return action.hash === Ticrypto.hash(DAD.getJson(action, { exclude: ['hash', 'blockHash'] })) -} - -MOM.validateMe = async function() { // 子类应当覆盖本方法。 +MOM.validateMe = function() { // Applicable on chain server. 子类应当覆盖本方法,静态的检查事务内容的格式和语义,是否符合该子类事务的特性要求。To validate an action's content format. // to implement in subclasses: 检查子类事务内容的格式 let typedAction = new wo[this.type](this) - return await typedAction.validateMe() + return typedAction.validateMe() } -DAD.validate = async function (action) { +DAD.validate = function (action) { // Allicable on both client and chain server. mylog.info(`Validating action type=${action.type} of hash=${action.hash}`) let typedAction = new wo[action.type](action) - return await typedAction.validateMe() + return typedAction.validateMe() } -MOM.executeMe = async function() { // 子类应当覆盖本方法。 +MOM.executableMe = async function() { // Applicable on chain server. 子类应当覆盖本方法,动态的检查事务内容,在当前链状态下,是否能执行。To check if an action is executableMe given the current chain status. + let typedAction = new wo[this.type](this) + return await typedAction.executableMe() +} +DAD.executable = async function(action) { // For chain server. + let typedAction = new wo[action.type](action) + if (typedAction.hasOwnProperty('executableMe')) { // 防止子类忘了定义自己的 executableMe + return await typedAction.executableMe() + }else { + return true + } +} +MOM.executeMe = async function() { // For chain server. 子类应当覆盖本方法,执行事务,记录其(除了存入 Action 数据表之外的)副作用到内存数据库或其他地方。 // to implement in subclasses: 把action的影响,汇总登记到其他表格(用于辅助的、索引的表格),方便快速索引、处理。每种事务类型都要重定义这个方法。 let typedAction = new wo[this.type](this) return await typedAction.executeMe() } -DAD.execute = async function (action) { +DAD.execute = async function (action) { // For chain server. mylog.info(`Excecuting action type=${action.type} of hash=${action.hash}`) let typedAction = new wo[action.type](action) return await typedAction.executeMe() } +// [todo 20190411] 执行事务池中的所有事务 +// DAD.executePool = async function() { +// } /** * 获取一批交易,在出块时调用。调用actionPool的内容被深拷贝到currentActionPool后自动清空。 @@ -137,14 +164,16 @@ DAD.api.prepare = async function (option) { } catch (error) {} } // 前端发来action数据,进行格式检查(不检查是否可执行--这和事务类型、执行顺序有关)后放入缓冲池。 - if (option && option.Action && option.Action.type && option.Action.hash && !DAD.actionPool[option.Action.hash]) { - if (DAD.verifyAddress(option.Action) && // 只检查所有事务通用的格式 - DAD.verifySig(option.Action) && - DAD.verifyHash(option.Action) && + if (option && option.Action && option.Action.type && wo[option.Action.type] && option.Action.hash && !DAD.actionPool[option.Action.hash]) { + let typedAction = new wo[option.Action.type](option.Action) + if (typedAction.verifyAddress() && // 只检查所有事务通用的格式 + typedAction.verifySig() && + typedAction.verifyHash() && !DAD.actionPool[option.Action.hash] && - (await DAD.validate(option.Action)) // 调用子类的 validate 方法,检查子类的事务内容格式 + typedAction.validateMe() && // 检查事务的内容是否符合该子类事务的格式 + (await typedAction.executableMe()) // 检查事务是否可执行,在当前链的状态下。 ) { - DAD.actionPool[option.Action.hash] = option.Action + DAD.actionPool[option.Action.hash] = typedAction DAD.actionPoolInfo.totalAmount += option.Action.amount || 0 DAD.actionPoolInfo.totalFee += option.Action.fee || 0 wo.NodeNet.broadcast({ Action: option.Action }) diff --git a/ActionMultisig.js b/ActionMultisig.js index 0138d58..56bbefb 100644 --- a/ActionMultisig.js +++ b/ActionMultisig.js @@ -137,28 +137,28 @@ step3:发起人申请执行 } } */ + MOM.validateMe = async function () { - if (this.json.act === 'createTransfer') // 创建挂起的多重签名事务 - { + return wo.Crypto.isAddress(this.toAddress) && + this.fee >= wo.Config.MIN_FEE_ActionTransfer && + this.toAddress != this.actorAddress +} + +MOM.executableMe = async function () { + if (this.json.act === 'createTransfer') { // 创建挂起的多重签名事务 DAD.pendingPool[this.hash] = this return false - } else if (this.json.act === 'addSig') // 签名者签名 - { + } else if (this.json.act === 'addSig') { // 签名者签名 DAD.pendingPool[this.hash].json[this.actorPubkey] = this.json.signature return false - } else { - return wo.Crypto.isAddress(this.toAddress) && - this.fee >= wo.Config.MIN_FEE_ActionTransfer && - (await wo.Store.getBalance(this.actorAddress)) >= this.amount + this.fee && // Todo:引入缓存账户 - this.toAddress != this.actorAddress } + return true } MOM.executeMe = async function () { switch (this.json.act) { // 多重签名账户注册 - case 'sign': - { + case 'sign': { let actor = await wo.Account.getOne({ Account: { address: this.actorAddress } }) if (actor && actor.type !== 'multisig') { // 检查账户类型,只有不是多重签名账户的才可以执行 @@ -173,8 +173,7 @@ MOM.executeMe = async function () { return this } // 多重签名账户执行转账 - case 'emitTransfer': - { + case 'emitTransfer': { let sender = await wo.Account.getOne({ Account: { address: this.actorAddress } }) if (sender && this.checkMultiSig(sender) && this.toAddress != this.actorAddress && sender.balance >= this.amount + this.fee) { await sender.setMe({ Account: { balance: sender.balance - this.amount - this.fee }, cond: { address: sender.address } }) diff --git a/ActionRegisterChain.js b/ActionRegisterChain.js new file mode 100644 index 0000000..caa0810 --- /dev/null +++ b/ActionRegisterChain.js @@ -0,0 +1,36 @@ +const Action = require('./Action.js') + +const DAD = module.exports = function ActionRegisterChain (prop) { + this._class = this.constructor.name + this.setProp(prop) // 没有定义 ActionTransfer.prototype._model,因此继承了上级Action.prototype._model,因此通过this.setProp,继承了上级Action定义的实例自有数据。另一个方案是,调用 Action.call(this, prop) + this.type = this.constructor.name +} +DAD.__proto__ = Action +const MOM = DAD.prototype +MOM.__proto__ = Action.prototype + +MOM.validateMe = function () { + let result = (this.fee >= wo.Config.MIN_FEE_ActionRegisterChain || 0) && + // 检查事务内容数据,是否符合本类事务的格式和语义要求: + this.json && + this.json.consensus && // 共识机制 + this.json.network && // 网络机制 + this.json.chain && // 区块机制 + this.json.chain.period && // 出块周期 + this.json.chain.size // 区块大小 + return result +} + +MOM.executableMe = async function() { + // todo: 检查是否已有同名的应用链?以及其他检查。 + let balance = await wo.Store.getBalance(this.actorAddress) + return balance >= this.fee +} + +MOM.executeMe = async function () { + return this +} + +/** ****************** Public of class ********************/ + +DAD.api = {} diff --git a/ActionStore.js b/ActionStore.js index 10879ab..4907200 100644 --- a/ActionStore.js +++ b/ActionStore.js @@ -16,7 +16,13 @@ MOM.__proto__ = Action.prototype MOM.validateMe = function () { // check size, account balance >= fee, fee>wo.Config.MIN_FEE_ActionStore - return this.fee >= wo.Config.MIN_FEE_ActionStore + return (this.fee >= wo.Config.MIN_FEE_ActionStore || 0) +} + +MOM.executableMe = async function (){ + let balance = await wo.Store.getBalance(this.actorAddress) + return balance >= this.fee && + true // todo: 检查服务器上的存储容量是否还够用? } MOM.executeMe = async function () { diff --git a/ActionTransfer.js b/ActionTransfer.js index 693a8ab..98fb591 100644 --- a/ActionTransfer.js +++ b/ActionTransfer.js @@ -9,11 +9,15 @@ DAD.__proto__ = Action const MOM = DAD.prototype MOM.__proto__ = Action.prototype -MOM.validateMe = async function () { +MOM.validateMe = function () { // if (sender && sender.type !== 'multisig' && action.toAddress != action.actorAddress && sender.balance >= action.amount + action.fee){ - let balance = await wo.Store.getBalance(this.actorAddress) return this.actorAddress && this.toAddress && this.toAddress != this.actorAddress - && this.amount && this.amount > 0 && this.fee >= wo.Config.MIN_FEE_ActionTransfer && balance >= this.amount + this.fee + && this.amount && this.amount > 0 && (this.fee >= wo.Config.MIN_FEE_ActionTransfer || 0) +} + +MOM.executableMe = async function() { + let balance = await wo.Store.getBalance(this.actorAddress) + return balance >= this.amount + this.fee } MOM.executeMe = async function () {