Skip to content

Commit 5592753

Browse files
committed
fix(@embark/blockchain-api): add back contract event listen and log
Adds back the watch on contract events and writes them to a file with the same method as contract logs from transaction-logger, so I extracted those methods to utils/file so that both could use the same functions.
1 parent 87a04cd commit 5592753

File tree

8 files changed

+85
-70
lines changed

8 files changed

+85
-70
lines changed

dapps/templates/demo/contracts/simple_storage.sol

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@ pragma solidity ^0.6.0;
33
contract SimpleStorage {
44
uint public storedData;
55

6+
event Set(address caller, uint _value);
7+
68
constructor(uint initialValue) public {
79
storedData = initialValue;
810
}
911

1012
function set(uint x) public {
1113
storedData = x;
14+
emit Set(msg.sender, x);
1215
}
1316

1417
function get() public view returns (uint retVal) {

packages/cockpit/ui/src/actions/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ export const contractLogs = {
180180
export const CONTRACT_EVENTS = createRequestTypes('CONTRACT_EVENTS');
181181
export const contractEvents = {
182182
request: () => action(CONTRACT_EVENTS[REQUEST]),
183-
success: (contractEvents) => action(CONTRACT_EVENTS[SUCCESS], {contractEvents}),
183+
success: (contractEvents) => action(CONTRACT_EVENTS[SUCCESS], {contractEvents: contractEvents ? contractEvents.reverse() : []}),
184184
failure: (error) => action(CONTRACT_EVENTS[FAILURE], {error, name: 'contractEvents'})
185185
};
186186

packages/core/utils/src/file.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
import { Logger } from 'embark-logger';
12
import { __ } from 'embark-i18n';
23
import * as fs from 'fs-extra';
34
import * as path from 'path';
45
import { downloadFile } from './network';
56
import { dappPath, embarkPath } from './pathUtils';
67
import { ImportRemapping, prepareForCompilation } from './solidity/remapImports';
8+
import { cargo } from 'async';
79

810
const HTTP_CONTRACTS_DIRECTORY = '.embark/contracts/';
911

@@ -179,3 +181,53 @@ export function getExternalContractUrl(file: string, providerUrl: string) {
179181
url,
180182
};
181183
}
184+
185+
export function getCircularReplacer() {
186+
const seen = new WeakSet();
187+
return (key, value) => {
188+
if (typeof value === "object" && value !== null) {
189+
if (seen.has(value)) {
190+
return;
191+
}
192+
seen.add(value);
193+
}
194+
return value;
195+
};
196+
}
197+
198+
export function getAppendLogFileCargo(logFilePath: string, logger: Logger) {
199+
return cargo((tasks, callback) => {
200+
let appendThis = '';
201+
tasks.forEach(task => {
202+
// Write each line to a JSON string. The replacer is to avoid circular dependencies
203+
// Add a comma at the end to be able to make an array off of it when reading
204+
appendThis += `${JSON.stringify(task, getCircularReplacer())},\n`;
205+
});
206+
fs.appendFile(logFilePath, appendThis, (err) => {
207+
if (err) {
208+
logger.error('Error writing to the log file', err.message);
209+
logger.trace(err);
210+
}
211+
callback();
212+
});
213+
});
214+
}
215+
216+
export async function readAppendedLogs(logFile: string, asString: boolean = false) {
217+
await fs.ensureFile(logFile);
218+
const data = await fs.readFile(logFile);
219+
220+
let stringData = data.toString();
221+
222+
if (!stringData) {
223+
return asString ? '[]' : [];
224+
}
225+
226+
// remove last comma and add brackets around to make it an array of object logs
227+
stringData = `[${stringData.substring(0, stringData.length - 2)}]`;
228+
if (asString) {
229+
return stringData;
230+
}
231+
232+
return JSON.parse(stringData);
233+
}

packages/core/utils/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ const { extendZeroAddressShorthand, replaceZeroAddressShorthand } = AddressUtils
5959

6060
export { compact, last, recursiveMerge, groupBy } from './collections';
6161
export { prepareForCompilation } from './solidity/remapImports';
62-
export { File, getExternalContractUrl, Types } from './file';
62+
export { File, getExternalContractUrl, Types, getAppendLogFileCargo, getCircularReplacer, readAppendedLogs } from './file';
6363

6464
export {
6565
findMonorepoPackageFromRoot,

packages/plugins/ethereum-blockchain-client/src/api.js

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import async from "async";
2-
import {dappPath} from 'embark-utils';
2+
import {dappPath, getAppendLogFileCargo, readAppendedLogs} from 'embark-utils';
33
const embarkJsUtils = require('embarkjs').Utils;
44
const {bigNumberify} = require('ethers/utils/bignumber');
55
const RLP = require('ethers/utils/rlp');
@@ -11,11 +11,20 @@ const BLOCK_LIMIT = 100;
1111
export default class EthereumAPI {
1212
constructor(embark, web3, blockchainName) {
1313
this.embark = embark;
14+
this.events = embark.events;
15+
this.logger = embark.logger;
1416
this.blockchainName = blockchainName;
1517
this.web3 = web3;
1618
this.requestManager = new Manager(web3.currentProvider);
1719
this.fs = embark.fs;
18-
this.logFile = dappPath(".embark", "contractEvents.json");
20+
this.logFile = dappPath(".embark", "contractEvents.json.txt");
21+
this.contractsSubscriptions = [];
22+
this.contractsEvents = [];
23+
24+
this.writeLogFile = getAppendLogFileCargo(this.logFile, this.logger);
25+
this.events.on('contractsDeployed', () => {
26+
this.subscribeToContractEvents();
27+
});
1928
}
2029

2130
registerAPIs() {
@@ -26,7 +35,7 @@ export default class EthereumAPI {
2635
this.embark.events.request("blockchain:api:register", this.blockchainName, "getTransactions", this.getTransactions.bind(this));
2736
this.embark.events.request("blockchain:api:register", this.blockchainName, "getTransactionByHash", this.getTransactionByHash.bind(this));
2837
this.embark.events.request("blockchain:api:register", this.blockchainName, "getTransactionByRawTransactionHash", this.getTransactionByRawTransactionHash.bind(this));
29-
this.embark.events.request("blockchain:api:register", this.blockchainName, "getEvents", this.getEvents.bind(this));
38+
this.embark.events.request("blockchain:api:register", this.blockchainName, "getEvents", this.readEvents.bind(this));
3039
this.embark.events.request("blockchain:api:register", this.blockchainName, "signMessage", this.signMessage.bind(this));
3140
this.embark.events.request("blockchain:api:register", this.blockchainName, "verifyMessage", this.verifyMessage.bind(this));
3241
}
@@ -356,7 +365,7 @@ export default class EthereumAPI {
356365
});
357366
}
358367

359-
subscribeToContractEvents(callback) {
368+
subscribeToContractEvents() {
360369
this.contractsSubscriptions.forEach((eventEmitter) => {
361370
const reqMgr = eventEmitter.options.requestManager;
362371
// attempting an eth_unsubscribe when not connected throws an
@@ -378,28 +387,24 @@ export default class EthereumAPI {
378387
eventEmitter.on('data', (data) => {
379388
const dataWithName = Object.assign(data, {name: contractObject.className});
380389
this.contractsEvents.push(dataWithName);
390+
this.saveEvent(dataWithName);
381391
this.events.emit('blockchain:contracts:event', dataWithName);
382392
});
383393
});
384-
callback();
385394
});
386395
}
387396

388-
getEvents() {
389-
const data = this.readEvents();
390-
return Object.values(data).reverse();
391-
}
392-
393397
saveEvent(event) {
394398
this.writeLogFile.push(event);
395399
}
396400

397-
readEvents() {
398-
this.fs.ensureFileSync(this.logFile);
401+
async readEvents(asString) {
399402
try {
400-
return JSON.parse(this.fs.readFileSync(this.logFile));
401-
} catch (_error) {
402-
return {};
403+
return readAppendedLogs(this.logFile, asString);
404+
} catch (e) {
405+
this.logger.error('Error reading contract log file', e.message);
406+
this.logger.trace(e.trace);
407+
return asString ? '[]' : [];
403408
}
404409
}
405410

packages/plugins/ethereum-blockchain-client/src/index.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ class EthereumBlockchainClient {
1515
this.events = embark.events;
1616
this.logger = embark.logger;
1717
this.fs = embark.fs;
18-
this.contractsSubscriptions = [];
19-
this.contractsEvents = [];
2018

2119
this.logFile = dappPath(".embark", "contractEvents.json");
2220

packages/plugins/transaction-logger/src/index.js

Lines changed: 6 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
const async = require('async');
21
import { __ } from 'embark-i18n';
32
const Web3 = require('web3');
43
const util = require('util');
54

65
const { blockchain: blockchainConstants } = require('embark-core/constants');
7-
import { dappPath, hexToNumber } from 'embark-utils';
6+
import { dappPath, hexToNumber, getAppendLogFileCargo, readAppendedLogs } from 'embark-utils';
87
import { getAddressToContract, getTransactionParams } from './transactionUtils';
98
export { getAddressToContract, getTransactionParams };
109

@@ -18,19 +17,6 @@ const LISTENED_METHODS = [
1817
blockchainConstants.transactionMethods.eth_sendRawTransaction
1918
];
2019

21-
const getCircularReplacer = () => {
22-
const seen = new WeakSet();
23-
return (key, value) => {
24-
if (typeof value === "object" && value !== null) {
25-
if (seen.has(value)) {
26-
return;
27-
}
28-
seen.add(value);
29-
}
30-
return value;
31-
};
32-
};
33-
3420
export default class TransactionLogger {
3521
constructor(embark, _options) {
3622
this.embark = embark;
@@ -60,21 +46,7 @@ export default class TransactionLogger {
6046
});
6147
});
6248

63-
this.writeLogFile = async.cargo((tasks, callback) => {
64-
let appendThis = '';
65-
tasks.forEach(task => {
66-
// Write each line to a JSON string. The replacer is to avoid circular dependencies
67-
// Add a comma at the end to be able to make an array off of it when reading
68-
appendThis += `${JSON.stringify(task, getCircularReplacer())},\n`;
69-
});
70-
this.fs.appendFile(this.logFile, appendThis, (err) => {
71-
if (err) {
72-
this.logger.error('Error writing to the log file', err.message);
73-
this.logger.trace(err);
74-
}
75-
callback();
76-
});
77-
});
49+
this.writeLogFile = getAppendLogFileCargo(this.logFile, this.logger);
7850
}
7951

8052
get web3() {
@@ -272,25 +244,10 @@ export default class TransactionLogger {
272244

273245
async _readLogs(asString = false) {
274246
try {
275-
await this.fs.ensureFile(this.logFile);
276-
let data = await this.fs.readFile(this.logFile);
277-
278-
data = data.toString();
279-
280-
if (!data) {
281-
return asString ? '[]' : [];
282-
}
283-
284-
// remove last comma and add brackets around to make it an array of object logs
285-
data = `[${data.substring(0, data.length - 2)}]`;
286-
if (asString) {
287-
return data;
288-
}
289-
290-
return JSON.parse(data);
291-
} catch (error) {
292-
this.logger.error('Error reading contract log file', error.message);
293-
this.logger.trace(error.trace);
247+
return readAppendedLogs(this.logFile, asString);
248+
} catch (e) {
249+
this.logger.error('Error reading contract log file', e.message);
250+
this.logger.trace(e.trace);
294251
return asString ? '[]' : [];
295252
}
296253
}

packages/stack/blockchain/src/api.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,10 +248,10 @@ export default class BlockchainAPI {
248248
this.embark.registerAPICall(
249249
"get",
250250
"/embark-api/blockchain/contracts/events",
251-
(_req, res) => {
251+
async (_req, res) => {
252252
try {
253253
const getEvents = this.getCallForBlockchain(blockchainName, "getEvents");
254-
res.send(JSON.stringify(getEvents()));
254+
res.send(await getEvents(true));
255255
} catch (error) {
256256
res.status(500).send({ error });
257257
}

0 commit comments

Comments
 (0)