Initial commit: add .gitignore and README
This commit is contained in:
62
smart_contracts/scripts/compile.js
Normal file
62
smart_contracts/scripts/compile.js
Normal file
@@ -0,0 +1,62 @@
|
||||
const path = require('path');
|
||||
const fs = require('fs-extra');
|
||||
const solc = require('solc');
|
||||
|
||||
const contractsPath = path.resolve(__dirname, '../', 'contracts');
|
||||
|
||||
function buildSources() {
|
||||
const sources = {};
|
||||
const contractsFiles = fs.readdirSync(contractsPath);
|
||||
contractsFiles.forEach(file => {
|
||||
if(file.endsWith(".sol")){
|
||||
const contractFullPath = path.resolve(contractsPath, file);
|
||||
sources[file] = {
|
||||
content: fs.readFileSync(contractFullPath, 'utf8')
|
||||
};
|
||||
}
|
||||
});
|
||||
return sources;
|
||||
}
|
||||
|
||||
const input = {
|
||||
language: 'Solidity',
|
||||
sources: buildSources(),
|
||||
settings: {
|
||||
outputSelection: {
|
||||
'*': {
|
||||
'*': [ '*', 'evm.bytecode' ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function compileContracts() {
|
||||
const stringifiedJson = JSON.stringify(input);
|
||||
console.log(stringifiedJson)
|
||||
const compilationResult = solc.compile(stringifiedJson);
|
||||
console.log(compilationResult)
|
||||
const output = JSON.parse(compilationResult);
|
||||
console.log(output)
|
||||
const compiledContracts = output.contracts;
|
||||
for (let contract in compiledContracts) {
|
||||
for(let contractName in compiledContracts[contract]) {
|
||||
console.log(contract)
|
||||
fs.outputJsonSync(
|
||||
path.resolve(contractsPath, `${contractName}.json`),
|
||||
compiledContracts[contract][contractName], { spaces: 2 }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const main = () => {
|
||||
compileContracts();
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main();
|
||||
}
|
||||
|
||||
module.exports = exports = main
|
||||
|
||||
|
||||
74
smart_contracts/scripts/keys.js
Normal file
74
smart_contracts/scripts/keys.js
Normal file
@@ -0,0 +1,74 @@
|
||||
// WARNING: the keys here are demo purposes ONLY. Please use a tool like EthSigner for production, rather than hard coding private keys
|
||||
|
||||
module.exports = {
|
||||
tessera: {
|
||||
member1: {
|
||||
publicKey: "BULeR8JyUWhiuuCMU/HLA0Q5pzkYT+cHII3ZKBey3Bo=",
|
||||
},
|
||||
member2: {
|
||||
publicKey: "QfeDAys9MPDs2XHExtc84jKGHxZg/aj52DTh0vtA3Xc=",
|
||||
},
|
||||
member3: {
|
||||
publicKey: "1iTZde/ndBHvzhcl7V68x44Vx7pl8nwx9LqnM/AfJUg=",
|
||||
},
|
||||
},
|
||||
besu: {
|
||||
rpcnode: {
|
||||
name: "rpcnode",
|
||||
url: "http://127.0.0.1:8545",
|
||||
wsUrl: "ws://127.0.0.1:8546",
|
||||
nodekey:
|
||||
"0e93a540518eeb673d94fb496b746008ab56605463cb9212493997f5755124d1",
|
||||
accountAddress: "c9c913c8c3c1cd416d80a0abf475db2062f161f6",
|
||||
accountPrivateKey:
|
||||
"0x60bbe10a196a4e71451c0f6e9ec9beab454c2a5ac0542aa5b8b733ff5719fec3",
|
||||
},
|
||||
member1: {
|
||||
name: "member1",
|
||||
url: "http://127.0.0.1:20000",
|
||||
wsUrl: "ws://127.0.0.1:20001",
|
||||
privateUrl: "http://127.0.0.1:9081",
|
||||
nodekey:
|
||||
"0xb9a4bd1539c15bcc83fa9078fe89200b6e9e802ae992f13cd83c853f16e8bed4",
|
||||
accountAddress: "0xf0e2db6c8dc6c681bb5d6ad121a107f300e9b2b5",
|
||||
accountPrivateKey:
|
||||
"8bbbb1b345af56b560a5b20bd4b0ed1cd8cc9958a16262bc75118453cb546df7",
|
||||
},
|
||||
member2: {
|
||||
name: "member2",
|
||||
url: "http://127.0.0.1:20002",
|
||||
wsUrl: "ws://127.0.0.1:20003",
|
||||
privateUrl: "http://127.0.0.1:9082",
|
||||
nodekey:
|
||||
"f18166704e19b895c1e2698ebc82b4e007e6d2933f4b31be23662dd0ec602570",
|
||||
accountAddress: "0xca843569e3427144cead5e4d5999a3d0ccf92b8e",
|
||||
accountPrivateKey:
|
||||
"4762e04d10832808a0aebdaa79c12de54afbe006bfffd228b3abcc494fe986f9",
|
||||
},
|
||||
member3: {
|
||||
name: "member3",
|
||||
url: "http://127.0.0.1:20004",
|
||||
wsUrl: "ws://127.0.0.1:20005",
|
||||
privateUrl: "http://127.0.0.1:9083",
|
||||
nodekey:
|
||||
"4107f0b6bf67a3bc679a15fe36f640415cf4da6a4820affaac89c8b280dfd1b3",
|
||||
accountAddress: "0x0fbdc686b912d7722dc86510934589e0aaf3b55a",
|
||||
accountPrivateKey:
|
||||
"61dced5af778942996880120b303fc11ee28cc8e5036d2fdff619b5675ded3f0",
|
||||
},
|
||||
},
|
||||
accounts: {
|
||||
a: {
|
||||
address: "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73",
|
||||
privateKey: "0x8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63",
|
||||
},
|
||||
b: {
|
||||
address: "0x627306090abaB3A6e1400e9345bC60c78a8BEf57",
|
||||
privateKey: "0xc87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3",
|
||||
},
|
||||
c: {
|
||||
address: "0xf17f52151EbEF6C7334FAD080c5704D77216b732",
|
||||
privateKey: "0xae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f",
|
||||
},
|
||||
},
|
||||
};
|
||||
130
smart_contracts/scripts/privacy/concurrent_private_txs.js
Normal file
130
smart_contracts/scripts/privacy/concurrent_private_txs.js
Normal file
@@ -0,0 +1,130 @@
|
||||
const Web3 = require("web3");
|
||||
const Web3Quorum = require("web3js-quorum");
|
||||
const Tx = require("ethereumjs-tx");
|
||||
const PromisePool = require("async-promise-pool");
|
||||
const { tessera, besu } = require("../keys.js");
|
||||
|
||||
const chainId = 1337;
|
||||
const web3 = new Web3Quorum(new Web3(besu.member1.url), chainId);
|
||||
|
||||
/*
|
||||
Transactions are sent in batches.
|
||||
TX_COUNT defines the total of transactions
|
||||
BATCH_SIZE defines how many transactions will be sent at once
|
||||
*/
|
||||
const TX_COUNT = 100;
|
||||
const BATCH_SIZE = 5;
|
||||
|
||||
// options used to create a privacy group with only one member
|
||||
const privacyOptions = {
|
||||
privateFrom: tessera.member1.publicKey,
|
||||
privateFor: [tessera.member1.publicKey],
|
||||
privateKey: besu.member1.accountPrivateKey,
|
||||
};
|
||||
|
||||
const deployContractData =
|
||||
"0x608060405234801561001057600080fd5b5060405161018e38038061018e8339818101604052602081101561003357600080fd5b8101908080519060200190929190505050806000819055507f85bea11d86cefb165374e0f727bacf21dc2f4ea816493981ecf72dcfb212a410816040518082815260200191505060405180910390a15060fd806100916000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c806360fe47b11460375780636d4ce63c146062575b600080fd5b606060048036036020811015604b57600080fd5b8101908080359060200190929190505050607e565b005b606860bf565b6040518082815260200191505060405180910390f35b806000819055507f85bea11d86cefb165374e0f727bacf21dc2f4ea816493981ecf72dcfb212a410816040518082815260200191505060405180910390a150565b6000805490509056fea265627a7a723158207735a32daa767059dd230ee7718eb7f09ff35ca8ba54249b53ea1c2e12b98f8564736f6c634300051100320000000000000000000000000000000000000000000000000000000000000001";
|
||||
|
||||
// get nonce of account in the privacy group
|
||||
function getPrivateNonce(account) {
|
||||
return web3.priv.getTransactionCount(
|
||||
account,
|
||||
web3.utils.generatePrivacyGroup(privacyOptions)
|
||||
);
|
||||
}
|
||||
|
||||
// get public nonce of account
|
||||
function getPublicNonce(account) {
|
||||
return web3.eth.getTransactionCount(account, "pending");
|
||||
}
|
||||
|
||||
// distribute payload to participants
|
||||
function distributePayload(payload, nonce) {
|
||||
return web3.priv.generateAndDistributeRawTransaction({
|
||||
...privacyOptions,
|
||||
data: payload,
|
||||
nonce,
|
||||
});
|
||||
}
|
||||
|
||||
// create and sign PMT
|
||||
function sendPMT(sender, enclaveKey, nonce) {
|
||||
const rawTx = {
|
||||
nonce: web3.utils.numberToHex(nonce), // PMT nonce
|
||||
from: sender,
|
||||
to: "0x000000000000000000000000000000000000007e", // privacy precompile address
|
||||
data: enclaveKey,
|
||||
gasLimit: "0x5a88",
|
||||
};
|
||||
|
||||
const tx = new Tx(rawTx);
|
||||
tx.sign(Buffer.from(besu.member1.accountPrivateKey, "hex"));
|
||||
|
||||
const hexTx = `0x${tx.serialize().toString("hex")}`;
|
||||
|
||||
// eslint-disable-next-line promise/avoid-new
|
||||
return new Promise((resolve, reject) => {
|
||||
web3.eth
|
||||
.sendSignedTransaction(hexTx)
|
||||
.once("receipt", (rcpt) => {
|
||||
resolve(rcpt);
|
||||
})
|
||||
.on("error", (error) => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function printPrivTxDetails(pmtRcpt) {
|
||||
return web3.priv
|
||||
.waitForTransactionReceipt(pmtRcpt.transactionHash)
|
||||
.then((privTxRcpt) => {
|
||||
console.log(
|
||||
`=== Private TX ${privTxRcpt.transactionHash}\n` +
|
||||
` > Status ${privTxRcpt.status}\n` +
|
||||
` > Block #${pmtRcpt.blockNumber}\n` +
|
||||
` > PMT Index #${pmtRcpt.transactionIndex}\n` +
|
||||
` > PMT Hash ${pmtRcpt.transactionHash}\n`
|
||||
);
|
||||
return Promise.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
Example of sending private transactions in batch.
|
||||
|
||||
The basic steps are:
|
||||
|
||||
1. Find the expected public and private nonce for the sender account
|
||||
2. Ditribute the private transaction (incrementing the private nonce)
|
||||
3. Create a PMT for each private transaction (incrementing the public nonce)
|
||||
*/
|
||||
module.exports = async () => {
|
||||
const sender = "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73";
|
||||
|
||||
const privateNonce = await getPrivateNonce(sender);
|
||||
const publicNonce = await getPublicNonce(sender);
|
||||
|
||||
const pool = new PromisePool({ concurrency: BATCH_SIZE });
|
||||
|
||||
for (let i = 0; i < TX_COUNT; i += 1) {
|
||||
pool.add(() => {
|
||||
return distributePayload(deployContractData, privateNonce + i)
|
||||
.then((enclaveKey) => {
|
||||
return sendPMT(sender, enclaveKey, publicNonce + i);
|
||||
})
|
||||
.then(printPrivTxDetails);
|
||||
});
|
||||
}
|
||||
|
||||
await pool.all();
|
||||
};
|
||||
|
||||
if (require.main === module) {
|
||||
module.exports().catch((error) => {
|
||||
console.log(error);
|
||||
console.log(
|
||||
"\nThis example requires ONCHAIN privacy to be DISABLED. \nCheck config for ONCHAIN privacy groups."
|
||||
);
|
||||
});
|
||||
}
|
||||
200
smart_contracts/scripts/privacy/private_tx.js
Normal file
200
smart_contracts/scripts/privacy/private_tx.js
Normal file
@@ -0,0 +1,200 @@
|
||||
const path = require("path");
|
||||
const fs = require("fs-extra");
|
||||
const Web3 = require("web3");
|
||||
const Web3Quorum = require("web3js-quorum");
|
||||
|
||||
// WARNING: the keys here are demo purposes ONLY. Please use a tool like EthSigner for production, rather than hard coding private keys
|
||||
const { tessera, besu } = require("../keys.js");
|
||||
const chainId = 1337;
|
||||
// abi and bytecode generated from simplestorage.sol:
|
||||
// > solcjs --bin --abi simplestorage.sol
|
||||
const contractJsonPath = path.resolve(
|
||||
__dirname,
|
||||
"../../",
|
||||
"contracts",
|
||||
"SimpleStorage.json"
|
||||
);
|
||||
const contractJson = JSON.parse(fs.readFileSync(contractJsonPath));
|
||||
const contractBytecode = contractJson.evm.bytecode.object;
|
||||
const contractAbi = contractJson.abi;
|
||||
|
||||
// Besu doesn't support eth_sendTransaction so we use the eea_sendRawTransaction(https://besu.hyperledger.org/en/latest/Reference/API-Methods/#eea_sendrawtransaction) for things like simple value transfers, contract creation or contract invocation
|
||||
async function createContract(
|
||||
clientUrl,
|
||||
fromPrivateKey,
|
||||
fromPublicKey,
|
||||
toPublicKey
|
||||
) {
|
||||
const web3 = new Web3(clientUrl);
|
||||
const web3quorum = new Web3Quorum(web3, chainId);
|
||||
// initialize the default constructor with a value `47 = 0x2F`; this value is appended to the bytecode
|
||||
const contractConstructorInit = web3.eth.abi
|
||||
.encodeParameter("uint256", "47")
|
||||
.slice(2);
|
||||
const txOptions = {
|
||||
data: "0x" + contractBytecode + contractConstructorInit,
|
||||
privateKey: fromPrivateKey,
|
||||
privateFrom: fromPublicKey,
|
||||
privateFor: [toPublicKey],
|
||||
};
|
||||
console.log("Creating contract...");
|
||||
// Generate and send the Raw transaction to the Besu node using the eea_sendRawTransaction(https://besu.hyperledger.org/en/latest/Reference/API-Methods/#eea_sendrawtransaction) JSON-RPC call
|
||||
const txHash = await web3quorum.priv.generateAndSendRawTransaction(txOptions);
|
||||
console.log("Getting contractAddress from txHash: ", txHash);
|
||||
const privateTxReceipt = await web3quorum.priv.waitForTransactionReceipt(
|
||||
txHash
|
||||
);
|
||||
console.log("Private Transaction Receipt: ", privateTxReceipt);
|
||||
return privateTxReceipt;
|
||||
}
|
||||
|
||||
async function getValueAtAddress(
|
||||
clientUrl,
|
||||
nodeName = "node",
|
||||
address,
|
||||
contractAbi,
|
||||
fromPrivateKey,
|
||||
fromPublicKey,
|
||||
toPublicKey
|
||||
) {
|
||||
const web3 = new Web3(clientUrl);
|
||||
const web3quorum = new Web3Quorum(web3, chainId);
|
||||
const contract = new web3quorum.eth.Contract(contractAbi);
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
const functionAbi = contract._jsonInterface.find((e) => {
|
||||
return e.name === "get";
|
||||
});
|
||||
const functionParams = {
|
||||
to: address,
|
||||
data: functionAbi.signature,
|
||||
privateKey: fromPrivateKey,
|
||||
privateFrom: fromPublicKey,
|
||||
privateFor: [toPublicKey],
|
||||
};
|
||||
const transactionHash = await web3quorum.priv.generateAndSendRawTransaction(
|
||||
functionParams
|
||||
);
|
||||
// console.log(`Transaction hash: ${transactionHash}`);
|
||||
const result = await web3quorum.priv.waitForTransactionReceipt(
|
||||
transactionHash
|
||||
);
|
||||
console.log(
|
||||
"" + nodeName + " value from deployed contract is: " + result.output
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
async function setValueAtAddress(
|
||||
clientUrl,
|
||||
address,
|
||||
value,
|
||||
contractAbi,
|
||||
fromPrivateKey,
|
||||
fromPublicKey,
|
||||
toPublicKey
|
||||
) {
|
||||
const web3 = new Web3(clientUrl);
|
||||
const web3quorum = new Web3Quorum(web3, chainId);
|
||||
const contract = new web3quorum.eth.Contract(contractAbi);
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
const functionAbi = contract._jsonInterface.find((e) => {
|
||||
return e.name === "set";
|
||||
});
|
||||
const functionArgs = web3quorum.eth.abi
|
||||
.encodeParameters(functionAbi.inputs, [value])
|
||||
.slice(2);
|
||||
const functionParams = {
|
||||
to: address,
|
||||
data: functionAbi.signature + functionArgs,
|
||||
privateKey: fromPrivateKey,
|
||||
privateFrom: fromPublicKey,
|
||||
privateFor: [toPublicKey],
|
||||
};
|
||||
const transactionHash = await web3quorum.priv.generateAndSendRawTransaction(
|
||||
functionParams
|
||||
);
|
||||
console.log(`Transaction hash: ${transactionHash}`);
|
||||
const result = await web3quorum.priv.waitForTransactionReceipt(
|
||||
transactionHash
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
createContract(
|
||||
besu.member1.url,
|
||||
besu.member1.accountPrivateKey,
|
||||
tessera.member1.publicKey,
|
||||
tessera.member3.publicKey
|
||||
)
|
||||
.then(async function (privateTxReceipt) {
|
||||
console.log("Address of transaction: ", privateTxReceipt.contractAddress);
|
||||
let newValue = 123;
|
||||
|
||||
//wait for the blocks to propogate to the other nodes
|
||||
await new Promise((r) => setTimeout(r, 20000));
|
||||
console.log(
|
||||
"Use the smart contracts 'get' function to read the contract's constructor initialized value .. "
|
||||
);
|
||||
await getValueAtAddress(
|
||||
besu.member1.url,
|
||||
"Member1",
|
||||
privateTxReceipt.contractAddress,
|
||||
contractAbi,
|
||||
besu.member1.accountPrivateKey,
|
||||
tessera.member1.publicKey,
|
||||
tessera.member3.publicKey
|
||||
);
|
||||
console.log(
|
||||
`Use the smart contracts 'set' function to update that value to ${newValue} .. - from member1 to member3`
|
||||
);
|
||||
await setValueAtAddress(
|
||||
besu.member1.url,
|
||||
privateTxReceipt.contractAddress,
|
||||
newValue,
|
||||
contractAbi,
|
||||
besu.member1.accountPrivateKey,
|
||||
tessera.member1.publicKey,
|
||||
tessera.member3.publicKey
|
||||
);
|
||||
//wait for the blocks to propogate to the other nodes
|
||||
await new Promise((r) => setTimeout(r, 20000));
|
||||
console.log(
|
||||
"Verify the private transaction is private by reading the value from all three members .. "
|
||||
);
|
||||
await getValueAtAddress(
|
||||
besu.member1.url,
|
||||
"Member1",
|
||||
privateTxReceipt.contractAddress,
|
||||
contractAbi,
|
||||
besu.member1.accountPrivateKey,
|
||||
tessera.member1.publicKey,
|
||||
tessera.member3.publicKey
|
||||
);
|
||||
await getValueAtAddress(
|
||||
besu.member2.url,
|
||||
"Member2",
|
||||
privateTxReceipt.contractAddress,
|
||||
contractAbi,
|
||||
besu.member2.accountPrivateKey,
|
||||
tessera.member2.publicKey,
|
||||
tessera.member1.publicKey
|
||||
);
|
||||
await getValueAtAddress(
|
||||
besu.member3.url,
|
||||
"Member3",
|
||||
privateTxReceipt.contractAddress,
|
||||
contractAbi,
|
||||
besu.member3.accountPrivateKey,
|
||||
tessera.member3.publicKey,
|
||||
tessera.member1.publicKey
|
||||
);
|
||||
})
|
||||
.catch(console.error);
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main();
|
||||
}
|
||||
|
||||
module.exports = exports = main;
|
||||
232
smart_contracts/scripts/privacy/private_tx_privacy_group.js
Normal file
232
smart_contracts/scripts/privacy/private_tx_privacy_group.js
Normal file
@@ -0,0 +1,232 @@
|
||||
const path = require("path");
|
||||
const fs = require("fs-extra");
|
||||
const Web3 = require("web3");
|
||||
const Web3Quorum = require("web3js-quorum");
|
||||
|
||||
// WARNING: the keys here are demo purposes ONLY. Please use a tool like EthSigner for production, rather than hard coding private keys
|
||||
const { tessera, besu } = require("../keys.js");
|
||||
const chainId = 1337;
|
||||
// abi and bytecode generated from simplestorage.sol:
|
||||
// > solcjs --bin --abi simplestorage.sol
|
||||
const contractJsonPath = path.resolve(
|
||||
__dirname,
|
||||
"../../",
|
||||
"contracts",
|
||||
"SimpleStorage.json"
|
||||
);
|
||||
const contractJson = JSON.parse(fs.readFileSync(contractJsonPath));
|
||||
const contractBytecode = contractJson.evm.bytecode.object;
|
||||
const contractAbi = contractJson.abi;
|
||||
// initialize the default constructor with a value `47 = 0x2F`; this value is appended to the bytecode
|
||||
const contractConstructorInit =
|
||||
"000000000000000000000000000000000000000000000000000000000000002F";
|
||||
|
||||
async function createPrivacyGroup(clientUrl, participantList) {
|
||||
const web3 = new Web3(clientUrl);
|
||||
const web3quorum = new Web3Quorum(web3, chainId);
|
||||
const contractOptions = {
|
||||
addresses: participantList,
|
||||
name: "web3js-quorum",
|
||||
description: "quickstart",
|
||||
};
|
||||
const result = await web3.priv.createPrivacyGroup(contractOptions);
|
||||
console.log(
|
||||
"Privacy group: " +
|
||||
result +
|
||||
" created between participants: " +
|
||||
participantList
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Besu doesn't support eth_sendTransaction so we use the eea_sendRawTransaction for things like simple value transfers, contract creation or contract invocation
|
||||
async function createContract(
|
||||
clientUrl,
|
||||
privacyGroupId,
|
||||
fromPrivateKey,
|
||||
fromPublicKey
|
||||
) {
|
||||
const web3 = new Web3(clientUrl);
|
||||
const web3quorum = new Web3Quorum(web3, chainId);
|
||||
const txOptions = {
|
||||
data: "0x" + contractBytecode + contractConstructorInit,
|
||||
privateKey: fromPrivateKey,
|
||||
privateFrom: fromPublicKey,
|
||||
privacyGroupId: privacyGroupId,
|
||||
};
|
||||
console.log("Creating contract...");
|
||||
// Generate and send the Raw transaction to the Besu node using the eea_sendRawTransaction JSON-RPC call
|
||||
const txHash = await web3quorum.priv.generateAndSendRawTransaction(txOptions);
|
||||
console.log("Getting contractAddress from txHash: ", txHash);
|
||||
const privateTxReceipt = await web3quorum.priv.waitForTransactionReceipt(
|
||||
txHash
|
||||
);
|
||||
console.log("Private Transaction Receipt: ", privateTxReceipt);
|
||||
return privateTxReceipt;
|
||||
}
|
||||
|
||||
async function getValueAtAddress(
|
||||
clientUrl,
|
||||
nodeName = "node",
|
||||
address,
|
||||
contractAbi,
|
||||
fromPrivateKey,
|
||||
fromPublicKey,
|
||||
privacyGroupId
|
||||
) {
|
||||
const web3 = new Web3(clientUrl);
|
||||
const web3quorum = new Web3Quorum(web3, chainId);
|
||||
const contract = new web3quorum.eth.Contract(contractAbi);
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
const functionAbi = contract._jsonInterface.find((e) => {
|
||||
return e.name === "get";
|
||||
});
|
||||
const functionParams = {
|
||||
to: address,
|
||||
data: functionAbi.signature,
|
||||
privateKey: fromPrivateKey,
|
||||
privateFrom: fromPublicKey,
|
||||
privacyGroupId: privacyGroupId,
|
||||
};
|
||||
const transactionHash = await web3quorum.priv.generateAndSendRawTransaction(
|
||||
functionParams
|
||||
);
|
||||
// console.log(`Transaction hash: ${transactionHash}`);
|
||||
const result = await web3quorum.priv.waitForTransactionReceipt(
|
||||
transactionHash
|
||||
);
|
||||
console.log(
|
||||
"" + nodeName + " value from deployed contract is: " + result.output
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
async function setValueAtAddress(
|
||||
clientUrl,
|
||||
address,
|
||||
value,
|
||||
contractAbi,
|
||||
fromPrivateKey,
|
||||
fromPublicKey,
|
||||
privacyGroupId
|
||||
) {
|
||||
const web3 = new Web3(clientUrl);
|
||||
const web3quorum = new Web3Quorum(web3, chainId);
|
||||
const contract = new web3quorum.eth.Contract(contractAbi);
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
const functionAbi = contract._jsonInterface.find((e) => {
|
||||
return e.name === "set";
|
||||
});
|
||||
const functionArgs = web3quorum.eth.abi
|
||||
.encodeParameters(functionAbi.inputs, [value])
|
||||
.slice(2);
|
||||
const functionParams = {
|
||||
to: address,
|
||||
data: functionAbi.signature + functionArgs,
|
||||
privateKey: fromPrivateKey,
|
||||
privateFrom: fromPublicKey,
|
||||
privacyGroupId,
|
||||
};
|
||||
const transactionHash = await web3quorum.priv.generateAndSendRawTransaction(
|
||||
functionParams
|
||||
);
|
||||
console.log(`Transaction hash: ${transactionHash}`);
|
||||
const result = await web3quorum.priv.waitForTransactionReceipt(
|
||||
transactionHash
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const participantList = [
|
||||
tessera.member1.publicKey,
|
||||
tessera.member3.publicKey,
|
||||
];
|
||||
const privacyGroupId = await createPrivacyGroup(
|
||||
besu.member1.url,
|
||||
participantList
|
||||
);
|
||||
createContract(
|
||||
besu.member1.url,
|
||||
privacyGroupId,
|
||||
besu.member1.accountPrivateKey,
|
||||
tessera.member1.publicKey,
|
||||
tessera.member3.publicKey
|
||||
)
|
||||
.then(async function (privateTxReceipt) {
|
||||
console.log("Address of transaction: ", privateTxReceipt.contractAddress);
|
||||
let newValue = 123;
|
||||
|
||||
//wait for the blocks to propogate to the other nodes
|
||||
await new Promise((r) => setTimeout(r, 10000));
|
||||
console.log(
|
||||
"Use the smart contracts 'get' function to read the contract's constructor initialized value .. "
|
||||
);
|
||||
await getValueAtAddress(
|
||||
besu.member1.url,
|
||||
"Member1",
|
||||
privateTxReceipt.contractAddress,
|
||||
contractAbi,
|
||||
besu.member1.accountPrivateKey,
|
||||
tessera.member1.publicKey,
|
||||
privacyGroupId
|
||||
);
|
||||
console.log(
|
||||
`Use the smart contracts 'set' function to update that value to ${newValue} .. - from member1 to member3`
|
||||
);
|
||||
await setValueAtAddress(
|
||||
besu.member1.url,
|
||||
privateTxReceipt.contractAddress,
|
||||
newValue,
|
||||
contractAbi,
|
||||
besu.member1.accountPrivateKey,
|
||||
tessera.member1.publicKey,
|
||||
privacyGroupId
|
||||
);
|
||||
//wait for the blocks to propogate to the other nodes
|
||||
await new Promise((r) => setTimeout(r, 10000));
|
||||
console.log(
|
||||
"Verify the private transaction is private by reading the value from all three members .. "
|
||||
);
|
||||
await getValueAtAddress(
|
||||
besu.member1.url,
|
||||
"Member1",
|
||||
privateTxReceipt.contractAddress,
|
||||
contractAbi,
|
||||
besu.member1.accountPrivateKey,
|
||||
tessera.member1.publicKey,
|
||||
privacyGroupId
|
||||
).catch(() => {
|
||||
console.log("Member1 cannot obtain value");
|
||||
});
|
||||
await getValueAtAddress(
|
||||
besu.member2.url,
|
||||
"Member2",
|
||||
privateTxReceipt.contractAddress,
|
||||
contractAbi,
|
||||
besu.member2.accountPrivateKey,
|
||||
tessera.member2.publicKey,
|
||||
privacyGroupId
|
||||
).catch(() => {
|
||||
console.log("Member2 cannot obtain value");
|
||||
});
|
||||
await getValueAtAddress(
|
||||
besu.member3.url,
|
||||
"Member3",
|
||||
privateTxReceipt.contractAddress,
|
||||
contractAbi,
|
||||
besu.member3.accountPrivateKey,
|
||||
tessera.member3.publicKey,
|
||||
privacyGroupId
|
||||
).catch(() => {
|
||||
console.log("Member3 cannot obtain value");
|
||||
});
|
||||
})
|
||||
.catch(console.error);
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main();
|
||||
}
|
||||
|
||||
module.exports = exports = main;
|
||||
88
smart_contracts/scripts/public/hre_1559_public_tx.js
Normal file
88
smart_contracts/scripts/public/hre_1559_public_tx.js
Normal file
@@ -0,0 +1,88 @@
|
||||
const path = require('path');
|
||||
const fs = require('fs-extra');
|
||||
var ethers = require('ethers');
|
||||
|
||||
// RPCNODE details
|
||||
const { tessera, besu } = require("../keys.js");
|
||||
const host = besu.rpcnode.url;
|
||||
const accountPrivateKey = besu.rpcnode.accountPrivateKey;
|
||||
|
||||
// abi and bytecode generated from simplestorage.sol:
|
||||
// > solcjs --bin --abi simplestorage.sol
|
||||
const contractJsonPath = path.resolve(__dirname, '../../','contracts','Counter.json');
|
||||
const contractJson = JSON.parse(fs.readFileSync(contractJsonPath));
|
||||
const contractAbi = contractJson.abi;
|
||||
const contractBytecode = contractJson.evm.bytecode.object
|
||||
|
||||
async function getValueAtAddress(provider, deployedContractAbi, deployedContractAddress){
|
||||
const contract = new ethers.Contract(deployedContractAddress, deployedContractAbi, provider);
|
||||
const res = await contract.getCount();
|
||||
console.log("Obtained value at deployed contract is: "+ res);
|
||||
return res
|
||||
}
|
||||
|
||||
// You need to use the accountAddress details provided to Quorum to send/interact with contracts
|
||||
async function incrementValueAtAddress(provider, wallet, deployedContractAbi, deployedContractAddress){
|
||||
const contract = new ethers.Contract(deployedContractAddress, deployedContractAbi, provider);
|
||||
const contractWithSigner = contract.connect(wallet);
|
||||
const tx = await contractWithSigner.incrementCounter();
|
||||
// verify the updated value
|
||||
await tx.wait();
|
||||
// const res = await contract.get();
|
||||
// console.log("Obtained value at deployed contract is: "+ res);
|
||||
return tx;
|
||||
}
|
||||
|
||||
async function decrementValueAtAddress(provider, wallet, deployedContractAbi, deployedContractAddress){
|
||||
const contract = new ethers.Contract(deployedContractAddress, deployedContractAbi, provider);
|
||||
const contractWithSigner = contract.connect(wallet);
|
||||
const tx = await contractWithSigner.decrementCounter();
|
||||
// verify the updated value
|
||||
await tx.wait();
|
||||
// const res = await contract.get();
|
||||
// console.log("Obtained value at deployed contract is: "+ res);
|
||||
return tx;
|
||||
}
|
||||
|
||||
async function createContract(provider, wallet, contractAbi, contractByteCode) {
|
||||
const feeData = await provider.getFeeData();
|
||||
const factory = new ethers.ContractFactory(contractAbi, contractByteCode, wallet);
|
||||
const contract = await factory.deploy({
|
||||
chainId: 1337,
|
||||
type: 2,
|
||||
maxPriorityFeePerGas: feeData["maxPriorityFeePerGas"],
|
||||
maxFeePerGas: feeData["maxFeePerGas"],
|
||||
});
|
||||
// The contract is NOT deployed yet; we must wait until it is mined
|
||||
const deployed = await contract.waitForDeployment();
|
||||
//The contract is deployed now
|
||||
return contract
|
||||
};
|
||||
|
||||
async function main(){
|
||||
const provider = new ethers.JsonRpcProvider(host);
|
||||
const wallet = new ethers.Wallet(accountPrivateKey, provider);
|
||||
|
||||
createContract(provider, wallet, contractAbi, contractBytecode)
|
||||
.then(async function(contract){
|
||||
console.log(contract);
|
||||
contractAddress = await contract.getAddress();
|
||||
console.log("Use the smart contracts 'get' function to read the contract's initialized value .. " )
|
||||
await getValueAtAddress(provider, contractAbi, contractAddress);
|
||||
console.log("Use the smart contracts 'increment' function to update that value .. " );
|
||||
await incrementValueAtAddress(provider, wallet, contractAbi, contractAddress );
|
||||
console.log("Verify the updated value that was set .. " )
|
||||
await getValueAtAddress(provider, contractAbi, contractAddress);
|
||||
console.log("Use the smart contracts 'decrement' function to update that value .. " );
|
||||
await decrementValueAtAddress(provider, wallet, contractAbi, contractAddress );
|
||||
console.log("Verify the updated value that was set .. " )
|
||||
await getValueAtAddress(provider, contractAbi, contractAddress);
|
||||
})
|
||||
.catch(console.error);
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main();
|
||||
}
|
||||
|
||||
module.exports = exports = main
|
||||
55
smart_contracts/scripts/public/hre_eth_tx.js
Normal file
55
smart_contracts/scripts/public/hre_eth_tx.js
Normal file
@@ -0,0 +1,55 @@
|
||||
const path = require('path');
|
||||
const fs = require('fs-extra');
|
||||
var ethers = require('ethers');
|
||||
|
||||
// member1 details
|
||||
const { accounts, besu } = require("../keys.js");
|
||||
const host = besu.rpcnode.url;
|
||||
// one of the seeded accounts
|
||||
const accountAPrivateKey = accounts.a.privateKey;
|
||||
|
||||
async function main(){
|
||||
const provider = new ethers.JsonRpcProvider(host);
|
||||
|
||||
const walletA = new ethers.Wallet(accountAPrivateKey, provider);
|
||||
var accountABalance = await provider.getBalance(walletA.address);
|
||||
console.log("Account A has balance of: " + accountABalance);
|
||||
|
||||
// create a new account to use to transfer eth to
|
||||
const walletB = ethers.Wallet.createRandom()
|
||||
var accountBBalance = await provider.getBalance(walletB.address);
|
||||
console.log("Account B has balance of: " + accountBBalance);
|
||||
|
||||
const nonce = await provider.getTransactionCount(walletA.address);
|
||||
const feeData = await provider.getFeeData();
|
||||
const gasLimit = await provider.estimateGas({from: walletA.address, value: ethers.parseEther("0.01")});
|
||||
|
||||
// send some eth from A to B
|
||||
const txn = {
|
||||
nonce: nonce,
|
||||
from: walletA.address,
|
||||
to: walletB.address,
|
||||
value: 0x10, //amount of eth to transfer
|
||||
gasPrice: feeData.gasPrice, //ETH per unit of gas
|
||||
gasLimit: gasLimit //max number of gas units the tx is allowed to use
|
||||
};
|
||||
|
||||
console.log("create and sign the txn")
|
||||
const signedTx = await walletA.sendTransaction(txn);
|
||||
await signedTx.wait();
|
||||
console.log("tx transactionHash: " + signedTx.hash);
|
||||
|
||||
//After the transaction there should be some ETH transferred
|
||||
accountABalance = await provider.getBalance(walletA.address);
|
||||
console.log("Account A has balance of: " + accountABalance);
|
||||
accountBBalance = await provider.getBalance(walletB.address);
|
||||
console.log("Account B has balance of: " + accountBBalance);
|
||||
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main();
|
||||
}
|
||||
|
||||
module.exports = exports = main
|
||||
|
||||
69
smart_contracts/scripts/public/hre_public_tx.js
Normal file
69
smart_contracts/scripts/public/hre_public_tx.js
Normal file
@@ -0,0 +1,69 @@
|
||||
const path = require('path');
|
||||
const fs = require('fs-extra');
|
||||
var ethers = require('ethers');
|
||||
|
||||
// RPCNODE details
|
||||
const { tessera, besu } = require("../keys.js");
|
||||
const host = besu.rpcnode.url;
|
||||
const accountPrivateKey = besu.rpcnode.accountPrivateKey;
|
||||
|
||||
// abi and bytecode generated from simplestorage.sol:
|
||||
// > solcjs --bin --abi simplestorage.sol
|
||||
const contractJsonPath = path.resolve(__dirname, '../../','contracts','SimpleStorage.json');
|
||||
const contractJson = JSON.parse(fs.readFileSync(contractJsonPath));
|
||||
const contractAbi = contractJson.abi;
|
||||
const contractBytecode = contractJson.evm.bytecode.object
|
||||
|
||||
async function getValueAtAddress(provider, deployedContractAbi, deployedContractAddress){
|
||||
const contract = new ethers.Contract(deployedContractAddress, deployedContractAbi, provider);
|
||||
const res = await contract.get();
|
||||
console.log("Obtained value at deployed contract is: "+ res);
|
||||
return res
|
||||
}
|
||||
|
||||
// You need to use the accountAddress details provided to Quorum to send/interact with contracts
|
||||
async function setValueAtAddress(provider, wallet, deployedContractAbi, deployedContractAddress, value){
|
||||
const contract = new ethers.Contract(deployedContractAddress, deployedContractAbi, provider);
|
||||
const contractWithSigner = contract.connect(wallet);
|
||||
const tx = await contractWithSigner.set(value);
|
||||
// verify the updated value
|
||||
await tx.wait();
|
||||
// const res = await contract.get();
|
||||
// console.log("Obtained value at deployed contract is: "+ res);
|
||||
return tx;
|
||||
}
|
||||
|
||||
async function createContract(provider, wallet, contractAbi, contractByteCode, contractInit) {
|
||||
const factory = new ethers.ContractFactory(contractAbi, contractByteCode, wallet);
|
||||
const contract = await factory.deploy(contractInit);
|
||||
// The contract is NOT deployed yet; we must wait until it is mined
|
||||
const deployed = await contract.waitForDeployment();
|
||||
//The contract is deployed now
|
||||
return contract
|
||||
};
|
||||
|
||||
async function main(){
|
||||
const provider = new ethers.JsonRpcProvider(host);
|
||||
const wallet = new ethers.Wallet(accountPrivateKey, provider);
|
||||
|
||||
createContract(provider, wallet, contractAbi, contractBytecode, 47)
|
||||
.then(async function(contract){
|
||||
contractAddress = await contract.getAddress();
|
||||
console.log("Contract deployed at address: " + contractAddress);
|
||||
console.log("Use the smart contracts 'get' function to read the contract's constructor initialized value .. " )
|
||||
await getValueAtAddress(provider, contractAbi, contractAddress);
|
||||
console.log("Use the smart contracts 'set' function to update that value to 123 .. " );
|
||||
await setValueAtAddress(provider, wallet, contractAbi, contractAddress, 123 );
|
||||
console.log("Verify the updated value that was set .. " )
|
||||
await getValueAtAddress(provider, contractAbi, contractAddress);
|
||||
// await getAllPastEvents(host, contractAbi, tx.contractAddress);
|
||||
})
|
||||
.catch(console.error);
|
||||
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main();
|
||||
}
|
||||
|
||||
module.exports = exports = main
|
||||
52
smart_contracts/scripts/public/web3_eth_tx.js
Normal file
52
smart_contracts/scripts/public/web3_eth_tx.js
Normal file
@@ -0,0 +1,52 @@
|
||||
const path = require('path');
|
||||
const fs = require('fs-extra');
|
||||
const Web3 = require('web3');
|
||||
|
||||
// member1 details
|
||||
const { tessera, besu, accounts } = require("../keys.js");
|
||||
const host = besu.rpcnode.url;
|
||||
|
||||
async function main(){
|
||||
const web3 = new Web3(host);
|
||||
//pre seeded account - test account only
|
||||
|
||||
const privateKeyA = accounts.a.privateKey;
|
||||
const accountA = web3.eth.accounts.privateKeyToAccount(privateKeyA);
|
||||
var accountABalance = web3.utils.fromWei(await web3.eth.getBalance(accountA.address));
|
||||
console.log("Account A has balance of: " + accountABalance);
|
||||
|
||||
// create a new account to use to transfer eth to
|
||||
var accountB = web3.eth.accounts.create();
|
||||
var accountBBalance = web3.utils.fromWei(await web3.eth.getBalance(accountB.address));
|
||||
console.log("Account B has balance of: " + accountBBalance);
|
||||
|
||||
// send some eth from A to B
|
||||
const txn = {
|
||||
nonce: web3.utils.numberToHex(await web3.eth.getTransactionCount(accountA.address)),
|
||||
from: accountA.address,
|
||||
to: accountB.address,
|
||||
value: "0x100", //amount of eth to transfer
|
||||
gasPrice: "0x0", //ETH per unit of gas
|
||||
gasLimit: "0x24A22" //max number of gas units the tx is allowed to use
|
||||
};
|
||||
|
||||
console.log("create and sign the txn")
|
||||
const signedTx = await web3.eth.accounts.signTransaction(txn, accountA.privateKey);
|
||||
console.log("sending the txn")
|
||||
const txReceipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction);
|
||||
console.log("tx transactionHash: " + txReceipt.transactionHash);
|
||||
|
||||
//After the transaction there should be some ETH transferred
|
||||
accountABalance = web3.utils.fromWei(await web3.eth.getBalance(accountA.address));
|
||||
console.log("Account A has an updated balance of: " + accountABalance);
|
||||
accountBBalance = web3.utils.fromWei(await web3.eth.getBalance(accountB.address));
|
||||
console.log("Account B has an updated balance of: " + accountBBalance);
|
||||
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main();
|
||||
}
|
||||
|
||||
module.exports = exports = main
|
||||
|
||||
Reference in New Issue
Block a user