Created
September 1, 2017 17:20
-
-
Save datchley/6b0c9fe795c7e79256840a339968dcd7 to your computer and use it in GitHub Desktop.
Some testing code to generate proper eosd API calls.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const fetch = require('isomorphic-fetch'); | |
function pad(number) { | |
if (number < 10) { | |
return '0' + number; | |
} | |
return number; | |
} | |
// eosd currently has issues with "real" ISO time format, | |
// so we remove the milliseconds and 'Z' ending | |
const formatISO = d => | |
d.getUTCFullYear() + | |
'-' + pad(d.getUTCMonth() + 1) + | |
'-' + pad(d.getUTCDate()) + | |
'T' + pad(d.getUTCHours()) + | |
':' + pad(d.getUTCMinutes()) + | |
':' + pad(d.getUTCSeconds()) | |
// '.' + (d.getUTCMilliseconds() / 1000).toFixed(3).slice(2, 5) + | |
// 'Z'; | |
// Example block returned from /v1/chain/get_info | |
// providing information about the head of the blockchain | |
var block_info = { | |
"head_block_num": 50, | |
"last_irreversible_block_num": 32, | |
"head_block_id": "00000032ef4abccc5fefd86c67623e5e640cdde6b6472b42bc6a868e2fb93655", | |
"head_block_time": "2017-08-31T17:57:54", | |
"head_block_producer": "inits", | |
"recent_slots": "1111111111111111111111111111111111111111111111111111111111111111", | |
"participation_rate": "1.00000000000000000" | |
}; | |
const wrappedFetch = (url, options = {}) => { | |
console.log(`wrappedFetch(${url})`); | |
const opts = { | |
method: 'POST', | |
redirect: 'follow', | |
headers: new Headers({ | |
'Content-type': 'text/json; charset=utf-8' | |
}), | |
...options | |
}; | |
console.log(`-> options:\n ${JSON.stringify(opts, null, 2)}`); | |
return fetch(url, opts) | |
.then(resp => { | |
if (resp.ok) { | |
return resp.json(); | |
} | |
resp.text().then(message => { | |
throw new Error(`request to ${url} failed: ${message}`); | |
}); | |
}) | |
.catch(error => { | |
console.error(error); | |
}); | |
} | |
const eosd = 'http://104.198.175.158:8888'; | |
const endpoints = { | |
'newaccount': '/v1/chain/push_transaction', | |
'transfer': '/v1/chain/push_transaction', | |
'getinfo': '/v1/chain/get_info', | |
'getaccount': '/v1/chain/get_account', | |
'gettxnhistory': '/v1/account_history/get_transactions' | |
}; | |
const url = type => `${eosd}${endpoints[type]}`; | |
const getHead = () => wrappedFetch(url('getinfo')); | |
const request = async (type, data) => { | |
const endpoint = url(type); | |
try { | |
const head = await getHead(); | |
const payload = getReqJSON(type, head, data); | |
console.log(`Sending payload: ${JSON.stringify(payload, null, 2)}`); | |
const json = wrappedFetch(endpoint, { body: JSON.stringify(payload) }); | |
return json; | |
} | |
catch (e) { | |
console.error(`Request for ${type} failed: ${e}`); | |
} | |
} | |
// Grab the first 32bits from the 2nd 64 bit chunk and convert to uint | |
const getRefBlockPrefix = (info, offset=8) => new Buffer(info.head_block_id, 'hex').readUInt32LE(offset); | |
// Generate a reference block prefix the same as Steemit does (but for Browser) | |
// const getRefBlockPrefix = (info, offset=4) => { | |
// const len = info.head_block_id.length / 2; // hex 2 chars per 8-bits | |
// let buf = new Uint8Array(len); | |
// for (var i = 0; i < len; ++i) { | |
// var parsed = parseInt(info.head_block_id.substr(i*2, 2), 16); | |
// buf[i] = parsed; | |
// } | |
// return ((buf[offset]) | | |
// (buf[offset + 1] << 8) | | |
// (buf[offset + 2] << 16)) + | |
// (buf[offset + 3] * 0x1000000); | |
// } | |
// Generate a reference block number, same as Steemit | |
const getRefBlockNum = info => info.head_block_num & 0xFFFF; // (info.head_block_num - 3) & 0xFFFF; | |
// Generate an expiration date, 1 hour from time on head block | |
// returned from /v1/chain/get_info | |
const getExpiration = info => { | |
const dt = new Date(info.head_block_time + 'Z'); | |
return formatISO(dt); | |
// return new Date( | |
// dt.getTime() + | |
// 60 * 60 * 1000 | |
// ).toISOString(); | |
} | |
// | |
// Demo Data | |
// | |
const owner = 'inita'; | |
const ownerKeys = { | |
"owner": { | |
"threshold": 1, | |
"keys": [{ | |
"key": "EOS4toFS3YXEQCkuuw1aqDLrtHim86Gz9u3hBdcBw5KNPZcursVHq", | |
"weight": 1 | |
}], | |
"accounts": [] | |
}, | |
"active": { | |
"threshold": 1, | |
"keys": [{ | |
"key": "EOS7d9A3uLe6As66jzN8j44TXJUqJSK3bFjjEEqR4oTvNAB3iM9SA", | |
"weight": 1 | |
}], | |
"accounts": [] | |
}, | |
"recovery": { | |
"threshold": 1, | |
"keys": [], | |
"accounts": [{ | |
"permission": { | |
"account": "inita", | |
"permission": "active" | |
}, | |
"weight": 1 | |
}] | |
} | |
}; | |
const messages = { | |
newaccount: { | |
"code": "eos", | |
"type": "newaccount", | |
"authorization": [{ | |
"account": "inita", | |
"permission": "active" | |
}], | |
"data": { | |
"creator": "inita", | |
"name": "tester", | |
...ownerKeys, | |
"deposit": "0.00000001 EOS" | |
} | |
}, | |
transfer: { | |
"code": "eos", | |
"type": "transfer", | |
"authorization": [{ | |
"account": "inita", | |
"permission": "active" | |
}], | |
"data": { | |
"from": "inita", | |
"to": "test", | |
"amount": 100, | |
"memo": "this is a memo" | |
} | |
} | |
}; | |
const genHeader = block => ({ | |
"refBlockNum": getRefBlockNum(block), | |
"refBlockPrefix": getRefBlockPrefix(block), | |
"expiration": getExpiration(block), | |
}); | |
const genScope = (type, data) => { | |
if (type === 'newaccount') { | |
return [ "eos", "inita" ]; // hard coded for demo | |
} | |
if (type === 'transfer') { | |
return [ data.from, data.to ]; // parties in transfer | |
} | |
// wha'chew talkin' 'bout, Willis?! | |
throw new TypeError(`can not create scope for unknown txn type '${type}'`); | |
}; | |
const genMessages = (type, data) => { | |
if (type === 'newaccount') { | |
return [{ | |
...messages[type], | |
data: { | |
...messages[type].data, | |
name: data.name | |
} | |
}]; | |
} | |
if (type === 'transfer') { | |
return [{ | |
...messages[type], | |
data | |
}]; | |
} | |
// wha'chew talkin' 'bout, Willis?! | |
throw new TypeError(`can not create scope for unknown txn type '${type}'`); | |
} | |
// newaccount: | |
// @param data [Object] - w/ properties: `name` | |
// transfer: | |
// @param data [Object] - w/ properties: `to`, `from`, `amount`[, `memo`] | |
// | |
const getReqJSON = (type, head, data={}) => { | |
switch(type) { | |
// POST type calls | |
case "newaccount": | |
case "transfer": | |
return { | |
...genHeader(head), | |
scope: genScope(type, data), | |
messages: genMessages(type, data), | |
signatures: [] | |
}; | |
// GET type calls | |
case "getinfo": | |
return {}; | |
case "getaccount": | |
return { | |
name: data.name | |
}; | |
case "gettxnhistory": | |
return { | |
account_name: data.name, | |
skip_seq: data.start || 0, | |
num_seq: data.count || 25 | |
}; | |
default: | |
return data; | |
} | |
} | |
// console.log( | |
// getReqJSON('newaccount', block_info, { name: 'tester' }) | |
// ); | |
// console.log( | |
// getReqJSON('transfer', block_info, { to: 'tester', from: 'inita', amount: 100, memo: "charity" }) | |
// ); | |
// console.log( | |
// getReqJSON('getinfo', block_info) | |
// ); | |
// console.log( | |
// getReqJSON('getaccount', block_info, { name: 'tester' }) | |
// ); | |
// console.log( | |
// getReqJSON('gettxnhistory', block_info, { name: 'tester' }) | |
// ); | |
getHead() | |
.then(block => | |
console.log(`Got chain head:\n ${JSON.stringify(block, null, 2)}`) | |
) | |
.catch(e => | |
console.error('FAIL!: ', e) | |
); | |
request('newaccount', { name: 'tester2' }) | |
.then(resp => | |
console.log(`Got response:\n ${JSON.stringify(resp, null, 2)}`) | |
) | |
.catch(e => | |
console.error('FAIL!: ', e) | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment