升级到目前最新的 node.server/modules/Action/*.js,其中重要的是,把 var Ling = wo&&wo.Ling?wo.Ling:require('fon.ling') 改成 var Ling = require('fon.ling')。原来的写法有 bug! 钱包前端引用了 tic.tool4chain 再引用了 tic.action,在浏览器里报错 "wo 不存在"。
This commit is contained in:
parent
dd0260c517
commit
1fd50f0294
@ -1,40 +1,28 @@
|
|||||||
const Action = require('./Action.js')
|
const Action = require('./Action.js')
|
||||||
const Ticrypto = wo&&wo.Crypto?wo.Crypto:require('tic.crypto')
|
|
||||||
|
const DAD = module.exports = function ActTransfer (prop) {
|
||||||
/******************** Public of instance ********************/
|
this._class = 'ActTransfer'
|
||||||
|
this.setProp(prop) // 没有定义 ActTransfer.prototype._model,因此继承了上级Action.prototype._model,因此通过this.setProp,继承了上级Action定义的实例自有数据。另一个方案是,调用 Action.call(this, prop)
|
||||||
const DAD=module.exports=function ActTransfer(prop) {
|
this.type = 'ActTransfer'
|
||||||
this._class='ActTransfer'
|
}
|
||||||
this.setProp(prop) // 没有定义 ActTransfer.prototype._model,因此继承了上级Action.prototype._model,因此通过this.setProp,继承了上级Action定义的实例自有数据。另一个方案是,调用 Action.call(this, prop)
|
DAD.__proto__ = Action
|
||||||
this.type='ActTransfer'
|
const MOM = DAD.prototype
|
||||||
}
|
MOM.__proto__ = Action.prototype
|
||||||
DAD.__proto__= Action
|
|
||||||
// DAD._table=DAD.name // 注释掉,从而继承父类Action的数据库表格名
|
DAD.validate = async function (action) {
|
||||||
const MOM=DAD.prototype
|
// if (sender && sender.type !== 'multisig' && action.toAddress != action.actorAddress && sender.balance >= action.amount + action.fee){
|
||||||
MOM.__proto__=Action.prototype
|
let sender = await wo.Store.getBalance(action.actorAddress)
|
||||||
|
return action.actorAddress && action.toAddress && action.toAddress != action.actorAddress && action.amount && action.amount > 0 && sender >= action.amount + action.fee && action.fee >= wo.Config.MIN_FEE_ActTransfer
|
||||||
/******************** Shared by instances ********************/
|
}
|
||||||
|
|
||||||
MOM.validate=function(){
|
DAD.execute = async function (action) {
|
||||||
// return Ticrypto.isAddress(this.toAddress)
|
let sender = await wo.Store.getBalance(action.actorAddress)
|
||||||
return Ticrypto.isAddress(this.toAddress) && this.fee>=wo.Config.MIN_FEE_ActTransfer
|
if (sender >= action.amount + action.fee) {
|
||||||
// && wo.Account.accountPool[this.actorAddress].balance>this.amount+this.fee //Todo:引入缓存账户
|
await wo.Store.decrease(action.actorAddress, action.amount + action.fee)
|
||||||
&&this.toAddress != this.actorAddress
|
await wo.Store.increase(action.toAddress, action.amount)
|
||||||
}
|
return true
|
||||||
|
}
|
||||||
MOM.execute=async function(){
|
return null
|
||||||
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}})
|
DAD.api = {}
|
||||||
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={}
|
|
||||||
|
179
ling/Action.js
179
ling/Action.js
@ -1,123 +1,144 @@
|
|||||||
const Ling = wo&&wo.Ling?wo.Ling:require('fon.ling')
|
var Ling = require('fon.ling')
|
||||||
const Ticrypto = wo&&wo.Crypto?wo.Crypto:require('tic.crypto')
|
var Ticrypto = require('tic.crypto')
|
||||||
|
|
||||||
/******************** Public of instance ********************/
|
/** ****************** Public of instance ********************/
|
||||||
|
|
||||||
const DAD=module.exports=function Action(prop) {
|
const DAD = module.exports = function Action (prop) {
|
||||||
this._class=this.constructor.name
|
this._class = this.constructor.name
|
||||||
this.setProp(prop)
|
this.setProp(prop)
|
||||||
}
|
}
|
||||||
DAD.__proto__=Ling
|
DAD.__proto__ = Ling
|
||||||
DAD._table=DAD.name
|
DAD._table = DAD.name
|
||||||
const MOM=DAD.prototype
|
const MOM = DAD.prototype
|
||||||
MOM.__proto__=Ling.prototype
|
MOM.__proto__ = Ling.prototype
|
||||||
|
|
||||||
/******************** Shared by instances ********************/
|
/** ****************** Shared by instances ********************/
|
||||||
MOM._tablekey='hash'
|
MOM._tablekey = 'hash'
|
||||||
MOM._model= {
|
MOM._model = {
|
||||||
hash: { default:undefined, sqlite:'TEXT UNIQUE', mysql:'VARCHAR(64) PRIMARY KEY' }, // 不纳入签名和哈希
|
hash: { default: undefined, sqlite: 'TEXT UNIQUE', mysql: 'VARCHAR(64) PRIMARY KEY' }, // 不纳入签名和哈希
|
||||||
version: { default:0, sqlite:'INTEGER' },
|
version: { default: 0, sqlite: 'INTEGER' },
|
||||||
type: { default:'Action', sqlite:'TEXT', mysql:'VARCHAR(100)' }, // 是否放在 assets里更好?这里该放action自己的version
|
type: { default: 'Action', sqlite: 'TEXT', mysql: 'VARCHAR(100)' }, // 是否放在 assets里更好?这里该放action自己的version
|
||||||
blockHash: { default:undefined, sqlite:'TEXT', mysql:'VARCHAR(64)' }, // 不纳入签名和哈希。只为了方便查找
|
blockHash: { default: undefined, sqlite: 'TEXT', mysql: 'VARCHAR(64)' }, // 不纳入签名和哈希。只为了方便查找
|
||||||
timestamp: { default:undefined, sqlite:'TEXT', mysql:'CHAR(24)' },
|
timestamp: { default: undefined, sqlite: 'TEXT', mysql: 'CHAR(24)' },
|
||||||
actorPubkey: { default:undefined, sqlite:'TEXT', mysql:'BINARY(32)' },
|
actorPubkey: { default: undefined, sqlite: 'TEXT', mysql: 'BINARY(32)' },
|
||||||
actorAddress: { default:undefined, sqlite:'TEXT', mysql:'VARCHAR(50)' },
|
actorAddress: { default: undefined, sqlite: 'TEXT', mysql: 'VARCHAR(50)' },
|
||||||
actorSignature:{ default:undefined, sqlite:'TEXT', mysql:'BINARY(64)' }, // 不纳入签名,纳入哈希
|
actorSignature: { default: undefined, sqlite: 'TEXT', mysql: 'BINARY(64)' }, // 不纳入签名,纳入哈希
|
||||||
toAddress: { default:undefined, sqlite:'TEXT', mysql:'VARCHAR(50)' },
|
toAddress: { default: undefined, sqlite: 'TEXT', mysql: 'VARCHAR(50)' },
|
||||||
amount: { default:0, sqlite:'NUMERIC', mysql:'BIGINT' },
|
amount: { default: 0, sqlite: 'NUMERIC', mysql: 'BIGINT' },
|
||||||
fee: { default:0, sqlite:'NUMERIC', mysql:'BIGINT' },
|
fee: { default: 0, sqlite: 'NUMERIC', mysql: 'BIGINT' },
|
||||||
// signSignature: { default:undefined, sqlite:'TEXT', mysql:'BINARY(64)' }, // 不纳入签名,纳入哈希
|
message: { default: undefined, sqlite: 'TEXT', mysql: 'VARCHAR(256)' },
|
||||||
// requesterPubkey:{ default:undefined, sqlite:'TEXT', mysql:'BINARY(32)' },
|
dataIndex: { default: undefined, sqlite: 'TEXT', mysql: 'VARCHAR(50)' }, // 用于索引json中存储数据,
|
||||||
// signatures: { default:undefined, sqlite:'TEXT', mysql:'TEXT' },
|
method: { default: undefined, sqlite: 'TEXT' },
|
||||||
// option: { default:undefined, sqlite:'TEXT', mysql:'VARCHAR(4096)' },
|
data: { default: undefined, sqlite: 'TEXT' }
|
||||||
// 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){ // 由前端调用,后台不创建
|
MOM.packMe = function (keypair) { // 由前端调用,后台不创建
|
||||||
this.actorPubkey=keypair.pubkey
|
this.actorPubkey = keypair.pubkey
|
||||||
this.actorAddress=Ticrypto.pubkey2address(keypair.pubkey)
|
this.actorAddress = Ticrypto.pubkey2address(keypair.pubkey)
|
||||||
this.timestamp=new Date()
|
this.timestamp = new Date()
|
||||||
|
|
||||||
this.signMe(keypair.seckey)
|
this.signMe(keypair.seckey)
|
||||||
this.hashMe()
|
this.hashMe()
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
MOM.signMe = function(seckey){ // 由前端调用,后台不该进行签名
|
MOM.signMe = function (seckey) { // 由前端调用,后台不该进行签名
|
||||||
let json=this.getJson({exclude:['hash','blockHash','actorSignature']}) // 是前端用户发起事务时签字,这时候还不知道进入哪个区块,所以不能计入blockHash
|
let json = this.getJson({ exclude: ['hash', 'blockHash', 'actorSignature'] }) // 是前端用户发起事务时签字,这时候还不知道进入哪个区块,所以不能计入blockHash
|
||||||
this.actorSignature=Ticrypto.sign(json, seckey)
|
this.actorSignature = Ticrypto.sign(json, seckey)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
MOM.verifySig = function(){
|
MOM.hashMe = function () {
|
||||||
let json=this.getJson({exclude:['hash','blockHash','actorSignature']})
|
this.hash = Ticrypto.hash(this.getJson({ exclude: ['hash', 'blockHash'] })) // block.hash 受到所包含的actionList影响,所以action不能受blockHash影响,否则循环了
|
||||||
let res=Ticrypto.verify(json, this.actorSignature, this.actorPubkey)
|
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]
|
||||||
|
}
|
||||||
|
let json = JSON.stringify(data)
|
||||||
|
return json
|
||||||
|
}
|
||||||
|
|
||||||
|
DAD.verifySig = function (action) {
|
||||||
|
let json = DAD.getJson(action, { exclude: ['hash', 'blockHash', 'actorSignature'] })
|
||||||
|
let res = Ticrypto.verify(json, action.actorSignature, action.actorPubkey)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
MOM.verifyAddress = function(){
|
DAD.verifyAddress = function (action) {
|
||||||
return this.actorAddress===Ticrypto.pubkey2address(this.actorPubkey)
|
return action.actorAddress === Ticrypto.pubkey2address(action.actorPubkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
MOM.hashMe = function(){
|
DAD.verifyHash = function (action) {
|
||||||
this.hash=Ticrypto.hash(this.getJson({exclude:['hash', 'blockHash']})) // block.hash 受到所包含的actionList影响,所以action不能受blockHash影响,否则循环了
|
return action.hash === Ticrypto.hash(DAD.getJson(action, { exclude: ['hash', 'blockHash'] }))
|
||||||
return this
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MOM.verifyHash = function(){
|
DAD.execute = function () { // 子类应当覆盖本方法。把action的影响,汇总登记到其他表格(用于辅助的、索引的表格),方便快速索引、处理。每种事务类型都要重定义这个方法。
|
||||||
return this.hash===Ticrypto.hash(this.getJson({exclude:['hash', 'blockHash']}))
|
|
||||||
}
|
|
||||||
|
|
||||||
MOM.execute=function(){ // 子类应当覆盖本方法。把action的影响,汇总登记到其他表格(用于辅助的、索引的表格),方便快速索引、处理。每种事务类型都要重定义这个方法。
|
|
||||||
// save to account or other tables
|
// save to account or other tables
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
MOM.validate=function(){ // 子类应当覆盖本方法
|
DAD.calculateFee = function () {
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
MOM.calculateFee = function(){
|
|
||||||
return 1000
|
return 1000
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 获取一批交易,在出块时调用。调用actionPool的内容被深拷贝到currentActionPool后自动清空。
|
||||||
|
* 所以在一次出块期间只能调用一次
|
||||||
|
*/
|
||||||
|
DAD.getActionBatch = function () {
|
||||||
|
let actionBatch = {
|
||||||
|
actionPool: JSON.parse(JSON.stringify(DAD.actionPool)), // deep copy
|
||||||
|
totalAmount: DAD.actionPoolInfo.totalAmount,
|
||||||
|
totalFee: DAD.actionPoolInfo.totalFee
|
||||||
|
}
|
||||||
|
DAD.actionPool = {}
|
||||||
|
DAD.actionPoolInfo = {
|
||||||
|
totalAmount: 0,
|
||||||
|
totalFee: 0
|
||||||
|
}
|
||||||
|
return actionBatch
|
||||||
|
}
|
||||||
|
|
||||||
// DAD._init=async function(){
|
/** ********************* Public of class *******************/
|
||||||
// await DAD.__proto__._init() // create database table at first
|
DAD.api = {}
|
||||||
// await DAD.actionLoop()
|
|
||||||
// return this
|
|
||||||
// }
|
|
||||||
|
|
||||||
/*********************** Public of class *******************/
|
DAD.api.getAction = async function (option) {
|
||||||
DAD.api={}
|
|
||||||
|
|
||||||
DAD.api.getAction=async function(option){
|
|
||||||
return await DAD.getOne(option)
|
return await DAD.getOne(option)
|
||||||
}
|
}
|
||||||
|
|
||||||
DAD.api.getActionList=async function(option){
|
DAD.api.getActionList = async function (option) {
|
||||||
return await DAD.getAll(option)
|
return await DAD.getAll(option)
|
||||||
}
|
}
|
||||||
|
|
||||||
DAD.api.prepare=async function(option){ // 前端发来action数据,进行初步检查(不检查是否可执行--这和事务类型、执行顺序有关,只检查格式是否有效--这是所有事务通用的规范)后放入缓冲池。
|
DAD.api.prepare = async function (option) {
|
||||||
|
// 前端发来action数据,进行初步检查(不检查是否可执行--这和事务类型、执行顺序有关,只检查格式是否有效--这是所有事务通用的规范)后放入缓冲池。
|
||||||
if (option && option.Action && option.Action.type && option.Action.hash && !DAD.actionPool[option.Action.hash]) {
|
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 (DAD.verifyAddress(option.Action) &&
|
||||||
if (action.verifyAddress() && action.verifySig() && action.verifyHash() // 对所有Action类型都通用的验证
|
DAD.verifySig(option.Action) &&
|
||||||
&& action.validate()) { // 各子类特有的验证
|
DAD.verifyHash(option.Action) &&
|
||||||
// mylog.info('Received action='+JSON.stringify(action))
|
!DAD.actionPool[option.Action.hash] &&
|
||||||
DAD.actionPool[action.hash]=action
|
(await wo[option.Action.type].validate(option.Action))
|
||||||
|
) {
|
||||||
|
DAD.actionPool[option.Action.hash] = option.Action
|
||||||
|
DAD.actionPoolInfo.totalAmount += option.Action.amount || 0
|
||||||
|
DAD.actionPoolInfo.totalFee += option.Action.fee || 0
|
||||||
wo.Peer.broadcast('/Action/prepare', option)
|
wo.Peer.broadcast('/Action/prepare', option)
|
||||||
return action
|
return option.Action
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null // 非法的交易数据
|
return null // 非法的交易数据
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************** Private in class *******************/
|
/** ******************** Private in class *******************/
|
||||||
|
|
||||||
DAD.actionPool={} // 随时不断接收新的交易请求
|
DAD.actionPool = {} // 交易池,在执行getActionBatch时被清空
|
||||||
|
// DAD.currentActionPool = {} // 仅包含0~40秒的交易,40~59秒的交易将被堆积到actionPool。
|
||||||
const my = {
|
DAD.actionPoolInfo = {
|
||||||
|
totalAmount: 0,
|
||||||
|
totalFee: 0
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user