Skip to content

Commit 3e4945b

Browse files
committed
feat(examples): add an example app using Sawtooth and Go-Ethereum
Signed-off-by: Takuma TAKEUCHI <[email protected]>
1 parent 4ddda0b commit 3e4945b

34 files changed

+2679
-13
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
1+
/*
2+
* Copyright 2020 Hyperledger Cactus Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* BusinessLogicElectricityTrade.ts
6+
*/
7+
8+
import { Request } from 'express';
9+
import { RequestInfo } from './RequestInfo';
10+
import { TradeInfo } from '../../packages/routing-interface/TradeInfo';
11+
import { transactionManagement } from '../../packages/routing-interface/routes/index';
12+
import { BusinessLogicBase } from '../../packages/business-logic-plugin/BusinessLogicBase';
13+
import { makeRawTransaction } from './TransactionEthereum'
14+
import { LedgerEvent } from '../../packages/ledger-plugin/LedgerPlugin';
15+
import { json2str } from '../../packages/ledger-plugin/DriverCommon'
16+
17+
const fs = require('fs');
18+
const path = require('path');
19+
const config: any = JSON.parse(fs.readFileSync(path.resolve(__dirname, "./config/default.json"), 'utf8'));
20+
import { getLogger } from "log4js";
21+
const moduleName = 'BusinessLogicElectricityTrade';
22+
const logger = getLogger(`${moduleName}`);
23+
logger.level = config.logLevel;
24+
25+
export class BusinessLogicElectricityTrade extends BusinessLogicBase {
26+
businessLogicID: string;
27+
28+
constructor(businessLogicID: string) {
29+
super();
30+
this.businessLogicID = businessLogicID;
31+
}
32+
33+
startTransaction(req: Request, businessLogicID: string, tradeID: string) {
34+
35+
logger.debug("called startTransaction()");
36+
37+
// set RequestInfo
38+
const requestInfo: RequestInfo = new RequestInfo();
39+
requestInfo.businessLogicID = businessLogicID;
40+
41+
// set TradeID
42+
requestInfo.setTradeID(tradeID);
43+
44+
// Create trade information
45+
const tradeInfo: TradeInfo = new TradeInfo(requestInfo.businessLogicID, requestInfo.tradeID);
46+
47+
this.startMonitor(tradeInfo);
48+
}
49+
50+
startMonitor(tradeInfo: TradeInfo) {
51+
// Get Verifier Instance
52+
logger.debug(`##startMonitor(): businessLogicID: ${tradeInfo.businessLogicID}`);
53+
const useValidator = JSON.parse(transactionManagement.getValidatorToUse(tradeInfo.businessLogicID));
54+
logger.debug(`filterKey: ${config.electricityTradeInfo.sawtooth.filterKey}`);
55+
const options = {
56+
"filterKey": config.electricityTradeInfo.sawtooth.filterKey
57+
}
58+
const verifierSawtooth = transactionManagement.getVerifier(useValidator['validatorID'][0], options);
59+
logger.debug("getVerifierSawtooth");
60+
61+
}
62+
63+
remittanceTransaction(transactionSubset: object) {
64+
65+
logger.debug(`called remittanceTransaction(), accountInfo = ${json2str(transactionSubset)}`);
66+
67+
const accountInfo = this.getAccountInfo(transactionSubset);
68+
if (Object.keys(accountInfo).length === 0) {
69+
logger.debug(`remittanceTransaction(): skip (No target data)`);
70+
return;
71+
}
72+
73+
const txParam: { fromAddress: string, fromAddressPkey: string, toAddress: string, amount: number, gas: number } = {
74+
fromAddress: accountInfo['fromAddress'],
75+
fromAddressPkey: accountInfo['fromAddressPkey'],
76+
toAddress: accountInfo['toAddress'],
77+
amount: Number(transactionSubset['Value']),
78+
gas: config.electricityTradeInfo.ethereum.gas
79+
};
80+
logger.debug(`####txParam = ${json2str(txParam)}`);
81+
82+
// Get Verifier Instance
83+
logger.debug(`##remittanceTransaction(): businessLogicID: ${this.businessLogicID}`);
84+
const useValidator = JSON.parse(transactionManagement.getValidatorToUse(this.businessLogicID));
85+
const verifierEthereum = transactionManagement.getVerifier(useValidator['validatorID'][1]);
86+
logger.debug("getVerifierEthereum");
87+
88+
// Generate parameters for// sendRawTransaction
89+
logger.debug(`####exec makeRawTransaction!!`);
90+
makeRawTransaction(txParam)
91+
.then(result => {
92+
logger.info('remittanceTransaction txId : ' + result.txId);
93+
94+
// Set Parameter
95+
logger.debug('remittanceTransaction data : ' + json2str(result.data));
96+
const contract = {}; // NOTE: Since contract does not need to be specified, specify an empty object.
97+
const method = {type: "web3Eth", command: "sendRawTransaction"};
98+
const args = {"args": [result.data["serializedTx"]]};
99+
100+
// Run Verifier (Ethereum)
101+
verifierEthereum.requestLedgerOperationNeo(contract, method, args);
102+
})
103+
.catch(err => {
104+
logger.error(err);
105+
});
106+
}
107+
108+
onEvent(ledgerEvent: LedgerEvent, targetIndex: number): void {
109+
logger.debug(`##in BLP:onEvent()`);
110+
logger.debug(`##onEvent(): ${json2str(ledgerEvent['data']['blockData'][targetIndex])}`);
111+
112+
switch (ledgerEvent.verifierId) {
113+
case config.electricityTradeInfo.sawtooth.validatorID:
114+
this.onEventSawtooth(ledgerEvent.data, targetIndex);
115+
break;
116+
case config.electricityTradeInfo.ethereum.validatorID:
117+
this.onEventEthereum(ledgerEvent.data, targetIndex);
118+
break;
119+
default:
120+
logger.error(`##onEvent(), invalid verifierId: ${ledgerEvent.verifierId}`);
121+
return;
122+
}
123+
}
124+
125+
onEventSawtooth(event: object, targetIndex: number): void {
126+
logger.debug(`##in onEventSawtooth()`);
127+
const tx = this.getTransactionFromSawtoothEvent(event, targetIndex);
128+
if (tx == null) {
129+
logger.error(`##onEventSawtooth(): invalid event: ${json2str(event)}`);
130+
return;
131+
}
132+
133+
try {
134+
const txId = tx['header_signature'];
135+
logger.debug(`##txId = ${txId}`);
136+
137+
if (tx['payload_decoded'][0].Verb !== "set") {
138+
const transactionSubset = {
139+
"Name": tx['payload_decoded'][0].Name,
140+
"Value": tx['payload_decoded'][0].Value,
141+
"Verb": tx['payload_decoded'][0].Verb
142+
};
143+
this.remittanceTransaction(transactionSubset);
144+
}
145+
}
146+
catch (err) {
147+
logger.error(`##onEventSawtooth(): err: ${err}, event: ${json2str(event)}`);
148+
}
149+
}
150+
151+
getTransactionFromSawtoothEvent(event: object, targetIndex: number): object | null {
152+
try {
153+
const retTransaction = event['blockData'][targetIndex];
154+
logger.debug(`##getTransactionFromSawtoothEvent(), retTransaction: ${retTransaction}`);
155+
return retTransaction;
156+
}
157+
catch (err) {
158+
logger.error(`##getTransactionFromSawtoothEvent(): invalid even, err:${err}, event:${event}`);
159+
}
160+
}
161+
162+
onEventEthereum(event: object, targetIndex: number): void {
163+
logger.debug(`##in onEventEthereum()`);
164+
const tx = this.getTransactionFromEthereumEvent(event, targetIndex);
165+
if (tx == null) {
166+
logger.error(`##onEventEthereum(): invalid event: ${json2str(event)}`);
167+
return;
168+
}
169+
170+
try {
171+
const txId = tx['hash'];
172+
const status = event['status']
173+
logger.debug(`##txId = ${txId}`);
174+
logger.debug(`##status =${status}`);
175+
176+
if (status !== 200) {
177+
logger.error(`##onEventEthereum(): error event, status: ${status}, txId: ${txId}`);
178+
return;
179+
}
180+
}
181+
catch (err) {
182+
logger.error(`##onEventEthereum(): err: ${err}, event: ${json2str(event)}`);
183+
}
184+
}
185+
186+
getTransactionFromEthereumEvent(event: object, targetIndex: number): object | null {
187+
try {
188+
const retTransaction = event['blockData']['transactions'][targetIndex];
189+
logger.debug(`##getTransactionFromEthereumEvent(), retTransaction: ${retTransaction}`);
190+
return retTransaction;
191+
}
192+
catch (err) {
193+
logger.error(`##getTransactionFromEthereumEvent(): invalid even, err:${err}, event:${event}`);
194+
}
195+
}
196+
197+
getOperationStatus(tradeID: string): object {
198+
logger.debug(`##in getOperationStatus()`);
199+
return {};
200+
}
201+
202+
getTxIDFromEvent(ledgerEvent: LedgerEvent, targetIndex: number): string | null {
203+
logger.debug(`##in getTxIDFromEvent`);
204+
// logger.debug(`##event: ${json2str(ledgerEvent)}`);
205+
206+
switch (ledgerEvent.verifierId) {
207+
case config.electricityTradeInfo.sawtooth.validatorID:
208+
return this.getTxIDFromEventSawtooth(ledgerEvent.data, targetIndex);
209+
case config.electricityTradeInfo.ethereum.validatorID:
210+
return this.getTxIDFromEventEtherem(ledgerEvent.data, targetIndex);
211+
default:
212+
logger.error(`##getTxIDFromEvent(): invalid verifierId: ${ledgerEvent.verifierId}`);
213+
}
214+
return null;
215+
}
216+
217+
getTxIDFromEventSawtooth(event: object, targetIndex: number): string | null {
218+
logger.debug(`##in getTxIDFromEventSawtooth()`);
219+
const tx = this.getTransactionFromSawtoothEvent(event, targetIndex);
220+
if (tx == null) {
221+
logger.warn(`#getTxIDFromEventSawtooth(): skip(not found tx)`);
222+
return null;
223+
}
224+
225+
try {
226+
const txId = tx['header_signature'];
227+
228+
if (typeof txId !== 'string') {
229+
logger.warn(`#getTxIDFromEventSawtooth(): skip(invalid block, not found txId.), event: ${json2str(event)}`);
230+
return null;
231+
}
232+
233+
logger.debug(`###getTxIDFromEventSawtooth(): txId: ${txId}`);
234+
return txId;
235+
236+
}
237+
catch (err) {
238+
logger.error(`##getTxIDFromEventSawtooth(): err: ${err}, event: ${json2str(event)}`);
239+
return null;
240+
}
241+
}
242+
243+
getTxIDFromEventEtherem(event: object, targetIndex: number): string | null {
244+
logger.debug(`##in getTxIDFromEventEtherem()`);
245+
const tx = this.getTransactionFromEthereumEvent(event, targetIndex);
246+
if (tx == null) {
247+
logger.warn(`#getTxIDFromEventEtherem(): skip(not found tx)`);
248+
return null;
249+
}
250+
251+
try {
252+
const txId = tx['hash'];
253+
254+
if (typeof txId !== 'string') {
255+
logger.warn(`#getTxIDFromEventEtherem(): skip(invalid block, not found txId.), event: ${json2str(event)}`);
256+
return null;
257+
}
258+
259+
logger.debug(`###getTxIDFromEventEtherem(): txId: ${txId}`);
260+
return txId;
261+
262+
}
263+
catch (err) {
264+
logger.error(`##getTxIDFromEventEtherem(): err: ${err}, event: ${json2str(event)}`);
265+
return null;
266+
}
267+
}
268+
269+
getEventDataNum(ledgerEvent: LedgerEvent): number {
270+
logger.debug(`##in BLP:getEventDataNum(), ledgerEvent.verifierId: ${ledgerEvent.verifierId}`);
271+
const event = ledgerEvent.data;
272+
let retEventNum = 0;
273+
274+
try {
275+
switch (ledgerEvent.verifierId) {
276+
case config.electricityTradeInfo.sawtooth.validatorID:
277+
retEventNum = event['blockData'].length;
278+
break;
279+
case config.electricityTradeInfo.ethereum.validatorID:
280+
retEventNum = event['blockData']['transactions'].length;
281+
break;
282+
default:
283+
logger.error(`##getEventDataNum(): invalid verifierId: ${ledgerEvent.verifierId}`);
284+
break;
285+
}
286+
logger.debug(`##getEventDataNum(): retEventNum: ${retEventNum}, verifierId: ${ledgerEvent.verifierId}`);
287+
return retEventNum;
288+
}
289+
catch (err) {
290+
logger.error(`##getEventDataNum(): invalid even, err: ${err}, event: ${event}`);
291+
return 0;
292+
}
293+
}
294+
295+
getAccountInfo(transactionSubset: object): object {
296+
const transactionInfo = {};
297+
for (const customer of config.electricityTradeInfo.ethereum.account.customer) {
298+
logger.debug(`customer = ${json2str(customer)}`);
299+
if (transactionSubset['Name'] === customer.number) {
300+
if (transactionSubset['Verb'] === "inc") {
301+
logger.debug('getAccountInfo(): A to B');
302+
transactionInfo['fromAddress'] = customer.accountA;
303+
transactionInfo['fromAddressPkey'] = config.electricityTradeInfo.ethereum.account.pKey[customer.accountA];
304+
transactionInfo['toAddress'] = customer.accountB;
305+
}
306+
else if (transactionSubset['Verb'] === "dec"){
307+
logger.debug('getAccountInfo(): B to A');
308+
transactionInfo['fromAddress'] = customer.accountB;
309+
transactionInfo['fromAddressPkey'] = config.electricityTradeInfo.ethereum.account.pKey[customer.accountB];
310+
transactionInfo['toAddress'] = customer.accountA;
311+
}
312+
}
313+
}
314+
return transactionInfo;
315+
}
316+
}
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2020 Hyperledger Cactus Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* RequestInfo.ts
6+
*/
7+
8+
// transaction information
9+
class TradeInfo {
10+
ethereumAccountA: string;
11+
ethereumAccountB: string;
12+
}
13+
14+
// authorization information
15+
class AuthInfo {
16+
company: string;
17+
}
18+
19+
// request information
20+
export class RequestInfo {
21+
businessLogicID: string;
22+
tradeID: string;
23+
tradeInfo: TradeInfo;
24+
authInfo: AuthInfo;
25+
constructor() {
26+
this.tradeInfo = new TradeInfo();
27+
this.authInfo = new AuthInfo();
28+
}
29+
30+
setTradeID(tradeID: string) {
31+
this.tradeID = tradeID;
32+
}
33+
}
34+

0 commit comments

Comments
 (0)