Skip to content
This repository has been archived by the owner on Jun 29, 2023. It is now read-only.

Commit

Permalink
Merge pull request #647 from thehubbleproject/pubkey2states
Browse files Browse the repository at this point in the history
added mapping from pubkey hash to states
  • Loading branch information
kautukkundan authored Aug 23, 2021
2 parents ea02b74 + 1661810 commit e09c1fc
Show file tree
Hide file tree
Showing 10 changed files with 571 additions and 347 deletions.
2 changes: 1 addition & 1 deletion config.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"willingnessToBid": 1,
"maxPendingTransactions": 1024,
"feeReceivers": [{
"tokenID": 1,
"tokenID": 0,
"stateID": 0
}]
}
Expand Down
671 changes: 345 additions & 326 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"bn.js": "^5.2.0",
"ethers": "5.4.3",
"fastify": "^3.18.0",
"fastify-cors": "^6.0.2",
"level": "^7.0.0",
"lodash": "^4.17.21",
"mcl-wasm": "0.4.5",
Expand Down
70 changes: 70 additions & 0 deletions test/client/pubkey2states.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import chai, { assert } from "chai";
import chaiAsPromised from "chai-as-promised";
import { StateDatabaseEngine } from "../../ts/client/database";
import { PRODUCTION_PARAMS } from "../../ts/constants";
import { State } from "../../ts/state";
import del from "del";
import { PubkeyLeaf } from "../../ts/tree/leaves/PubkeyLeaf";
import { init } from "../../ts/mcl";
import { BlsSigner } from "../../ts/blsSigner";
import { Pubkey2StatesDB } from "../../ts/client/database/pubkey2states";

chai.use(chaiAsPromised);

const {
MAX_DEPTH: maxDepth,
MAX_DEPOSIT_SUBTREE_DEPTH: maxSubtreeDepth
} = PRODUCTION_PARAMS;

describe("StateDBEngine", () => {
let engine: StateDatabaseEngine;
let p0: PubkeyLeaf;
let p1: PubkeyLeaf;
let statesP0: State[];
let statesP1: State[];

before(async function() {
await del("./leveldb/*");
});

after(async function() {
await del("./leveldb/*");
});

beforeEach(async function() {
engine = new StateDatabaseEngine(maxDepth);
statesP0 = [];
statesP1 = [];

await init();

p0 = PubkeyLeaf.fromSolG2(BlsSigner.new().pubkey, 0);
await p0.toDB();

p1 = PubkeyLeaf.fromSolG2(BlsSigner.new().pubkey, 1);
await p1.toDB();

for (let i = 0; i < 4; i++) {
statesP0.push(State.new(p0.itemID, i, i, i));
}

for (let i = 0; i < 2; i++) {
statesP1.push(State.new(p1.itemID, i, i, i));
}
});
it("update pubkey with states", async function() {
await engine.updateBatch(0, maxSubtreeDepth, statesP0);
await engine.updateBatch(1, maxSubtreeDepth, statesP1);

assert.deepEqual(await Pubkey2StatesDB.getStates(p0.item.hash()), [
0,
1,
2,
3
]);
assert.deepEqual(await Pubkey2StatesDB.getStates(p1.item.hash()), [
4,
5
]);
});
});
1 change: 1 addition & 0 deletions ts/client/database/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export const close = async (): Promise<void> => {
export const pubkeyDB = sub(db, "pubkey");
export const stateDB = sub(db, "state");
export const nodeDB = sub(db, "node");
export const pubkey2statesDB = sub(db, "pubkey2states");
29 changes: 29 additions & 0 deletions ts/client/database/pubkey2states.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import _ from "lodash";
import { PubkeyLeafFactory } from "../../tree/leaves/PubkeyLeaf";
import { pubkey2statesDB } from "./connection";

export class Pubkey2StatesDB {
static async getStates(pubkeyHash: string): Promise<number[]> {
return JSON.parse(await pubkey2statesDB.get(pubkeyHash));
}

static async update(pubkeyID: number, stateID: number): Promise<void> {
const pubkeyLeaf = await PubkeyLeafFactory().fromDB(pubkeyID);
const pubkeyHash = pubkeyLeaf.item.hash();

try {
const states: string = await pubkey2statesDB.get(pubkeyHash);
const appended = _.union<number>(JSON.parse(states), [stateID]);
await pubkey2statesDB.put(pubkeyHash, JSON.stringify(appended));
} catch (error) {
if (error.name === "NotFoundError") {
await pubkey2statesDB.put(
pubkeyHash,
JSON.stringify([stateID])
);
} else {
throw error;
}
}
}
}
13 changes: 13 additions & 0 deletions ts/client/database/stateEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { State } from "../../state";
import { StateLeafFactory } from "../../tree/leaves/StateLeaf";
import { StorageEngine } from "../storageEngine/interfaces";
import { DatabaseEngine } from "./databaseEngine";
import { Pubkey2StatesDB } from "./pubkey2states";

export interface StateStorageEngine extends StorageEngine<State> {}

Expand All @@ -10,4 +11,16 @@ export class StateDatabaseEngine extends DatabaseEngine<State>
constructor(depth: number) {
super(depth, StateLeafFactory());
}

public async updateBatch(
path: number,
depth: number,
items: State[]
): Promise<void> {
for (const [i, item] of items.entries()) {
const itemID = path * 2 ** depth + i;
await this.update(itemID, item);
await Pubkey2StatesDB.update(item.pubkeyID.toNumber(), itemID);
}
}
}
6 changes: 3 additions & 3 deletions ts/client/features/transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,11 +197,11 @@ export class TransferOffchainTx extends TransferCompressedTx
const signature = { sol: solG1, mcl: mclG1 };

