从tic.common转化而来,彻底脱离对 Base/*, _Ling.js 的依赖,只保留并提供 Action及其子类。

This commit is contained in:
luk.lu 2018-11-27 10:42:05 +08:00
commit 89975eea2c
5 changed files with 187 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
# 以'#'开始的行,被视为注释.
node_modules
package-lock.json
.vscode
.svn
~*
.gitattributes

6
index.js Normal file
View File

@ -0,0 +1,6 @@
const Action = require('./ling/Action.js')
const ActTransfer = require('./ling/ActTransfer.js')
module.exports = {
Action,
ActTransfer
}

40
ling/ActTransfer.js Normal file
View File

@ -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={}

123
ling/Action.js Normal file
View File

@ -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 = {
}

11
package.json Normal file
View File

@ -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": ""
}