124 lines
5.2 KiB
JavaScript
124 lines
5.2 KiB
JavaScript
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 = {
|
||
}
|