return new this(
obj.fromIndex.toNumber(),
obj.toIndex.toNumber(),
obj.fromIndex,
obj.toIndex,
obj.amount,
obj.fee,
obj.nonce.toNumber(),
obj.nonce,
signature
);
}
Expand Down
2 changes: 1 addition & 1 deletion ts/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ async function main() {
console.info("Starting Hubble node...");
const config = await configFromPath(configPath);

const fast = fastify({ logger: true });
const fast = fastify({ logger: true, maxParamLength: 512 });
fast.setErrorHandler(console.error);

const node = await HubbleNode.init(config, fast);
Expand Down
123 changes: 107 additions & 16 deletions ts/client/services/rpc.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { arrayify } from "@ethersproject/bytes";
import { FastifyInstance } from "fastify";
import { CoreAPI } from "../coreAPI";
import { Pubkey2StatesDB } from "../database/pubkey2states";
import { ITransferPool, TransferOffchainTx } from "../features/transfer";
import cors from "fastify-cors";

const tx = {
schema: {
Expand All @@ -20,30 +22,115 @@ export class RPC {
fastify: FastifyInstance,
transferPool?: ITransferPool
) {
fastify.register(cors, {
origin: "*"
});
fastify.get<{ Params: { stateID: number } }>(
"/user/state/:stateID",
async function(request) {
const stateID = request.params.stateID;
const state = await l2Storage.state.get(stateID);
return state.toJSON();
async function(request, reply) {
try {
const { stateID } = request.params;
const state = await l2Storage.state.get(stateID);
return state.toJSON();
} catch (error) {
if (error.name === "NotFoundError") {
return reply
.status(404)
.send({ error: "pubkey not found" });
} else {
console.error(error);
return reply.status(500);
}
}
}
);
fastify.get<{ Params: { pubkeyHash: string } }>(
"/user/state/pubkey/:pubkeyHash",
async function(request, reply) {
try {
const { pubkeyHash } = request.params;
const stateIndices = await Pubkey2StatesDB.getStates(
pubkeyHash
);
let data = stateIndices.map(async id => {
let state = await l2Storage.state.get(Number(id));
return {
stateId: id,
balance: state.balance.toString(),
tokenId: state.tokenID.toString(),
nonce: state.nonce.toString()
};
});
return { states: await Promise.all(data) };
} catch (error) {
if (error.name === "NotFoundError") {
return reply
.status(404)
.send({ error: "pubkey not found" });
} else {
console.error(error);
return reply.status(500);
}
}
}
);
fastify.get<{ Params: { pubkeyID: number } }>(
"/user/pubkey/hash/:pubkeyID",
async function(request, reply) {
try {
const { pubkeyID } = request.params;
const pubkey = await l2Storage.pubkey.get(pubkeyID);
return { hash: pubkey.hash() };
} catch (error) {
return reply
.status(404)
.send({ error: "pubkey not found" });
}
}
);
fastify.get<{ Params: { pubkeyHash: string } }>(
"/user/pubkey/id/:pubkeyHash",
async function(request, reply) {
try {
const { pubkeyHash } = request.params;
const stateIndices = await Pubkey2StatesDB.getStates(
pubkeyHash
);
let data = await l2Storage.state.get(
Number(stateIndices[0])
);
return { id: data.pubkeyID.toNumber() };
} catch (error) {
if (error.name === "NotFoundError") {
return reply
.status(404)
.send({ error: "pubkey not found" });
} else {
console.error(error);
return reply.status(500);
}
}
}
);
fastify.post<{ Body: { bytes: string } }>(
"/tx",
tx,
async (request, reply) => {
if (!transferPool) {
reply.status(409).send("not a proposer");
return;
}

const bytes = arrayify(request.body.bytes);
const transfer = TransferOffchainTx.deserialize(bytes);
console.log(transfer.toString());
try {
if (!transferPool) {
reply.status(409).send("not a proposer");
return;
}

await transferPool.push(transfer);
await l2Storage.transactions.pending(transfer);
return { txHash: transfer.hash() };
const bytes = arrayify(request.body.bytes);
const transfer = TransferOffchainTx.deserialize(bytes);
await transferPool.push(transfer);
await l2Storage.transactions.pending(transfer);
return { txHash: transfer.hash() };
} catch (error) {
console.error(error);
return reply.status(500);
}
}
);
fastify.get<{ Params: { txMsg: string } }>(
Expand All @@ -57,7 +144,11 @@ export class RPC {
}
// In the future, we may want to clean up
// this JSON serialization to something more minimal.
return JSON.stringify(txStatus);
return JSON.stringify({
status: txStatus.status,
l1BlockIncluded: txStatus.l1BlockIncluded,
l1TxnHash: txStatus.l1TxnHash
});
}
);
}
Expand Down

0 comments on commit e09c1fc

Please sign in to comment.