ProHoster > Blog > Administración > Realiza transaccións públicas e privadas na cadea de bloques de JPMorgan Quorum usando Web3
Realiza transaccións públicas e privadas na cadea de bloques de JPMorgan Quorum usando Web3
quorum é unha cadea de bloques baseada en Ethereum desenvolvida por JPMorgan e, máis recentemente, converteuse na primeira plataforma de contabilidade distribuída que ofrece Microsoft Azure.
Quorum admite transaccións públicas e privadas e ten moitos casos de uso comercial.
Neste artigo, examinaremos un destes escenarios: a implantación dunha rede de libros de contas distribuídas entre un supermercado e o propietario dun almacén para proporcionar información actualizada sobre a temperatura do almacén.
Para ilustralo, utilizamos un escenario para controlar a temperatura nos almacéns dos membros da rede Quorum dentro da Internet das cousas (IoT).
Contexto
Un grupo de empresas de almacén únense nun consorcio para almacenar conxuntamente información e automatizar procesos na cadea de bloques. Para iso, as empresas decidiron utilizar Quorum. Neste artigo abordaremos dous escenarios: transaccións públicas e transaccións privadas.
As transaccións son creadas por diferentes participantes para interactuar co consorcio ao que pertencen. Cada transacción desprega un contrato ou chama a unha función do contrato para cargar datos á rede. Estas accións replícanse en todos os nodos da rede.
As transaccións públicas están dispoñibles para a súa visualización por todos os participantes do consorcio. As transaccións privadas engaden unha capa de confidencialidade e só están dispoñibles para aqueles participantes que teñan dereitos para facelo.
Para os dous escenarios, usamos o mesmo contrato para claridade.
Contrato intelixente
A continuación móstrase un contrato intelixente sinxelo creado para o noso escenario. Ten unha variable pública temperature, que se pode cambiar usando set e recibir por método get.
pragma solidity ^0.4.25;
contract TemperatureMonitor {
int8 public temperature;
function set(int8 temp) public {
temperature = temp;
}
function get() view public returns (int8) {
return temperature;
}
}
Para que o contrato funcione web3.js, debe traducirse ao formato ABI e ao bytecode. Usando a función formatContracta continuación compila o contrato utilizando solc-js.
Agora que o contrato está listo, implementaremos a rede e o contrato.
Implantación de nodos
A implantación dun nodo pode ser moi laboriosa e este proceso pódese substituír mediante un servizo Chainstack.
A continuación móstrase o proceso para a implantación da rede Quorum co consenso de Raft e tres nodos.
Primeiro, imos crear un proxecto e chamalo Proxecto Quórum:
Imos crear unha rede Quorum co consenso de Raft en Google Cloud Platform:
Engadimos dous nodos máis ao nodo xa creado por defecto:
Tres nodos en execución:
A páxina de detalles do nodo mostra o punto final RPC, a chave pública, etc.
A rede está implantada. Agora imos implementar contratos intelixentes e realizar transaccións usando web3.js.
Transaccións públicas
Contexto
A temperatura do almacén é de gran importancia para reducir os custos, especialmente para os produtos destinados a almacenarse a temperaturas baixo cero.
Ao permitir ás empresas compartir a temperatura exterior da súa localización xeográfica en tempo real e rexistrala nun libro inmutable, os participantes da rede reducen custos e tempo.
Realizaremos tres tarefas, ilustradas no diagrama:
Implementaremos o contrato vía Nodo 1:
const contractAddress = await deployContract(raft1Node);
console.log(`Contract address after deployment: ${contractAddress}`);
Establece a temperatura mediante Nodo 2 en 3 graos:
const status = await setTemperature(raft2Node, contractAddress, 3);
console.log(`Transaction status: ${status}`);
Nodo 3 recibirá información do contrato intelixente. O contrato devolverá o valor de 3 graos:
A continuación, veremos como executar unha transacción pública na rede Quorum usando web3.js.
Iniciamos unha instancia a través de RPC para tres nodos:
const raft1Node = new Web3(
new Web3.providers.HttpProvider(process.env.RPC1), null, {
transactionConfirmationBlocks: 1,
},
);
const raft2Node = new Web3(
new Web3.providers.HttpProvider(process.env.RPC2), null, {
transactionConfirmationBlocks: 1,
},
);
const raft3Node = new Web3(
new Web3.providers.HttpProvider(process.env.RPC3), null, {
transactionConfirmationBlocks: 1,
},
);
Implementemos o contrato intelixente:
// returns the default account from the Web3 instance initiated previously
function getAddress(web3) {
return web3.eth.getAccounts().then(accounts => accounts[0]);
}
// Deploys the contract using contract's interface and node's default address
async function deployContract(web3) {
const address = await getAddress(web3);
// initiate contract with contract's interface
const contract = new web3.eth.Contract(
temperatureMonitor.interface
);
return contract.deploy({
// deploy contract with contract's bytecode
data: temperatureMonitor.bytecode,
})
.send({
from: address,
gas: '0x2CD29C0',
})
.on('error', console.error)
.then((newContractInstance) => {
// returns deployed contract address
return newContractInstance.options.address;
});
}
web3.js ofrece dous métodos para interactuar co contrato: call и send.
Actualicemos a temperatura do contrato executando set utilizando o método web3 send.
// get contract deployed previously
async function getContract(web3, contractAddress) {
const address = await getAddress(web3);
return web3.eth.Contract(
temperatureMonitor.interface,
contractAddress, {
defaultAccount: address,
}
);
}
// calls contract set method to update contract's temperature
async function setTemperature(web3, contractAddress, temp) {
const myContract = await getContract(web3, contractAddress);
return myContract.methods.set(temp).send({}).then((receipt) => {
return receipt.status;
});
}
A continuación usamos o método web3 call para obter a temperatura do contrato. Teña en conta que o método call execútase nun nodo local e a transacción non se creará na cadea de bloques.
// calls contract get method to retrieve contract's temperature
async function getTemperature(web3, contractAddress) {
const myContract = await getContract(web3, contractAddress);
return myContract.methods.get().call().then(result => result);
}
Agora podes correr público.js para obter o seguinte resultado:
// Execute public script
node public.js
Contract address after deployment: 0xf46141Ac7D6D6E986eFb2321756b5d1e8a25008F
Transaction status: true
Retrieved contract Temperature 3
A continuación, podemos ver as entradas no explorador de Quórum no panel Chainstack, como se mostra a continuación.
Os tres nodos interactuaron e actualizáronse as transaccións:
A primeira transacción despregou o contrato.
A segunda transacción fixou a temperatura do contrato en 3 graos.
A temperatura recíbese a través dun nodo local, polo que non se crea ningunha transacción.
Transaccións privadas
Contexto
Un requisito común das organizacións é a protección de datos. Como exemplo, considere un escenario no que Supermercado aluga un espazo de almacén para almacenar produtos do mar dun separado Vendedor:
Vendedor usando sensores IoT, le os valores de temperatura cada 30 segundos e os transmite Ao supermercado;
estes valores só deberían estar dispoñibles Ao vendedor и Ao supermercado, en rede por un consorcio.
Realizaremos as catro tarefas ilustradas no diagrama anterior.
Usamos os mesmos tres nodos do escenario anterior para demostrar transaccións privadas:
Supermercado implementa un contrato intelixente que é privado para Supermercado и Vendedor.
O terceiro lado non ten dereito a acceder ao contrato intelixente.
Chamaremos os métodos get и set en nome de Supermercado и Vendedor para demostrar unha transacción privada de Quórum.
Implementaremos un contrato privado para os participantes Supermercado и Vendedor a través dun participante Supermercado:
Imos configurar a temperatura desde Terceiro (nodo externo) e obtén o valor da temperatura:
// Attempts to set Contract temperature to 10, this will not mutate contract's temperature
await setTemperature(
raft3Node,
contractAddress,
process.env.PK1,
10,
);
// This returns null
const temp = await getTemperature(raft3Node, contractAddress);
console.log(`[Node3] temp retrieved after updating contract from external nodes: ${temp}`);
Imos configurar a temperatura desde Vendedor (nodo interno) e obtén o valor da temperatura:
A temperatura neste escenario debería devolver o valor 12 do contrato intelixente. Teña en conta que Vendedor aquí ten acceso autorizado ao contrato intelixente.
// Updated Contract temperature to 12 degrees
await setTemperature(
raft2Node,
contractAddress,
process.env.PK1,
12,
);
// This returns 12
const temp2 = await getTemperature(raft2Node, contractAddress);
console.log(`[Node2] temp retrieved after updating contract from internal nodes: ${temp2}`);
Tomamos a temperatura de Terceiro (nodo externo):
No paso 3 a temperatura estableceuse en 12, pero O terceiro lado non ten acceso ao contrato intelixente. Polo tanto, o valor de retorno debe ser nulo.
// This returns null
const temp3 = await getTemperature(raft3Node, contractAddress);
console.log(`[Node3] temp retrieved from external nodes after update ${temp}`);
A continuación, analizaremos con máis detalle a realización de transaccións privadas na rede Quorum web3.js. Dado que a maior parte do código é o mesmo para as transaccións públicas, só destacaremos aquelas partes que son diferentes para as transaccións privadas.
Teña en conta que o contrato cargado na rede é inmutable, polo que o acceso con permiso debe concederse aos nodos apropiados habilitando o contrato público no momento en que se despregue o contrato, non despois.
async function deployContract(web3, publicKey) {
const address = await getAddress(web3);
const contract = new web3.eth.Contract(
temperatureMonitor.interface,
);
return contract.deploy({
data: temperatureMonitor.bytecode,
})
.send({
from: address,
gas: ‘0x2CD29C0’,
// Grant Permission to Contract by including nodes public keys
privateFor: [publicKey],
})
.then((contract) => {
return contract.options.address;
});
}
As transaccións privadas realízanse dun xeito similar, incluíndo a clave pública dos participantes no momento da execución.
async function setTemperature(web3, contractAddress, publicKey, temp) {
const address = await getAddress(web3);
const myContract = await getContract(web3, contractAddress);
return myContract.methods.set(temp).send({
from: address,
// Grant Permission by including nodes public keys
privateFor: [publicKey],
}).then((receipt) => {
return receipt.status;
});
}
Agora podemos correr privado.js cos seguintes resultados:
node private.js
Contract address after deployment: 0x85dBF88B4dfa47e73608b33454E4e3BA2812B21D
[Node3] temp retrieved after updating contract from external nodes: null
[Node2] temp retrieved after updating contract from internal nodes: 12
[Node3] temp retrieved from external nodes after update null
O explorador de Quórum en Chainstack mostrará o seguinte:
despregamento do contrato do participante Supermercado;
Actuación SetTemperature de Terceiro;
Actuación SetTemperature dun participante Vendedor.
Como podes ver, complétanse ambas as transaccións, pero só a transacción do participante Vendedor actualizou a temperatura no contrato. Así, as transaccións privadas proporcionan inmutabilidade, pero ao mesmo tempo non revelan datos a un terceiro.
Conclusión
Analizamos un caso de uso comercial de Quorum para proporcionar información actualizada sobre a temperatura nun almacén mediante a implantación dunha rede entre dúas partes: un supermercado e o propietario dun almacén.
Amosamos como se pode manter a información actualizada sobre a temperatura mediante transaccións públicas e privadas.
Pode haber moitos escenarios de aplicación e, como podes ver, non é nada difícil.