Skip to content

Commit

Permalink
add support for greymass history solution
Browse files Browse the repository at this point in the history
  • Loading branch information
shaqk committed Mar 23, 2023
1 parent 7d6492e commit 54f177e
Show file tree
Hide file tree
Showing 8 changed files with 403 additions and 44 deletions.
19 changes: 12 additions & 7 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
#host port to use for ibc-proof-server websocket
PORT=7788

#EOS example

#chain id of the chain that ibc-proof-server provides proofs for
CHAIN_ID="aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906"

#lightproof-db endpoint
LIGHTPROOF_API=http://localhost:8285
LIGHTPROOF_API=http://localhost:8285

# The history provider to fetch from (firehose/ship)
# The history provider to fetch from (firehose/ship/greymass)
HISTORY_PROVIDER=ship

#firehose history provider config
# Firehose GRPC address and mode (if HISTORY_PROVIDER is firehose)
GRPC_ADDRESS=eos.firehose.eosnation.io:9000
GRPC_INSECURE=false
GRPC_INSECURE=false

# SHIP websocket address (if HISTORY_PROVIDER is ship)
SHIP_WS=ws://localhost:8080

#ship history provider config
SHIP_WS=ws://192.168.86.41:8080
# Nodeos HTTP (if HISTORY_PROVIDER is greymass)
NODEOS_HTTP=http://localhost:8888


# only required for greymass; Block in which the ACTION RETURN feature was activated
RETURN_VALUE_ACTIVATION = 269183455
22 changes: 14 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
# ibc-proof-server

ibc-proof-server generates and serves heavy and light proofs for actions and schedules. Currently firehose and SHIP are supported.
ibc-proof-server generates and serves heavy and light proofs for actions and schedules. Currently firehose, SHIP and greymass are supported.

## Instructions

#### Clone the repo and install dependencies

```
git clone https://github.com/eostitan/ibc-proof-server.git
git clone https://github.com/CryptoMechanics/ibc-proof-server.git
cd ibc-proof-server
git checkout v2
npm install
```

Expand All @@ -29,15 +28,22 @@ CHAIN_ID="aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906"
# lightproof-db endpoint
LIGHTPROOF_API=http://localhost:8285
# The history provider to fetch from (firehose/ship)
# The history provider to fetch from (firehose/ship/greymass)
HISTORY_PROVIDER=ship
#firehose history provider config
# Firehose GRPC address and mode (if HISTORY_PROVIDER is firehose)
GRPC_ADDRESS=eos.firehose.eosnation.io:9000
GRPC_INSECURE=false
GRPC_INSECURE=false
# SHIP websocket address (if HISTORY_PROVIDER is ship)
SHIP_WS=ws://localhost:8080
# Nodeos HTTP (if HISTORY_PROVIDER is greymass)
NODEOS_HTTP=http://localhost:8888
# only required for greymass; Block in which the ACTION RETURN feature was activated
RETURN_VALUE_ACTIVATION = 269183455
#ship history provider config
SHIP_WS=ws://192.168.86.41:8080
```


Expand Down
45 changes: 35 additions & 10 deletions abstract.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,46 @@
const { getFirehoseHeavyProof, preprocessFirehoseBlock, convertFirehoseAction, getFirehoseIrreversibleBlock } = require("./firehoseFunctions");
const { getShipIrreversibleBlock, getShipHeavyProof } = require("./shipFunctions");
const { getNodeosIrreversibleBlock, getNodeoseHeavyProof, convertNodeosAction, formatBlockRes } = require("./nodeosFunctions");
const { getReceiptDigest } = require("./ibcFunctions")
const historyProvider = process.env.HISTORY_PROVIDER;
const axios = require('axios');


//Functions that abstract the history provider
const getIrreversibleBlock = async (block_num) => {
if (historyProvider === 'firehose') return getFirehoseIrreversibleBlock(block_num)
else if (historyProvider === 'ship') return getShipIrreversibleBlock(block_num);
else if (historyProvider === 'greymass') return getNodeosIrreversibleBlock(block_num);
}

const preprocessBlock = (obj, keepTraces) => {
if (historyProvider === 'firehose') return preprocessFirehoseBlock(obj, keepTraces);
else if (historyProvider === 'ship'){
// console.log("obj",obj);
return obj
}
else if (historyProvider === 'ship') return obj
else if (historyProvider === 'greymass') return formatBlockRes(obj)
}

const convertAction = (act) => {
const convertAction = (act, block_num) => {
if (historyProvider === 'firehose') return convertFirehoseAction(act);
else if (historyProvider === 'ship') return act
else if (historyProvider === 'greymass') return convertNodeosAction(act, block_num)
}

const getHeavyProof = req => {
const getHeavyProof =async req => {
if (historyProvider === 'firehose') return getFirehoseHeavyProof(req);
else if (historyProvider === 'ship')return getShipHeavyProof(req);
else if (historyProvider === 'greymass'){
const transactions = await getTxs(req.block_num+1); //since request includes previous block
return getNodeoseHeavyProof(req, transactions);
}
}

const getTxs = res =>{
const getTxs = async res =>{
if (historyProvider === 'firehose') {
let txs = res.block.unfilteredTransactionTraces.map(r=> r.actionTraces );
for (var tx of txs){
for (var act of tx){
let action_receipt_digest = getReceiptDigest(act.receipt);
const converted = convertAction(act);
const converted = await convertAction(act);
let action_receipt_digest = getReceiptDigest(converted.receipt);
act.action = converted.action;
act.receipt = converted.receipt;
act.action_receipt_digest = action_receipt_digest;
Expand All @@ -60,9 +66,28 @@ const getTxs = res =>{
//sort traces by global sequenece since SHIP doesnt sort them
traces.sort((a,b)=> a.receipt.global_sequence > b.receipt.global_sequence? 1 :-1);
txs.push(traces)

}
return txs;
}
else if (historyProvider === 'greymass') {
const newRes = await axios(`${process.env.NODEOS_HTTP}/v1/history/get_raw_actions_in_block?block_num=${res.block_num || res}`);
let txs =[];

for (var action of newRes.data.actions){
const converted = await convertAction(action, res.block_num || res);
let action_receipt_digest = await getReceiptDigest(converted.receipt);

let obj = {
action_receipt_digest,
transactionId: converted.action.transactionId,
receipt: converted.receipt,
action: {name: action.act.name}
}
let tx = txs.find(r=> r && r.find(s=>s.transactionId === obj.transactionId));
if (!tx) txs.push([obj]);
else tx.push(obj)
}

return txs;
}
}
Expand Down
17 changes: 11 additions & 6 deletions handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const axios = require("axios");
const { getIrreversibleBlock, preprocessBlock, getHeavyProof, getTxs } = require("./abstract")
const { getActionProof, getBmProof, verify, compressProof, getReceiptDigest } = require("./ibcFunctions")
const crypto = require("crypto");
const historyProvider = process.env.HISTORY_PROVIDER;

//Websocket handlers
async function handleHeavyProof(msgObj, ws){
Expand All @@ -16,7 +17,8 @@ async function handleHeavyProof(msgObj, ws){
const req_block_to_prove = {
firehoseOptions : { start_block_num, include_filter_expr: "", fork_steps: ["STEP_NEW", "STEP_UNDO"] },
action_receipt_digest: msgObj.action_receipt ? getReceiptDigest(msgObj.action_receipt) : msgObj.action_receipt_digest,
ws
ws,
block_num:start_block_num
}

const response = {
Expand Down Expand Up @@ -91,7 +93,6 @@ function handleLightProof(msgObj, ws){
if(!checkBlock2.available) return ws.send(JSON.stringify({ type:"error", error: checkBlock2.error }));
}

console.log("passed valid block check")
var result = await getIrreversibleBlock(msgObj.block_to_prove);
var block_to_prove = preprocessBlock(result, true);

Expand All @@ -105,7 +106,11 @@ function handleLightProof(msgObj, ws){

if (msgObj.action_receipt || msgObj.action_receipt_digest){
if (msgObj.action_receipt) msgObj.action_receipt_digest = getReceiptDigest(msgObj.action_receipt);
proof.actionproof = getActionProof(block_to_prove, msgObj.action_receipt_digest)
if (historyProvider==='greymass') {
const transactions = await getTxs(block_to_prove);
proof.actionproof = getActionProof({transactions, block_num: block_to_prove.block_num}, msgObj.action_receipt_digest)
}
else proof.actionproof = getActionProof(block_to_prove, msgObj.action_receipt_digest)
}

let blockID = (await axios.get(`${process.env.LIGHTPROOF_API}?blocks=${msgObj.block_to_prove}`)).data[0].id;
Expand All @@ -131,11 +136,11 @@ function handleLightProof(msgObj, ws){
async function handleGetBlockActions(msgObj, ws){
try {
console.log("handleGetBlockActions", msgObj.block_to_prove);
let checkBlock = await checkValidBlockRange(msgObj.block_to_prove);
if(!checkBlock.available) return ws.send(JSON.stringify({ type:"error", error: checkBlock.error }));
// let checkBlock = await checkValidBlockRange(msgObj.block_to_prove);
// if(!checkBlock.available) return ws.send(JSON.stringify({ type:"error", error: checkBlock.error }));

const res = await getIrreversibleBlock(msgObj.block_to_prove);
const txs = getTxs(res);
const txs = await getTxs(res.data);

console.log("handleGetBlockActions finished", msgObj.block_to_prove)
ws.send(JSON.stringify({ type: "getBlockActions", query : msgObj, txs }));
Expand Down
72 changes: 61 additions & 11 deletions ibcFunctions.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ const hex64 = require('hex64');
const axios = require("axios");
const historyProvider = process.env.HISTORY_PROVIDER;


const eosjsTypes = {
name: types.get("name"),
bytes: types.get("bytes"),
Expand All @@ -17,6 +16,22 @@ const eosjsTypes = {
varuint32: types.get("varuint32"),
checksum256: types.get("checksum256")
}
const { name, uint8, uint64,varuint32, checksum256, bytes } = eosjsTypes;

const nameToUint64 = (s) => {
let n = 0n;
let i = 0;
for (; i < 12 && s[i]; i++) n |= BigInt(char_to_symbol(s.charCodeAt(i)) & 0x1f) << BigInt(64 - 5 * (i + 1));
if (i == 12) n |= BigInt(char_to_symbol(s.charCodeAt(i)) & 0x0f);
return n.toString();
};

const char_to_symbol = c => {
if (typeof c == 'string') c = c.charCodeAt(0);
if (c >= 'a'.charCodeAt(0) && c <= 'z'.charCodeAt(0)) return c - 'a'.charCodeAt(0) + 6;
if (c >= '1'.charCodeAt(0) && c <= '5'.charCodeAt(0)) return c - '1'.charCodeAt(0) + 1;
return 0;
};

function getActionProof(block_to_prove, requested_action_receipt_digest){
let { action_receipt_digests, action_return_value } = getReceiptDigests(block_to_prove, requested_action_receipt_digest);
Expand All @@ -30,6 +45,7 @@ function getActionProof(block_to_prove, requested_action_receipt_digest){
function getReceiptDigests(block_to_prove, action_receipt_digest){
if (historyProvider === 'firehose') return getFirehoseReceiptDigests(block_to_prove, action_receipt_digest);
else if (historyProvider === 'ship') return getShipReceiptDigests(block_to_prove, action_receipt_digest);
else if (historyProvider === 'greymass') return getNodeosReceiptDigests(block_to_prove, action_receipt_digest);
}

function getShipReceiptDigests(block_to_prove, action_receipt_digest){
Expand All @@ -47,7 +63,21 @@ function getShipReceiptDigests(block_to_prove, action_receipt_digest){
return { action_receipt_digests, action_return_value };
}

function getFirehoseReceiptDigests(block_to_prove, action_receipt_digest){
function getNodeosReceiptDigests(block_to_prove, action_receipt_digest){
let action_return_value;
var action_receipt_digests = [];
for (traces of block_to_prove.transactions){
for (trace of traces.sort((a,b)=> a.receipt.global_sequence > b.receipt.global_sequence? 1 :-1)){
//if this is the trace of the action we are trying to prove, assign the action_return_value from trace result
if (trace.action_receipt_digest === action_receipt_digest && trace.return_value) action_return_value = trace.return_value.toString()
action_receipt_digests.push(trace.action_receipt_digest );
}
}

return { action_receipt_digests, action_return_value };
}

async function getFirehoseReceiptDigests(block_to_prove, action_receipt_digest){
let action_return_value;
var action_receipt_digests = [];

Expand All @@ -62,12 +92,6 @@ function getFirehoseReceiptDigests(block_to_prove, action_receipt_digest){
action_receipt_digests.push(receipt_digest);
}
}
// var action_receipt_digests_clone = JSON.parse(JSON.stringify(action_receipt_digests));
// // console.log("action_receipt_digests : ", JSON.stringify(action_receipt_digests, null, 2));

// var actionMerkleRoot = merkle(action_receipt_digests_clone);
// // console.log("actionMerkleRoot : ", actionMerkleRoot);

return { action_receipt_digests, action_return_value };
}
function getBmProof(block_to_prove, last_proven_block ){
Expand Down Expand Up @@ -306,19 +330,21 @@ function getProofPath (index, nodes_count) {


function getReceiptDigest(receipt){
const { name, uint8, uint64,varuint32, checksum256 } = eosjsTypes;
const buffer = new SerialBuffer({ TextEncoder, TextDecoder });


//handle different formats of receipt for dfuse (camelCase) / nodeos / SHIP
//if receipt is in nodeos format, convert to dfuse format
if (receipt.act_digest && !receipt.digest){

let authSequence = [];
for (var auth of receipt.auth_sequence) {
if(auth[1]) authSequence.push({ accountName: auth[0], sequence: auth[1] })
else authSequence.push({ accountName: auth.account, sequence: auth.sequence }) //handle SHIP
}

if (authSequence.length>1) authSequence = authSequence.sort((a,b)=> a.accountName > b.accountName? 1 : a.accountName < b.accountName ? -1 : 0);

receipt = {
receiver: receipt.receiver,
digest: receipt.act_digest,
Expand Down Expand Up @@ -352,6 +378,28 @@ function getReceiptDigest(receipt){
return crypto.createHash("sha256").update(buffer.asUint8Array()).digest("hex");
}

function getBaseActionDigest(a){
const buff = new SerialBuffer({ TextEncoder, TextDecoder });

uint64.serialize(buff, nameToUint64(a.account));
uint64.serialize(buff, nameToUint64(a.name));
varuint32.serialize(buff, a.authorization.length);

for (var i = 0 ; i < a.authorization.length;i++){
uint64.serialize(buff, nameToUint64(a.authorization[i].actor));
uint64.serialize(buff, nameToUint64(a.authorization[i].permission));
}

return crypto.createHash("sha256").update(buff.asUint8Array()).digest("hex");
}

function getDataDigest(act, returnValue){
const buff = new SerialBuffer({ TextEncoder, TextDecoder });
bytes.serialize(buff, act.data);
bytes.serialize(buff, returnValue);
return crypto.createHash("sha256").update(buff.asUint8Array()).digest("hex");
}

function compressProof(obj){
const newObj = JSON.parse(JSON.stringify(obj));
const hashes = [];
Expand Down Expand Up @@ -452,5 +500,7 @@ module.exports = {
getBmProof,
verify,
compressProof,
getReceiptDigest
getReceiptDigest,
getBaseActionDigest,
getDataDigest
}
Loading

0 comments on commit 54f177e

Please sign in to comment.