Skip to content
Snippets Groups Projects
Commit 1e6a0778 authored by Andrés Blanco's avatar Andrés Blanco
Browse files

Mejoras para poder comunicarse con BFA

Debido a la recomendación de geth de no unlockear las cuentas se
tuvieron que tomar ciertas medidas para poder bypassear esa necesidad.
Básicamente se parametrizó la cuenta y password a utilizar.
parent a0c5bb54
No related branches found
No related tags found
No related merge requests found
847e7d6ea18a417496518dc90b547438bf1b3d05.json
......@@ -28,6 +28,11 @@ El proyecto está compuesto por tres componentes, los contratos, una api rest
y una interfaz gráfica.
### Deployar los contratos
La primera vez hay que ejecutar lo siguiente dentro del directorio ```contract```
```shell
npm install
```
Para manejar los contratos se utilizó truffle, para hacer el deploy de los
contratos hay que correr dentro del directorio ```contract``` el siguiente comando
```shell
......@@ -119,13 +124,14 @@ node dist/index.js
Se pueden definir las siguientes variables de entorno para parametrizar el servidor:
* **GETH_HOST**: url del host geth a conectarse. Por defecto ***http://localhost:7545***
* **GETH_ACCOUNT**: account a utilizar. Por defecto se utiliza la que está la
pos 0 de ```web3.eth.getAccounts()```
* **GETH_ACCOUNT_JSON**: Path a la key encriptada (V3) donde se encuentra la account
a utilizar. Por defecto se utiliza la que está la pos 0 de ```web3.eth.getAccounts()```
* **GETH_ACCOUNT_PASSWORD**: Clave plana de la key provista en ***GETH_ACCOUNT_JSON***
* **CONTRACT_ABI_PATH**: path al archivo que contiene el abi. Puede ser un path
absoluto.
Si es relativo la ruta se calcula desde el dir api/dist. Por defecto se trata
de cargar desde el directorio build de truffle (```contract/build/contracts/Stamper.json```)
* **CONTRACT_ABI_ADDRESS**: dirección del contrato. Por defecto se utiliza la
* **CONTRACT_ADDRESS**: dirección del contrato. Por defecto se utiliza la
que está en el archivo de build de truffle para el netId actual
* **USE_CORS**: permite des/habilitar el CORS a este server. Por defecto está
habilitado. Para deshabilitar pasar ***USE_CORS=0***
......@@ -142,10 +148,20 @@ Se pueden definir las siguientes variables de entorno para parametrizar el servi
```
La otra forma es setearlos al correr node, eg:
```shell
```s
PORT=8010 USE_CORS=0 node dist/index.js
```
Ejemplo que levanta corriendo contra BFA:
```s
GETH_ACCOUNT_JSON=$(pwd)/../../847e7d6ea18a417496518dc90b547438bf1b3d05.json \
GETH_ACCOUNT_PASSWORD=mipasswordseguro \
GETH_HOST=http://localhost:8545 \
CONTRACT_ABI_PATH=$(pwd)/abi.json \
CONTRACT_ADDRESS=0x7e56220069CAaF8367EA42817EA9210296AeC7c6 \
node dist/index.js
```
### Deploy de la UI
Al buildear se crea el archivo ```ui/dist/index.html``` y todo el resto de los recursos
necesarios. Al acceder al index.html sólo se ve el componente de Stampeo. El html se ve así:
......
# Ejemplo en BFA
```bash
cd api
GETH_ACCOUNT_JSON=$(pwd)/../../847e7d6ea18a417496518dc90b547438bf1b3d05.json \
GETH_ACCOUNT_PASSWORD=passwordseguro \
GETH_HOST=http://localhost:8545 \
CONTRACT_ABI_PATH=$(pwd)/abi.json \
CONTRACT_ADDRESS=0x7e56220069CAaF8367EA42817EA9210296AeC7c6 \
npm run serve
```
\ No newline at end of file
[
{
"inputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "constructor",
"signature": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "from",
"type": "address"
},
{
"indexed": true,
"name": "object",
"type": "bytes32"
},
{
"indexed": false,
"name": "blockNo",
"type": "uint256"
}
],
"name": "Stamped",
"type": "event",
"signature": "0x3a0b5d7066b49e6f19e8199e84c7a296092240386482cc1b23a7c4e3c98a79d5"
},
{
"constant": false,
"inputs": [
{
"name": "objectList",
"type": "bytes32[]"
}
],
"name": "put",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function",
"signature": "0x3a00faae"
},
{
"constant": true,
"inputs": [
{
"name": "pos",
"type": "uint256"
}
],
"name": "getStamplistPos",
"outputs": [
{
"name": "",
"type": "bytes32"
},
{
"name": "",
"type": "address"
},
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function",
"signature": "0x9d192428"
},
{
"constant": true,
"inputs": [
{
"name": "object",
"type": "bytes32"
}
],
"name": "getObjectCount",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function",
"signature": "0xc2433cd3"
},
{
"constant": true,
"inputs": [
{
"name": "object",
"type": "bytes32"
},
{
"name": "pos",
"type": "uint256"
}
],
"name": "getObjectPos",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function",
"signature": "0x789bbb41"
},
{
"constant": true,
"inputs": [
{
"name": "object",
"type": "bytes32"
},
{
"name": "stamper",
"type": "address"
}
],
"name": "getBlockNo",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function",
"signature": "0xbbc48b7c"
},
{
"constant": true,
"inputs": [
{
"name": "stamper",
"type": "address"
}
],
"name": "getStamperCount",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function",
"signature": "0xc15ed491"
},
{
"constant": true,
"inputs": [
{
"name": "stamper",
"type": "address"
},
{
"name": "pos",
"type": "uint256"
}
],
"name": "getStamperPos",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function",
"signature": "0xa08d1a4f"
}
]
\ No newline at end of file
import { sign } from "crypto";
//const stamperInterface = require('../../contract/build/contracts/Stamper.json')
class Stamper {
constructor(web3, contractAbi, contractAddress) {
this.web3 = web3
this.contractAddress = contractAddress
this.contract = new web3.eth.Contract(contractAbi, contractAddress)
}
setSender(fromAddress) {
this.from = fromAddress
}
async stamp(hashes) {
// stampea un conjunto de hashes.
// si walletAccount es undefined trata de usar la account de web3.eth.defaultAccount
async stamp(hashes, walletAccount) {
console.log(`stamping ${hashes}`)
let defaultAccount = (walletAccount) ? walletAccount.address : this.web3.eth.defaultAccount
let hashesToStamp = []
for (let i=0; i < hashes.length; i++) {
let blockNo = await this.contract.methods.getBlockNo(hashes[i], this.from).call()
let blockNo = await this.contract.methods.getBlockNo(hashes[i], defaultAccount).call()
if (blockNo == 0) hashesToStamp.push(hashes[i])
}
......@@ -25,10 +27,36 @@ class Stamper {
resolve()
})
let txPromise = this.contract.methods.put(hashesToStamp).send({
from: this.from,
gasLimit: 500000
})
let txPromise
let gasLimit = 2000000
if (walletAccount) {
let methodPut = this.contract.methods.put(hashesToStamp)
let encodedABI = methodPut.encodeABI()
let tx = {
to: this.contractAddress,
// v: 47525974938 * 35 + 2,
// v: 47525974938,
chainId: '200941592',
gas: gasLimit,
// gasLimit: gasLimit,
data: encodedABI
}
// tx.v = Buffer.from([47525974938])
// tx.nonce = this.web3.utils.toHex(await this.web3.eth.getTransactionCount(defaultAccount))
let signedTx = await walletAccount.signTransaction(tx)
// console.log(signedTx)
// txPromise = this.web3.eth.sendSignedTransaction(signedTx)
// txPromise = this.web3.eth.sendSignedTransaction('0x' + signedTx.serialize().toString('hex'))
txPromise = this.web3.eth.sendSignedTransaction(signedTx.rawTransaction)
} else {
txPromise = this.contract.methods.put(hashesToStamp).send({
from: defaultAccount,
gasLimit: gasLimit
})
}
txPromise.then((receipt) => {
console.log(`> hashes stampeados en bloque: ${receipt.blockNumber}`)
......
......@@ -5,17 +5,15 @@ import express from 'express'
import cors from 'cors'
import bodyParser from 'body-parser'
import basicAuth from 'express-basic-auth'
//import SimpleStamper from './simpleStamperWrapper'
import Stamper from './StamperWrapper'
import fs from 'fs'
/***************************************************/
// Conexión al provider
/***************************************************/
const providerHost = process.env.GETH_HOST || 'http://localhost:7545'
const accountIsSet = process.env.GETH_ACCOUNT || false
// si no se seteó una account se usa esta const como el indice de accounts de ganache
const account = (accountIsSet) ? process.env.GETH_ACCOUNT : 0
// const providerHost = process.env.GETH_HOST || 'http://localhost:8545'
const accountIsSet = process.env.GETH_ACCOUNT_JSON || false
var web3 = web3
if (typeof web3 !== 'undefined') {
......@@ -28,16 +26,48 @@ if (typeof web3 !== 'undefined') {
setupWeb3()
}
let contractAbi;
let contractAddress;
let walletAccount;
async function setupWeb3() {
try {
let netIsListening = await web3.eth.net.isListening()
let netId = await web3.eth.net.getId()
web3.eth.defaultAccount = (accountIsSet) ? account : (await web3.eth.getAccounts())[account]
if (accountIsSet) {
let rawKeyJsonV3 = fs.readFileSync(process.env.GETH_ACCOUNT_JSON)
let keyJsonV3 = JSON.parse(rawKeyJsonV3)
let key = web3.eth.accounts.decrypt(keyJsonV3, process.env.GETH_ACCOUNT_PASSWORD)
walletAccount = web3.eth.accounts.wallet.add(key)
web3.eth.defaultAccount = (await web3.eth.getAccounts())[0]
} else {
// se trata de utilizar una que haya abierta
web3.eth.defaultAccount = (await web3.eth.getAccounts())[0]
}
/***************************************************/
// Carga de contrato
/***************************************************/
if (process.env.CONTRACT_ABI_PATH) {
contractAbi = require(process.env.CONTRACT_ABI_PATH)
if (!process.env.CONTRACT_ADDRESS) {
console.error('Si se especifica el path de un abi, debe proveerse un address con la env CONTRACT_ADDRESS')
process.exit(1)
}
contractAddress = process.env.CONTRACT_ADDRESS
} else {
let path = '../../contract/build/contracts/Stamper.json'
console.log(`Intentando cargar ${path} netId: ${netId}`)
let data = require(path)
contractAbi = data.abi
contractAddress = data.networks[netId].address
}
console.log(`Conectado exitosamente:
> host: ${providerHost}
> netId: ${netId}
> account: ${web3.eth.defaultAccount}
> address: ${contractAddress}
`)
} catch (e) {
console.error('Error de conexión')
......@@ -47,29 +77,7 @@ async function setupWeb3() {
}
/***************************************************/
// Carga de contrato
/***************************************************/
let contractAbi;
let contractAddress;
if (process.env.CONTRACT_ABI_PATH) {
contractAbi = require(process.env.CONTRACT_ABI_PATH)
if (!process.env.CONTRACT_ADDRESS) {
console.error('Si se especifica el path de un abi, debe proveerse un address con la env CONTRACT_ADDRESS')
process.exit(1)
}
contractAddress = process.env.CONTRACT_ADDRESS
} else {
let path = '../../contract/build/contracts/Stamper.json'
console.log(`Intentando cargar ${path}`)
let data = require(path)
contractAbi = data.abi
web3.eth.net.getId().then(function(netId) {
contractAddress = data.networks[netId].address
})
}
/***************************************************/
// Setup API
// Setup CORS y Auth
/***************************************************/
const app = express()
......@@ -96,7 +104,6 @@ if (process.env.API_USER && process.env.API_PASS) {
/***************************************************/
app.post('/stamp', async (req, res) => {
let ss = new Stamper(web3, contractAbi, contractAddress)
ss.setSender(web3.eth.defaultAccount)
if (!("hashes" in req.body)) {
res.status(422)
......@@ -120,7 +127,7 @@ app.post('/stamp', async (req, res) => {
}
try {
let txHash = await ss.stamp(hashes)
let txHash = await ss.stamp(hashes, walletAccount)
//let fullUrl = req.protocol + '://' + req.get('host')
res.status(200).send('success')
} catch (e) {
......@@ -132,7 +139,6 @@ app.post('/stamp', async (req, res) => {
app.get('/verify/:hash', async (req, res) => {
let ss = new Stamper(web3, contractAbi, contractAddress)
ss.setSender(web3.eth.defaultAccount)
var value = req.params.hash
if (! value.startsWith('0x')) {
......
.DS_Store
build
node_modules
# Deployando a BFA
Para hacer esto tuve que utilizar truffle-hdwallet-provider. Esto fue debido a
la imposibilidad de unlockear la account en geth directamente por un cambio reciente.
Para elegir la account que se quiere utilizar hay que pasar la pkey de la account en la variable
de entorno ```GETH_ACCOUNT_PKEY```.
La invocación se hace así *esto deployea a bfa*
```bash
GETH_ACCOUNT_PKEY=840e5ddddda6037390329b2d0b65f422f2555555555b6de292cc574fff212345 truffle migrate --network bfa
```
Para obtener la pkey desde el keystore de geth seguí las siguiente instrucciones: https://ethereum.stackexchange.com/questions/12830/how-to-get-private-key-from-account-address-and-password
Para hacerlo desde el REPL esto ayudó: https://stackoverflow.com/questions/18260605/how-to-require-node-module-in-node-repl-without-installing-globally
const Migrations = artifacts.require("Migrations");
module.exports = function(deployer) {
module.exports = function(deployer, network) {
deployer.deploy(Migrations);
};
const Stamper = artifacts.require("Stamper");
module.exports = function(deployer) {
module.exports = function(deployer, network) {
deployer.deploy(Stamper);
};
This diff is collapsed.
{
"name": "tsa2-contract",
"version": "1.0.0",
"description": "",
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"truffle-hdwallet-provider": "^1.0.9"
}
}
......@@ -21,9 +21,10 @@
// const HDWalletProvider = require('truffle-hdwallet-provider');
// const infuraKey = "fj4jll3k.....";
//
// const fs = require('fs');
// const mnemonic = fs.readFileSync(".secret").toString().trim();
const HDWalletProvider = require("truffle-hdwallet-provider");
module.exports = {
/**
* Networks define how you connect to your ethereum client and let you set the
......@@ -36,6 +37,12 @@ module.exports = {
*/
networks: {
bfa: {
host: "127.0.0.1", // Localhost (default: none)
port: 8545, // Standard Ethereum port (default: none)
provider: () => new HDWalletProvider(process.env.GETH_ACCOUNT_PKEY, "http://127.0.0.1:8545"),
network_id: "47525974938", // Any network (default: none)
}
// Useful for testing. The `development` name is special - truffle uses it by default
// if it's defined here and no other network is specified at the command line.
// You should run a client (like ganache-cli, geth or parity) in a separate terminal
......@@ -97,3 +104,5 @@ module.exports = {
}
}
}
//provider.engine.stop()
\ No newline at end of file
......@@ -11,7 +11,7 @@
<noscript>
<strong>We're sorry but ui doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app" apiurl="http://localhost:3000"></div>
<div id="app" apiurl="http://localhost:3001"></div>
<!-- built files will be auto injected -->
</body>
</html>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment