From 89975eea2c5346c6e3c4a2c1d6f21da890919e97 Mon Sep 17 00:00:00 2001 From: "luk.lu" Date: Tue, 27 Nov 2018 10:42:05 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=8Etic.common=E8=BD=AC=E5=8C=96=E8=80=8C?= =?UTF-8?q?=E6=9D=A5=EF=BC=8C=E5=BD=BB=E5=BA=95=E8=84=B1=E7=A6=BB=E5=AF=B9?= =?UTF-8?q?=20Base/*,=20=5FLing.js=20=E7=9A=84=E4=BE=9D=E8=B5=96=EF=BC=8C?= =?UTF-8?q?=E5=8F=AA=E4=BF=9D=E7=95=99=E5=B9=B6=E6=8F=90=E4=BE=9B=20Action?= =?UTF-8?q?=E5=8F=8A=E5=85=B6=E5=AD=90=E7=B1=BB=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 7 +++ index.js | 6 +++ ling/ActTransfer.js | 40 ++++++++++++++ ling/Action.js | 123 ++++++++++++++++++++++++++++++++++++++++++++ package.json | 11 ++++ 5 files changed, 187 insertions(+) create mode 100644 .gitignore create mode 100644 index.js create mode 100644 ling/ActTransfer.js create mode 100644 ling/Action.js create mode 100644 package.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..46dd5c4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +# 以'#'开始的行,被视为注释. +node_modules +package-lock.json +.vscode +.svn +~* +.gitattributes diff --git a/index.js b/index.js new file mode 100644 index 0000000..bb4d7f0 --- /dev/null +++ b/index.js @@ -0,0 +1,6 @@ +const Action = require('./ling/Action.js') +const ActTransfer = require('./ling/ActTransfer.js') +module.exports = { + Action, + ActTransfer +} \ No newline at end of file diff --git a/ling/ActTransfer.js b/ling/ActTransfer.js new file mode 100644 index 0000000..b26b409 --- /dev/null +++ b/ling/ActTransfer.js @@ -0,0 +1,40 @@ +const Action = require('./Action.js') +const Ticrypto = wo&&wo.Crypto?wo.Crypto:require('tic.crypto') + +/******************** Public of instance ********************/ + +const DAD=module.exports=function ActTransfer(prop) { + this._class='ActTransfer' + this.setProp(prop) // 没有定义 ActTransfer.prototype._model,因此继承了上级Action.prototype._model,因此通过this.setProp,继承了上级Action定义的实例自有数据。另一个方案是,调用 Action.call(this, prop) + this.type='ActTransfer' +} +DAD.__proto__= Action +// DAD._table=DAD.name // 注释掉,从而继承父类Action的数据库表格名 +const MOM=DAD.prototype +MOM.__proto__=Action.prototype + +/******************** Shared by instances ********************/ + +MOM.validate=function(){ + // return Ticrypto.isAddress(this.toAddress) + return Ticrypto.isAddress(this.toAddress) && this.fee>=wo.Config.MIN_FEE_ActTransfer + // && wo.Account.accountPool[this.actorAddress].balance>this.amount+this.fee //Todo:引入缓存账户 + &&this.toAddress != this.actorAddress +} + +MOM.execute=async function(){ + let sender= await wo.Account.getOne({Account: { address: this.actorAddress }}) + if (sender && sender.type !== 'multisig' && 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}}) + let getter= await wo.Account.getOne({Account: { address: this.toAddress }}) || await wo.Account.addOne({Account: { address: this.toAddress }}) + await getter.setMe({Account:{ balance: getter.balance+this.amount }, cond:{ address:getter.address}}) + // mylog.info('Excecuted action='+JSON.stringify(this)) + return this + } + // mylog.info('balance('+sender.address+')='+sender.balance+' is less than '+this.amount+', 无法转账') + return null +} + +/******************** Public of class ********************/ + +DAD.api={} diff --git a/ling/Action.js b/ling/Action.js new file mode 100644 index 0000000..1952e3a --- /dev/null +++ b/ling/Action.js @@ -0,0 +1,123 @@ +const Ling = wo&&wo.Ling?wo.Ling:require('fon.ling') +const Ticrypto = wo&&wo.Crypto?wo.Crypto:require('tic.crypto') + +/******************** Public of instance ********************/ + +const DAD=module.exports=function Action(prop) { + this._class=this.constructor.name + this.setProp(prop) +} +DAD.__proto__=Ling +DAD._table=DAD.name +const MOM=DAD.prototype +MOM.__proto__=Ling.prototype + +/******************** Shared by instances ********************/ +MOM._tablekey='hash' +MOM._model= { + hash: { default:undefined, sqlite:'TEXT UNIQUE', mysql:'VARCHAR(64) PRIMARY KEY' }, // 不纳入签名和哈希 + version: { default:0, sqlite:'INTEGER' }, + type: { default:'Action', sqlite:'TEXT', mysql:'VARCHAR(100)' }, // 是否放在 assets里更好?这里该放action自己的version + blockHash: { default:undefined, sqlite:'TEXT', mysql:'VARCHAR(64)' }, // 不纳入签名和哈希。只为了方便查找 + timestamp: { default:undefined, sqlite:'TEXT', mysql:'CHAR(24)' }, + actorPubkey: { default:undefined, sqlite:'TEXT', mysql:'BINARY(32)' }, + actorAddress: { default:undefined, sqlite:'TEXT', mysql:'VARCHAR(50)' }, + actorSignature:{ default:undefined, sqlite:'TEXT', mysql:'BINARY(64)' }, // 不纳入签名,纳入哈希 + toAddress: { default:undefined, sqlite:'TEXT', mysql:'VARCHAR(50)' }, + amount: { default:0, sqlite:'NUMERIC', mysql:'BIGINT' }, + fee: { default:0, sqlite:'NUMERIC', mysql:'BIGINT' }, +// signSignature: { default:undefined, sqlite:'TEXT', mysql:'BINARY(64)' }, // 不纳入签名,纳入哈希 +// requesterPubkey:{ default:undefined, sqlite:'TEXT', mysql:'BINARY(32)' }, +// signatures: { default:undefined, sqlite:'TEXT', mysql:'TEXT' }, +// option: { default:undefined, sqlite:'TEXT', mysql:'VARCHAR(4096)' }, +// act: { default:null, sqlite:'TEXT' }, // 相当于 asch/lisk里的asset + message: { default:undefined, sqlite:'TEXT', mysql:'VARCHAR(256)' }, + dataIndex: { default:undefined, sqlite:'TEXT', mysql:'VARCHAR(50)'}, //用于索引json中存储数据, + json: { default:{}, sqlite:'TEXT' } // 开发者自定义字段,可以用json格式添加任意数据,而不破坏整体结构 +} + +MOM.packMe = function(keypair){ // 由前端调用,后台不创建 + this.actorPubkey=keypair.pubkey + this.actorAddress=Ticrypto.pubkey2address(keypair.pubkey) + this.timestamp=new Date() + + this.signMe(keypair.seckey) + this.hashMe() + return this +} + +MOM.signMe = function(seckey){ // 由前端调用,后台不该进行签名 + let json=this.getJson({exclude:['hash','blockHash','actorSignature']}) // 是前端用户发起事务时签字,这时候还不知道进入哪个区块,所以不能计入blockHash + this.actorSignature=Ticrypto.sign(json, seckey) + return this +} + +MOM.verifySig = function(){ + let json=this.getJson({exclude:['hash','blockHash','actorSignature']}) + let res=Ticrypto.verify(json, this.actorSignature, this.actorPubkey) + return res +} + +MOM.verifyAddress = function(){ + return this.actorAddress===Ticrypto.pubkey2address(this.actorPubkey) +} + +MOM.hashMe = function(){ + this.hash=Ticrypto.hash(this.getJson({exclude:['hash', 'blockHash']})) // block.hash 受到所包含的actionList影响,所以action不能受blockHash影响,否则循环了 + return this +} + +MOM.verifyHash = function(){ + return this.hash===Ticrypto.hash(this.getJson({exclude:['hash', 'blockHash']})) +} + +MOM.execute=function(){ // 子类应当覆盖本方法。把action的影响,汇总登记到其他表格(用于辅助的、索引的表格),方便快速索引、处理。每种事务类型都要重定义这个方法。 + // save to account or other tables + return this +} + +MOM.validate=function(){ // 子类应当覆盖本方法 + return true +} + +MOM.calculateFee = function(){ + return 1000 +} + +// DAD._init=async function(){ +// await DAD.__proto__._init() // create database table at first +// await DAD.actionLoop() +// return this +// } + +/*********************** Public of class *******************/ +DAD.api={} + +DAD.api.getAction=async function(option){ + return await DAD.getOne(option) +} + +DAD.api.getActionList=async function(option){ + return await DAD.getAll(option) +} + +DAD.api.prepare=async function(option){ // 前端发来action数据,进行初步检查(不检查是否可执行--这和事务类型、执行顺序有关,只检查格式是否有效--这是所有事务通用的规范)后放入缓冲池。 + if (option && option.Action && option.Action.type && option.Action.hash && !DAD.actionPool[option.Action.hash]) { + let action=new wo[option.Action.type](option.Action) // 一次性把option.Action里送来的参数导入新建的action + if (action.verifyAddress() && action.verifySig() && action.verifyHash() // 对所有Action类型都通用的验证 + && action.validate()) { // 各子类特有的验证 + // mylog.info('Received action='+JSON.stringify(action)) + DAD.actionPool[action.hash]=action + wo.Peer.broadcast('/Action/prepare', option) + return action + } + } + return null // 非法的交易数据 +} + +/********************** Private in class *******************/ + +DAD.actionPool={} // 随时不断接收新的交易请求 + +const my = { +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..5825a79 --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "name": "tic.common", + "version": "0.1.5", + "dependencies": { + "fon.ling": "git+https://git.faronear.org/fon/fon.ling", + "tic.crypto": "git+https://git.faronear.org/tic/tic.crypto" + }, + "devDependencies": {}, + "scripts": {}, + "author": "" +}