This is a simple example of a smart contract written in ECMAScript which uses SQL database for storing the state.
class Engine {
constructor(db, contracts) {
this.db = db
this.contracts = contracts
}
async executeBlock(block) {
const {db} = this
const t = await db.transaction()
try {
await this.verifyBlock(block, t)
for (const tx of block.txs) {
try {
await this.executeTx(tx, t)
}
catch (err) {
if (err instanceof Revert) {
await this.txFailed(tx, error)
}
else {
throw err
}
}
}
await this.writeBlock(block, t)
await t.commit()
}
catch (err) {
await t.rollback()
throw err
}
}
async verifyBlock(block, db) {
throw new Error('Not implemented yet')
}
executeTx(tx, db) {
return this.contracts[tx.target](tx, t)
}
}
class PosEngine extends Engine {
async verifyBlock(block, db) {
const verifiers = await this.db.accounts.select(['address']).sort({value: -1}).limit(10)
.then((result) => result.map(({address}) => address))
for (const addr of block.voters) {
if (verifiers.includes(addr) === false) {
throw new Error(`invalid_voter:${addr}`);
}
}
}
}
const moneyDb = new PosEngine(db, {
async accounts(tx, db) {
const {sender, type, payload} = tx
switch (type) {
case 'TRANSFER': {
const {value} = await db.accounts.select().where({address: sender}).findOne()
if (value < tx.value) {
throw new Revert('insufficient_funds')
}
await db.accounts.select({
address: sender,
})
.update({
$decrease: {value: tx.value},
})
await db.accounts.select({
address: payload.receiver,
})
.update({
$increase: {value: tx.value},
})
}
default: {
throw new Error(`Unknown transaction type: ${type}`)
}
}
}
})