From 493679b934010896ee1023c79836397f296e81df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20B=C3=A9raud?= <adrien.beraud@savoirfairelinux.com> Date: Fri, 20 Mar 2020 17:32:00 -0400 Subject: [PATCH] node: cache address Change-Id: I10daaf8c778a45bc7d1c0af05eac311c13068bc6 --- index.js | 158 +++++++++++++++++++++++++------------------------ read_names.js | 71 ++++++++++++++-------- write_names.js | 20 +++++++ 3 files changed, 147 insertions(+), 102 deletions(-) mode change 100644 => 100755 read_names.js mode change 100644 => 100755 write_names.js diff --git a/index.js b/index.js index 3544727..763fb20 100755 --- a/index.js +++ b/index.js @@ -1,5 +1,6 @@ +#!/usr/bin/env nodejs /* - * Copyright (c) 2016-2017 Savoir-faire Linux Inc. + * Copyright (c) 2016-2020 Savoir-faire Linux Inc. * * Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com> * @@ -33,6 +34,7 @@ const path = require('path'); //Patch to support caching. //map of form {name,address} const cache = {}; +const addrCache = {}; function validateFile(filename){ if ( path.isAbsolute(filename) && fs.existsSync(filename) ) @@ -45,16 +47,16 @@ function validateFile(filename){ function loadCache(batchInputFile) { const NAME_LIST = JSON.parse(fs.readFileSync(batchInputFile, 'utf8')); for (const entry of Object.entries(NAME_LIST)) { - cache[entry[0]] = entry[1] + cache[entry[1]['name']] = entry[1]; + addrCache[entry[1]['addr']] = entry[1]; } + console.log('Loaded ' + Object.keys(cache).length + ' from cache'); } - - Object.getPrototypeOf(web3.eth).awaitConsensus = function(txhash, mined_cb) { - var ethP = this; - var tries = 5; - var filter = this.filter('latest'); + const ethP = this; + let tries = 5; + let filter = this.filter('latest'); filter.watch(function(error, result) { if (error) console.log("watch error: " + error); @@ -68,23 +70,20 @@ Object.getPrototypeOf(web3.eth).awaitConsensus = function(txhash, mined_cb) { }); } +console.log('Loading...'); web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545')); -const coinbase = web3.eth.coinbase; -console.log(coinbase); -let balance = web3.eth.getBalance(coinbase); -console.log(balance.toString(10)); const REG_FILE = __dirname + "/contract/registrar.out.json"; const REG_ADDR_FILE = __dirname + "/contractAddress.txt"; const NAME_VALIDATOR = new RegExp('^[a-z0-9-_]{3,32}$'); -let account; +let coinbase; +let balance; let regAddress = "0xe53cb2ace8707526a5050bec7bcf979c57f8b44f"; let regData; let regContract; let reg; - function loadNames(filename){ console.log("The cache will be populated with the data from the export file!"); const providedPath = String(argv['_'][0]); @@ -106,10 +105,6 @@ function verifySignature(name, _publickey, signature){ return ver; } -function unlockAccount() { - web3.personal.unlockAccount(coinbase, "apple123"); -} - function getRemainingGaz() { return web3.eth.getBalance(coinbase) / web3.eth.gasPrice; } @@ -141,31 +136,26 @@ function loadContract(onContractLoaded) { } else { regAddress = String(content).trim(); } - fs.readFile(REG_FILE, function(err, data){ + fs.readFile(REG_FILE, (err, data) => { if (err) { console.log("Can't read contract ABI: " + err); throw err; } + const dat = JSON.parse(data); regData = JSON.parse(data).contracts.registrar.GlobalRegistrar; - regContract = web3.eth.contract(regData.abi); + regContract = new web3.eth.Contract(regData.abi); console.log("Loading name contract from blockchain at " + regAddress); - web3.eth.getCode(regAddress, function(error, result) { + web3.eth.getCode(regAddress, (error, result) => { if (error) console.log("Error getting contract code: " + error); if (!result || result == "0x") { console.log("Contract not found at " + regAddress); initContract(onContractLoaded); } else { - regContract.at(regAddress, function(err, result) { - console.log("Contract found and loaded from " + regAddress); - if(!err) { - reg = result; - onContractLoaded(reg) - } - else { - console.error("err: " + err); - } - }); + regContract.options.address = regAddress; + regContract.options.from = coinbase; + reg = regContract; + onContractLoaded(reg); } }); }); @@ -173,10 +163,10 @@ function loadContract(onContractLoaded) { } function initContract(onContractInitialized) { - waitForGaz(3000000, function(){ + waitForGaz(1000000, () => { regContract.new({ from: coinbase, data: '0x'+regData.evm.bytecode.object, - gas: 3000000 }, function(e, contract) { + gas: 1000000 }, (e, contract) => { if(!e) { if(!contract.address) { console.log("Contract transaction send: TransactionHash: " + contract.transactionHash + " waiting to be mined..."); @@ -211,7 +201,7 @@ function isHashZero(h) { } function parseString(s) { - return s ? web3.toUtf8(s) : s; + return s ? web3.utils.hexToUtf8(s) : s; } function formatAddress(address) { @@ -224,7 +214,7 @@ function formatAddress(address) { s = "0x" + s; if (new BigNumber(s.substr(2), 16) == 0) return undefined; - return s; + return s.toLowerCase(); } catch (err) {} } return undefined; @@ -233,7 +223,7 @@ function formatAddress(address) { function readCertificateChain(path) { let cert = []; const ca = []; - fs.readFileSync(path, 'utf8').split("\n").forEach(function(line) { + fs.readFileSync(path, 'utf8').split("\n").forEach((line) => { cert.push(line); if (line.match(/-END CERTIFICATE-/)) { ca.push(cert.join("\n")); @@ -248,15 +238,15 @@ function startServer(result) { const app = express(); app.disable('x-powered-by'); app.use(bodyParser.json()); - app.use(function(req, res, next) { + app.use((req, res, next) => { res.setHeader('Content-Type', 'application/json'); next(); }); // Register name lookup handler - app.get("/name/:name", function(req, http_res) { + app.get("/name/:name", (req, http_res) => { try { - reg.addr(formatName(req.params.name), function(err, res_addr) { + reg.methods.addr(formatName(req.params.name)).call((err, res_addr) => { try { if (err) console.log("Name lookup error: " + err); @@ -264,22 +254,23 @@ function startServer(result) { throw Error("name not registered"); //http_res.status(404).end(JSON.stringify({"error": "name not registered"})); } else { - reg.publickey(formatName(req.params.name), function(err, res_publickey) { + reg.methods.publickey(formatName(req.params.name)).call((err, res_publickey) => { try { if (err) console.log("Name lookup error: " + err); if (isHashZero(res_publickey)) { http_res.end(JSON.stringify({"name": req.params.name, "addr": res_addr})); } else { - reg.signature(formatName(req.params.name), function(err, res_signature) { + reg.methods.signature(formatName(req.params.name)).call((err, res_signature) => { try { if (err) console.log("Name lookup error: " + err); - if (isHashZero(res_signature)) { - http_res.end(JSON.stringify({"name": req.params.name, "addr": res_addr})); - } else { - http_res.end(JSON.stringify({"name": req.params.name, "addr": res_addr, "publickey": res_publickey, "signature": res_signature })); - } + const resObj = isHashZero(res_signature) + ? {"name": req.params.name, "addr": res_addr} + : {"name": req.params.name, "addr": res_addr, "publickey": res_publickey, "signature": res_signature }; + cache[req.params.name] = resObj; + addrCache[res_addr] = resObj; + http_res.end(JSON.stringify(resObj)); } catch (err) { console.log("Name lookup exception: " + err); http_res.status(500).end(JSON.stringify({"error": "server error"})); @@ -293,16 +284,12 @@ function startServer(result) { }); } } catch (err) { - if(cache[req.params.name] != undefined){ - if(cache[req.params.name]['publickey'] && cache[req.params.name]['signature']){ - http_res.end(JSON.stringify({"name": req.params.name, "addr": cache[req.params.name]['addr'], "publickey": cache[req.params.name]['publickey'], "signature": cache[req.params.name]['signature']})); - } - else{ - http_res.end(JSON.stringify({"name": req.params.name, "addr": cache[req.params.name]['addr']})); - } + const cachedName = cache[req.params.name]; + if (cachedName != undefined) { + http_res.end(JSON.stringify(cachedName)); } - else{ - http_res.status(404).end(JSON.stringify({"error": "name not registered"})); + else { + http_res.status(404).end(JSON.stringify({"error": "name not registered"})); } } }); @@ -312,9 +299,9 @@ function startServer(result) { } }); - app.get("/name/:name/publickey", function(req, http_res) { + app.get("/name/:name/publickey", (req, http_res) => { try { - reg.publickey(formatName(req.params.name), function(err, res) { + reg.methods.publickey(formatName(req.params.name)).call((err, res) => { try { if (err) console.log("Name lookup error: " + err); @@ -334,9 +321,9 @@ function startServer(result) { } }); - app.get("/name/:name/signature", function(req, http_res) { + app.get("/name/:name/signature", (req, http_res) => { try { - reg.signature(formatName(req.params.name), function(err, res) { + reg.methods.signature(formatName(req.params.name)).call((err, res) => { try { if (err) console.log("Name lookup error: " + err); @@ -357,9 +344,9 @@ function startServer(result) { }); // Register owner lookup handler - app.get("/name/:name/owner", function(req, http_res) { + app.get("/name/:name/owner", (req, http_res) => { try { - reg.owner(req.params.name, function(err, res) { + reg.methods.owner(req.params.name).call((err, res) => { try { if (err) console.log("Owner lookup error: " + err); @@ -380,7 +367,7 @@ function startServer(result) { }); // Register address lookup handler - app.get("/addr/:addr", function(req, http_res) { + app.get("/addr/:addr", (req, http_res) => { try { var addr = formatAddress(req.params.addr); if (!addr) { @@ -388,15 +375,21 @@ function startServer(result) { http_res.status(400).end(JSON.stringify({"success": false})); return; } - reg.name(addr, function(err, res) { + reg.methods.name(addr).call((err, res) => { try { if (err) console.log("Address lookup error: " + err); var name = parseString(res); if (name) http_res.end(JSON.stringify({"name": name})); - else - http_res.status(404).end(JSON.stringify({"error": "address not registered"})); + else { + const cachedAddr = addrCache[addr]; + if (cachedAddr != undefined) { + http_res.end(JSON.stringify(cachedAddr)); + } else { + http_res.status(404).end(JSON.stringify({"error": "address not registered"})); + } + } } catch (err) { console.log("Address lookup exception: " + err); http_res.status(500).end(JSON.stringify({"error": "server error"})); @@ -409,9 +402,9 @@ function startServer(result) { }); // Register name registration handler - app.post("/name/:name", function(req, http_res) { + app.post("/name/:name", (req, http_res) => { try { - var addr = formatAddress(req.body.addr); + const addr = formatAddress(req.body.addr); if (!addr) { console.log("Error parsing input address"); http_res.status(400).end(JSON.stringify({"success": false})); @@ -460,38 +453,41 @@ function startServer(result) { } } console.log("Got reg request (" + req.params.name + " -> " + addr + ") from " + req.body.owner); - reg.owner(req.params.name, function(err, owner) { + reg.methods.owner(req.params.name).call((err, owner) => { if (owner == 0) { - reg.name(addr, function(err, res) { + reg.methods.name(addr, (err, res) => { try { if (err) console.log("Error checking name: " + err); - var name = parseString(res); + let name = parseString(res); if (name) { console.log("Address " + addr + " already registered with name: " + name); http_res.status(403).end(JSON.stringify({"success": false, "name": name, "addr": addr})); } else { console.log("Remaing gaz: " + getRemainingGaz()); - unlockAccount(); + //unlockAccount(); reg.reserveFor.sendTransaction(formatName(req.params.name), req.body.owner, addr, publickey, signature, { from: coinbase, gas: 3000000 - }, function(terr, reg_c) { + }, (terr, reg_c) => { if (terr) { console.log("Transaction error " + JSON.stringify(terr)); http_res.end(JSON.stringify(terr)); } else { //Add the registration into the cache. - cache[req.params.name] = { + const newReg = { addr, + name: req.params.name, publickey, signature }; + cache[req.params.name] = newReg; + addrCache[addr] = newReg; //Now we continue with the sending of the transactions. console.log("Transaction sent " + reg_c); // Send answer as soon as the transaction is queued http_res.end(JSON.stringify({"success": true})); - web3.eth.awaitConsensus(reg_c, function(error) { + web3.eth.awaitConsensus(reg_c, (error) => { if (error) { console.log(error); return; @@ -508,7 +504,7 @@ function startServer(result) { }); } else { if (owner == req.body.owner) { - reg.addr(req.params.name, function(err, reg_addr) { + reg.methods.addr(req.params.name).call((err, reg_addr) => { if (reg_addr == addr) { http_res.end(JSON.stringify({"success": true})); } else { @@ -526,7 +522,7 @@ function startServer(result) { } }); try { - http.createServer(app).listen(80); + http.createServer(app).listen(8080); } catch (err) { console.log("Error starting HTTP server: " + err); } @@ -545,7 +541,13 @@ function startServer(result) { } if(argv['_'] != 0){ - loadNames(argv['_']); + loadNames(argv['_']); } -unlockAccount(); -loadContract(startServer); + +web3.eth.getCoinbase(async (error, result) => { + console.log('Coinbase: ' + result); + coinbase = result; + balance = await web3.eth.getBalance(coinbase); + console.log('Balance: ' + balance.toString(10)); + loadContract(startServer); +}); diff --git a/read_names.js b/read_names.js old mode 100644 new mode 100755 index 34ad5c0..32dca5f --- a/read_names.js +++ b/read_names.js @@ -1,50 +1,70 @@ #!/usr/bin/env nodejs -var fs = require('fs'); -var Web3 = require('web3'); - -var web3 = new Web3(); -web3.SolidityCoder = require('web3/lib/solidity/coder'); +/* + * Copyright (c) 2016-2020 Savoir-faire Linux Inc. + * + * Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +'use strict'; +const fs = require('fs'); +const Web3 = require('web3'); +const web3 = new Web3(); web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545')); -var REG_ADDR_FILE = "contractAddress.txt"; -var REG_ADDR = "0xe53cb2ace8707526a5050bec7bcf979c57f8b44f"; -var REG_ABI_reserveFor = ['bytes32', 'address', 'address', 'string', 'string']; -var NAME_LIST = []; +const REG_ADDR_FILE = "contractAddress.txt"; +const REG_ABI_reserveFor = ['bytes32', 'address', 'address', 'string', 'string']; +let REG_ADDR = "0xe53cb2ace8707526a5050bec7bcf979c57f8b44f"; + function readContractAddress() { fs.readFile(REG_ADDR_FILE, function(err, content) { if (err) { console.log("Can't read contract address: " + err); } else { - REG_ADDR = String(content); + REG_ADDR = String(content).trim().toLowerCase(); } - getAllNames(); + web3.eth.getBlockNumber((err, content) => getAllNames(content)); }); } -function getAllNames() { - var totalBlocks = web3.eth.blockNumber; - var nextBlock = 0; - var rem = totalBlocks; - var cb = function(error, block) { +function getAllNames(totalBlocks) { + let nextBlock = 0; + let rem = totalBlocks; + fs.unlinkSync('names.json'); + const outFd = fs.openSync('names.json', 'a'); + fs.write(outFd, '[\n', e => { if (e) console.log(e) }); + + const cb = function(error, block) { rem--; if (error) { console.log("Can't get block: " + error); } else { - var transactionNum = block.transactions.length; - for (var t=0; t<transactionNum; t++) { + const transactionNum = block.transactions.length; + for (let t=0; t<transactionNum; t++) { try { - var tr = block.transactions[t]; - if (tr.to == REG_ADDR) { - const p = web3.SolidityCoder.decodeParams(REG_ABI_reserveFor, tr.input.substr(10)); - const n = web3.toUtf8(p[0]); + const tr = block.transactions[t]; + if (tr.to && tr.to.toLowerCase() == REG_ADDR) { + const p = web3.eth.abi.decodeParameters(REG_ABI_reserveFor, tr.input.substr(10)); + const n = web3.utils.hexToUtf8(p[0]); console.log("Entry: " + n + " -> " + p[1] + " " + p[2]); const newObj = {"name": n,"addr":p[2], "owner":p[1]}; if (p[3]) newObj["publickey"] = p[3]; if (p[4]) newObj["signature"] = p[4]; - NAME_LIST.push(newObj); + fs.write(outFd, JSON.stringify(newObj) + ',\n', e => { if (e) console.log(e) }); } else { console.log("Wrong contract: " + tr.to + " expected " + REG_ADDR); } @@ -57,11 +77,14 @@ function getAllNames() { web3.eth.getBlock(nextBlock++, true, cb); if (rem == 0) { console.log("Found " + NAME_LIST.length + " name mappings"); - fs.writeFile("names.json", JSON.stringify(NAME_LIST)); + fs.write(outFd, ']', e => { if (e) console.log(e) }); + fs.close(outFd, () => {}); } else if (!error && block && block.transactions.length) { console.log("Listing names: " + Math.round(100-100*rem/totalBlocks) + "%, " + rem + " remaining... "); } }; + console.log("Starting... total blocks: " + totalBlocks); + // 256 concurrent requests for (; nextBlock < totalBlocks && nextBlock < 256; nextBlock++) web3.eth.getBlock(nextBlock, true, cb); diff --git a/write_names.js b/write_names.js old mode 100644 new mode 100755 index c34b3dd..9ac852c --- a/write_names.js +++ b/write_names.js @@ -1,3 +1,23 @@ +#!/usr/bin/env nodejs +/* + * Copyright (c) 2016-2020 Savoir-faire Linux Inc. + * + * Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +'use strict'; var async = require("async"); var BigNumber = require('bignumber.js'); var fs = require('fs'); -- GitLab