diff --git a/applications/launchpad/gui-vue/.gitignore b/applications/launchpad/gui-vue/.gitignore index 403adbc1e5..140d0b7681 100644 --- a/applications/launchpad/gui-vue/.gitignore +++ b/applications/launchpad/gui-vue/.gitignore @@ -1,6 +1,7 @@ .DS_Store node_modules -/dist +dist/* +!dist/.gitkeep # local env files diff --git a/applications/launchpad/gui-vue/dist/.gitkeep b/applications/launchpad/gui-vue/dist/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/applications/tari_collectibles/web-app/.eslintrc.js b/applications/tari_collectibles/web-app/.eslintrc.js index 591394c75f..0bc28abcff 100644 --- a/applications/tari_collectibles/web-app/.eslintrc.js +++ b/applications/tari_collectibles/web-app/.eslintrc.js @@ -4,6 +4,7 @@ module.exports = { es2021: true, }, extends: ["plugin:react/recommended"], + parser: "babel-eslint", parserOptions: { ecmaFeatures: { jsx: true, diff --git a/applications/tari_collectibles/web-app/package-lock.json b/applications/tari_collectibles/web-app/package-lock.json index 0e41073293..c5ff9373ed 100644 --- a/applications/tari_collectibles/web-app/package-lock.json +++ b/applications/tari_collectibles/web-app/package-lock.json @@ -26,8 +26,8 @@ "web-vitals": "^1.1.2" }, "devDependencies": { + "babel-eslint": "^10.1.0", "eslint": "^7.32.0", - "eslint-config-airbnb": "^19.0.4", "eslint-plugin-import": "^2.25.4", "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-react": "^7.28.0", @@ -8059,55 +8059,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-config-airbnb": { - "version": "19.0.4", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz", - "integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==", - "dev": true, - "dependencies": { - "eslint-config-airbnb-base": "^15.0.0", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5" - }, - "engines": { - "node": "^10.12.0 || ^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.3", - "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.28.0", - "eslint-plugin-react-hooks": "^4.3.0" - } - }, - "node_modules/eslint-config-airbnb-base": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", - "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", - "dev": true, - "dependencies": { - "confusing-browser-globals": "^1.0.10", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5", - "semver": "^6.3.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "peerDependencies": { - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.2" - } - }, - "node_modules/eslint-config-airbnb-base/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/eslint-config-react-app": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-6.0.0.tgz", @@ -28124,37 +28075,6 @@ } } }, - "eslint-config-airbnb": { - "version": "19.0.4", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz", - "integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==", - "dev": true, - "requires": { - "eslint-config-airbnb-base": "^15.0.0", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5" - } - }, - "eslint-config-airbnb-base": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", - "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", - "dev": true, - "requires": { - "confusing-browser-globals": "^1.0.10", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, "eslint-config-react-app": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-6.0.0.tgz", diff --git a/applications/tari_collectibles/web-app/package.json b/applications/tari_collectibles/web-app/package.json index 421f7a989f..378a9aeb79 100644 --- a/applications/tari_collectibles/web-app/package.json +++ b/applications/tari_collectibles/web-app/package.json @@ -46,6 +46,7 @@ ] }, "devDependencies": { + "babel-eslint": "^10.1.0", "eslint": "^7.32.0", "eslint-plugin-import": "^2.25.4", "eslint-plugin-jsx-a11y": "^6.5.1", diff --git a/applications/tari_collectibles/web-app/src/AccountDashboard.js b/applications/tari_collectibles/web-app/src/AccountDashboard.js index 3742ea6bb3..0b79e1d1b1 100644 --- a/applications/tari_collectibles/web-app/src/AccountDashboard.js +++ b/applications/tari_collectibles/web-app/src/AccountDashboard.js @@ -129,7 +129,7 @@ class AccountDashboard extends React.Component { } } - async refreshBalance() { + refreshBalance = async () => { this.setState({ error: null }); let balance = await binding.command_asset_wallets_get_balance( this.state.assetPublicKey @@ -139,7 +139,7 @@ class AccountDashboard extends React.Component { return balance; }; - async refresh721() { + refresh721 = async () => { let tip721Data = {}; let tokens = await binding.command_tip004_list_tokens( this.state.assetPublicKey @@ -157,7 +157,7 @@ class AccountDashboard extends React.Component { return tip721Data; }; - async onGenerateReceiveAddress() { + onGenerateReceiveAddress = async () => { try { this.setState({ error: null }); let receiveAddress = await binding.command_asset_wallets_create_address( @@ -171,15 +171,14 @@ class AccountDashboard extends React.Component { } }; - async onSendToChanged(e) { + onSendToChanged = async (e) => { this.setState({ sendToAddress: e.target.value }); }; - async onSendToAmountChanged(e) { + onSendToAmountChanged = async (e) => { this.setState({ sendToAmount: parseInt(e.target.value) }); }; - - async onSend(){ + onSend = async () => { try { this.setState({ error: "" }); let result = await binding.command_asset_wallets_send_to( @@ -198,12 +197,12 @@ class AccountDashboard extends React.Component { this.setState({ error: err.message }); } }; - async openTip721SendDraft(tokenId) { + openTip721SendDraft = async (tokenId) => { this.setState({ tip721SendDraftId: tokenId, }); }; - async on721Send(fromAddressId, tokenId) { + on721Send = async (fromAddressId, tokenId) => { try { this.setState({ error: "" }); let result = await binding.command_tip721_transfer_from( @@ -222,7 +221,7 @@ class AccountDashboard extends React.Component { } }; - async onSaveToFavorites(){ + onSaveToFavorites = async () => { try { await binding.command_asset_wallets_create(this.state.assetPublicKey); await this.reload(); diff --git a/applications/tari_collectibles/web-app/src/Create.js b/applications/tari_collectibles/web-app/src/Create.js index ed9f7eeac9..9f3d8845d9 100644 --- a/applications/tari_collectibles/web-app/src/Create.js +++ b/applications/tari_collectibles/web-app/src/Create.js @@ -77,6 +77,7 @@ class Create extends React.Component { this.cleanup = null; } + componentDidMount() { this.cleanup = appWindow.listen("tauri://file-drop", (obj) => this.dropFile(obj) @@ -102,7 +103,7 @@ class Create extends React.Component { } } - async save() { + save = async () => { const isValid = await this.validate(); if (!isValid) { return; @@ -182,17 +183,17 @@ class Create extends React.Component { this.setState({ isSaving: false }); }; - async onNameChanged(e){ + onNameChanged = (e) => { this.setState({ name: e.target.value }); }; - onTipCheckboxChanged(e, tip){ + onTipCheckboxChanged = (e, tip) => { let obj = {}; obj[tip] = e.target.checked; this.setState(obj); }; - onTip002DataChanged(field, e){ + onTip002DataChanged = (field, e) => { let tip002Data = {}; tip002Data[field] = e.target.value; tip002Data = { ...this.state.tip002Data, ...tip002Data }; @@ -203,19 +204,19 @@ class Create extends React.Component { // this.setState({ numberInitialTokens: e.target.value }); // }; - onDescriptionChanged(e){ + onDescriptionChanged = (e) => { this.setState({ description: e.target.value, }); }; - onNewCommitteePubKeyChanged(e){ + onNewCommitteePubKeyChanged = (e) => { this.setState({ newCommitteePubKey: e.target.value, }); }; - onAddCommitteeMember(){ + onAddCommitteeMember = () => { let committee = [...this.state.tip003Data.committee]; committee.push(this.state.newCommitteePubKey); let tip003Data = { ...this.state.tip003Data, ...{ committee: committee } }; @@ -227,7 +228,7 @@ class Create extends React.Component { }); }; - onDeleteCommitteeMember(index){ + onDeleteCommitteeMember = (index) => { let committee = this.state.tip003Data.committee.filter(function ( _, i, @@ -253,13 +254,13 @@ class Create extends React.Component { return saveErrors.length === 0; } - onImageChanged(e){ + onImageChanged = (e) => { this.setState({ image: e.target.value, }); }; - async selectFile (){ + selectFile = async () => { const filePath = await dialog.open({ filters: [ { @@ -278,7 +279,7 @@ class Create extends React.Component { } }; - async addFileToIPFS(filePath) { + addFileToIPFS = async (filePath) => { const parts = filePath.split("/"); const name = parts[parts.length - 1]; // unfortunately the ipfs http /add api doesn't play nicely with the tauri http client diff --git a/applications/tari_collectibles/web-app/src/NewAccount.js b/applications/tari_collectibles/web-app/src/NewAccount.js index 49e37ceb6e..e08a6da086 100644 --- a/applications/tari_collectibles/web-app/src/NewAccount.js +++ b/applications/tari_collectibles/web-app/src/NewAccount.js @@ -44,11 +44,11 @@ class NewAccount extends React.Component { }; } - onAssetPublicKeyChanged(e){ + onAssetPublicKeyChanged = (e) => { this.setState({ assetPublicKey: e.target.value }); }; - async onSave(e){ + onSave = async (e) => { e.preventDefault(); console.log(this.state.assetPublicKey); this.setState({ isSaving: true, error: null }); diff --git a/applications/tari_explorer/.prettierrc b/applications/tari_explorer/.prettierrc index 8406771c0a..168d9d2a0c 100644 --- a/applications/tari_explorer/.prettierrc +++ b/applications/tari_explorer/.prettierrc @@ -1,4 +1,3 @@ { - "endOfLine": "auto", - "semi": false + "endOfLine": "auto" } diff --git a/applications/tari_explorer/app.js b/applications/tari_explorer/app.js index 94fa4883b2..6873db5174 100644 --- a/applications/tari_explorer/app.js +++ b/applications/tari_explorer/app.js @@ -1,35 +1,34 @@ -const createError = require('http-errors') -const express = require('express') -const path = require('path') -const cookieParser = require('cookie-parser') -const logger = require('morgan') -const asciichart = require('asciichart') - - -var indexRouter = require("./routes/index") -var blocksRouter = require("./routes/blocks") -var mempoolRouter = require("./routes/mempool") -var searchRouter = require("./routes/search") - -var assetsRouter = require('./routes/assets'); -var validatorRouter = require('./routes/validator'); - -var hbs = require("hbs") +const createError = require("http-errors"); +const express = require("express"); +const path = require("path"); +const cookieParser = require("cookie-parser"); +const logger = require("morgan"); +const asciichart = require("asciichart"); + +var indexRouter = require("./routes/index"); +var blocksRouter = require("./routes/blocks"); +var mempoolRouter = require("./routes/mempool"); +var searchRouter = require("./routes/search"); + +var assetsRouter = require("./routes/assets"); +var validatorRouter = require("./routes/validator"); + +var hbs = require("hbs"); hbs.registerHelper("hex", function (buffer) { - return buffer ? Buffer.from(buffer).toString("hex") : "" -}) + return buffer ? Buffer.from(buffer).toString("hex") : ""; +}); hbs.registerHelper("json", function (obj) { - return Buffer.from(JSON.stringify(obj)).toString("base64") -}) + return Buffer.from(JSON.stringify(obj)).toString("base64"); +}); hbs.registerHelper("timestamp", function (timestamp) { - var dateObj = new Date(timestamp.seconds * 1000) - const day = dateObj.getUTCDate() - const month = dateObj.getUTCMonth() + 1 - const year = dateObj.getUTCFullYear() - const hours = dateObj.getUTCHours() - const minutes = dateObj.getUTCMinutes() - const seconds = dateObj.getSeconds() + var dateObj = new Date(timestamp.seconds * 1000); + const day = dateObj.getUTCDate(); + const month = dateObj.getUTCMonth() + 1; + const year = dateObj.getUTCFullYear(); + const hours = dateObj.getUTCHours(); + const minutes = dateObj.getUTCMinutes(); + const seconds = dateObj.getSeconds(); return ( year.toString() + @@ -43,68 +42,68 @@ hbs.registerHelper("timestamp", function (timestamp) { minutes.toString().padStart(2, "0") + ":" + seconds.toString().padStart(2, "0") - ) -}) + ); +}); hbs.registerHelper("percentbar", function (a, b) { - var percent = (a / (a + b)) * 100 - var barWidth = percent / 10 - var bar = "**********".slice(0, barWidth) - var space = "...........".slice(0, 10 - barWidth) - return bar + space + " " + parseInt(percent) + "% " -}) + var percent = (a / (a + b)) * 100; + var barWidth = percent / 10; + var bar = "**********".slice(0, barWidth); + var space = "...........".slice(0, 10 - barWidth); + return bar + space + " " + parseInt(percent) + "% "; +}); hbs.registerHelper("chart", function (data, height) { if (data.length > 0) { return asciichart.plot(data, { height: height, - }) + }); } else { - return "**No data**" + return "**No data**"; } -}) +}); -hbs.registerHelper('json', function(obj) { +hbs.registerHelper("json", function (obj) { return JSON.stringify(obj); -}) +}); -var app = express() +var app = express(); // view engine setup -app.set("views", path.join(__dirname, "views")) -app.set("view engine", "hbs") +app.set("views", path.join(__dirname, "views")); +app.set("view engine", "hbs"); -app.use(logger("dev")) -app.use(express.json()) +app.use(logger("dev")); +app.use(express.json()); app.use( express.urlencoded({ extended: false, }) -) -app.use(cookieParser()) -app.use(express.static(path.join(__dirname, "public"))) +); +app.use(cookieParser()); +app.use(express.static(path.join(__dirname, "public"))); -app.use('/', indexRouter); -app.use('/blocks', blocksRouter); -app.use('/assets', assetsRouter); -app.use('/validator', validatorRouter); -app.use("/mempool", mempoolRouter) -app.use("/search", searchRouter) +app.use("/", indexRouter); +app.use("/blocks", blocksRouter); +app.use("/assets", assetsRouter); +app.use("/validator", validatorRouter); +app.use("/mempool", mempoolRouter); +app.use("/search", searchRouter); // catch 404 and forward to error handler app.use(function (req, res, next) { - next(createError(404)) -}) + next(createError(404)); +}); // error handler app.use(function (err, req, res) { // set locals, only providing error in development - res.locals.message = err.message - res.locals.error = req.app.get("env") === "development" ? err : {} + res.locals.message = err.message; + res.locals.error = req.app.get("env") === "development" ? err : {}; // render the error page - res.status(err.status || 500) - res.render("error") -}) + res.status(err.status || 500); + res.render("error"); +}); -module.exports = app +module.exports = app; diff --git a/applications/tari_explorer/baseNodeClient.js b/applications/tari_explorer/baseNodeClient.js index 73267e8da5..11852781b8 100644 --- a/applications/tari_explorer/baseNodeClient.js +++ b/applications/tari_explorer/baseNodeClient.js @@ -1,9 +1,9 @@ -var { Client } = require("base-node-grpc-client") +var { Client } = require("base-node-grpc-client"); function createClient() { - return Client.connect("localhost:18142") + return Client.connect("localhost:18142"); } module.exports = { createClient, -} +}; diff --git a/applications/tari_explorer/bin/www b/applications/tari_explorer/bin/www index cc31eafa52..255b127045 100755 --- a/applications/tari_explorer/bin/www +++ b/applications/tari_explorer/bin/www @@ -4,49 +4,49 @@ * Module dependencies. */ -var app = require('../app'); -var debug = require('debug')('tari-explorer:server'); -var http = require('http'); +var app = require("../app") +var debug = require("debug")("tari-explorer:server") +var http = require("http") /** * Get port from environment and store in Express. */ -var port = normalizePort(process.env.PORT || '4000'); -app.set('port', port); +var port = normalizePort(process.env.PORT || "4000") +app.set("port", port) /** * Create HTTP server. */ -var server = http.createServer(app); +var server = http.createServer(app) /** * Listen on provided port, on all network interfaces. */ -server.listen(port); -server.on('error', onError); -server.on('listening', onListening); +server.listen(port) +server.on("error", onError) +server.on("listening", onListening) /** * Normalize a port into a number, string, or false. */ function normalizePort(val) { - var port = parseInt(val, 10); + var port = parseInt(val, 10) if (isNaN(port)) { // named pipe - return val; + return val } if (port >= 0) { // port number - return port; + return port } - return false; + return false } /** @@ -54,26 +54,24 @@ function normalizePort(val) { */ function onError(error) { - if (error.syscall !== 'listen') { - throw error; + if (error.syscall !== "listen") { + throw error } - var bind = typeof port === 'string' - ? 'Pipe ' + port - : 'Port ' + port; + var bind = typeof port === "string" ? "Pipe " + port : "Port " + port // handle specific listen errors with friendly messages switch (error.code) { - case 'EACCES': - console.error(bind + ' requires elevated privileges'); - process.exit(1); - break; - case 'EADDRINUSE': - console.error(bind + ' is already in use'); - process.exit(1); - break; + case "EACCES": + console.error(bind + " requires elevated privileges") + process.exit(1) + break + case "EADDRINUSE": + console.error(bind + " is already in use") + process.exit(1) + break default: - throw error; + throw error } } @@ -82,9 +80,9 @@ function onError(error) { */ function onListening() { - var addr = server.address(); - var bind = typeof addr === 'string' - ? 'pipe ' + addr - : 'port ' + addr.port; - debug('Listening on ' + bind); + var addr = server.address() + console.log("Address: ", addr) + var bind = typeof addr === "string" ? "pipe " + addr : "port " + addr.port + debug("Listening on " + bind) + console.log("Listening on " + bind) } diff --git a/applications/tari_explorer/routes/assets.js b/applications/tari_explorer/routes/assets.js index fb91877ceb..ae6480ad95 100644 --- a/applications/tari_explorer/routes/assets.js +++ b/applications/tari_explorer/routes/assets.js @@ -20,40 +20,40 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -var { createClient: createBaseNodeClient } = require('../baseNodeClient') +var { createClient: createBaseNodeClient } = require("../baseNodeClient"); -var express = require('express') -var router = express.Router() +var express = require("express"); +var router = express.Router(); /* GET home page. */ -router.get('/:asset_public_key', async function (req, res, next) { - let baseNodeClient = createBaseNodeClient() +router.get("/:asset_public_key", async function (req, res) { + let baseNodeClient = createBaseNodeClient(); // let validatorNodeClient = createValidatorNodeClient() - let asset_public_key = req.params.asset_public_key + let asset_public_key = req.params.asset_public_key; try { - let tokens = await baseNodeClient.getTokens({ asset_public_key: Buffer.from(asset_public_key, "hex") }) - console.log(tokens) + let tokens = await baseNodeClient.getTokens({ + asset_public_key: Buffer.from(asset_public_key, "hex"), + }); + console.log(tokens); if (!tokens || tokens.length === 0) { res.status(404); - res.render('404', { message: `No tokens for asset found`}); + res.render("404", { message: `No tokens for asset found` }); return; } // let headers = validatorNodeClient.listHeaders({ from_height: 0, num_headers: 101 }) - res.render('assets', { + res.render("assets", { title: `Asset with pub key: ${asset_public_key}`, tokens: tokens, // headers - }) - - + }); } catch (error) { - res.status(500) - res.render('error', { error: error }) + res.status(500); + res.render("error", { error: error }); } -}) +}); -module.exports = router +module.exports = router; diff --git a/applications/tari_explorer/routes/blocks.js b/applications/tari_explorer/routes/blocks.js index c8d6b3b205..9bc9b3cf1b 100644 --- a/applications/tari_explorer/routes/blocks.js +++ b/applications/tari_explorer/routes/blocks.js @@ -20,38 +20,50 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -var { createClient } = require('../baseNodeClient') +var { createClient } = require("../baseNodeClient"); -var express = require("express") -var router = express.Router() +var express = require("express"); +var router = express.Router(); router.get("/:height", async function (req, res) { - let client = createClient() - let height = req.params.height - try { - let block = await client.getBlocks({ heights: [height] }) + let client = createClient(); + let height = parseInt(req.params.height); + let block = await client.getBlocks({ heights: [height] }); if (!block || block.length === 0) { res.status(404); - res.render('404', { message: `Block at height ${height} not found`}); + res.render("404", { message: `Block at height ${height} not found` }); return; } - console.log(block) - console.log(block[0].block.body.outputs[0]) - res.render('blocks', { - title: `Block at height:${block[0].block.header.height}`, - height: height, - prevHeight: parseInt(height) - 1, - nextHeight: parseInt(height) + 1, - block: block[0].block, - pows: { '0': 'Monero', '2': 'SHA' } - }) + let tipInfo = await client.getTipInfo({}); + let tipHeight = parseInt(tipInfo.metadata.height_of_longest_chain); + + let prevHeight = height - 1; + let prevLink = `/blocks/${prevHeight}`; + if (height === 0) prevLink = null; + + let nextHeight = height + 1; + let nextLink = `/blocks/${nextHeight}`; + if (height === tipHeight) nextLink = null; + + // console.log(block); + res.render("blocks", { + title: `Block at height: ${block[0].block.header.height}`, + header: block[0].block.header, + height, + prevLink, + prevHeight, + nextLink, + nextHeight, + block: block[0].block, + pows: { 0: "Monero", 1: "SHA-3" }, + }); } catch (error) { - res.status(500) - res.render('error', { error: error }) + res.status(500); + res.render("error", { error: error }); } -}) +}); -module.exports = router +module.exports = router; diff --git a/applications/tari_explorer/routes/index.js b/applications/tari_explorer/routes/index.js index fe9cdd9273..06fb08d681 100644 --- a/applications/tari_explorer/routes/index.js +++ b/applications/tari_explorer/routes/index.js @@ -1,39 +1,39 @@ -var { createClient } = require("../baseNodeClient") +var { createClient } = require("../baseNodeClient"); -var express = require("express") -var router = express.Router() +var express = require("express"); +var router = express.Router(); /* GET home page. */ router.get("/", async function (req, res) { try { - let client = createClient() - let from = parseInt(req.query.from || 0) - let limit = parseInt(req.query.limit || "20") + let client = createClient(); + let from = parseInt(req.query.from || 0); + let limit = parseInt(req.query.limit || "20"); - let tipInfo = await client.getTipInfo({}) + let tipInfo = await client.getTipInfo({}); // Algo split let last100Headers = await client.listHeaders({ from_height: 0, num_headers: 101, - }) - let monero = [0, 0, 0, 0] - let sha = [0, 0, 0, 0] + }); + let monero = [0, 0, 0, 0]; + let sha = [0, 0, 0, 0]; // console.log(last100Headers) for (let i = 0; i < last100Headers.length - 1; i++) { - let arr = last100Headers[i].pow.pow_algo === "0" ? monero : sha + let arr = last100Headers[i].pow.pow_algo === "0" ? monero : sha; if (i < 10) { - arr[0] += 1 + arr[0] += 1; } if (i < 20) { - arr[1] += 1 + arr[1] += 1; } if (i < 50) { - arr[2] += 1 + arr[2] += 1; } - arr[3] += 1 + arr[3] += 1; } const algoSplit = { monero10: monero[0], @@ -44,95 +44,96 @@ router.get("/", async function (req, res) { sha20: sha[1], sha50: sha[2], sha100: sha[3], - } + }; // console.log(algoSplit) // Get one more header than requested so we can work out the difference in MMR_size let headers = await client.listHeaders({ from_height: from, num_headers: limit + 1, - }) + }); for (var i = headers.length - 2; i >= 0; i--) { headers[i].kernels = - headers[i].kernel_mmr_size - headers[i + 1].kernel_mmr_size + headers[i].kernel_mmr_size - headers[i + 1].kernel_mmr_size; headers[i].outputs = - headers[i].output_mmr_size - headers[i + 1].output_mmr_size + headers[i].output_mmr_size - headers[i + 1].output_mmr_size; } - let lastHeader = headers[headers.length - 1] + let lastHeader = headers[headers.length - 1]; if (lastHeader.height === "0") { // If the block is the genesis block, then the MMR sizes are the values to use - lastHeader.kernels = lastHeader.kernel_mmr_size - lastHeader.outputs = lastHeader.output_mmr_size + lastHeader.kernels = lastHeader.kernel_mmr_size; + lastHeader.outputs = lastHeader.output_mmr_size; } else { // Otherwise remove the last one, as we don't want to show it - headers.splice(headers.length - 1, 1) + headers.splice(headers.length - 1, 1); } // console.log(headers); - let firstHeight = parseInt(headers[0].height || "0") + let firstHeight = parseInt(headers[0].height || "0"); // -- mempool - let mempool = await client.getMempoolTransactions({}) + let mempool = await client.getMempoolTransactions({}); - console.log(mempool) + console.log(mempool); for (let i = 0; i < mempool.length; i++) { - let sum = 0 + let sum = 0; for (let j = 0; j < mempool[i].transaction.body.kernels.length; j++) { - sum += parseInt(mempool[i].transaction.body.kernels[j].fee) + sum += parseInt(mempool[i].transaction.body.kernels[j].fee); } - mempool[i].transaction.body.total_fees = sum + mempool[i].transaction.body.total_fees = sum; } - res.render("index", { + const result = { title: "Blocks", - tipInfo: tipInfo, - mempool: mempool, - headers: headers, - pows: { 0: "Monero", 2: "SHA" }, + tipInfo, + mempool, + headers, + pows: { 0: "Monero", 1: "SHA-3" }, nextPage: firstHeight - limit, prevPage: firstHeight + limit, - limit: limit, - from: from, - algoSplit: algoSplit, + limit, + from, + algoSplit, blockTimes: getBlockTimes(last100Headers), moneroTimes: getBlockTimes(last100Headers, "0"), shaTimes: getBlockTimes(last100Headers, "1"), - }) + }; + res.render("index", result); } catch (error) { - res.status(500) - res.render("error", { error: error }) + res.status(500); + res.render("error", { error: error }); } -}) +}); function getBlockTimes(last100Headers, algo) { - let blocktimes = [] - let i = 0 + let blocktimes = []; + let i = 0; if (algo === "0" || algo === "1") { while ( i < last100Headers.length && last100Headers[i].pow.pow_algo !== algo ) { - i++ - blocktimes.push(0) + i++; + blocktimes.push(0); } } if (i >= last100Headers.length) { // This happens if there are no blocks for a specific algorithm in last100headers - return blocktimes + return blocktimes; } - let lastBlockTime = parseInt(last100Headers[i].timestamp.seconds) - i++ + let lastBlockTime = parseInt(last100Headers[i].timestamp.seconds); + i++; while (i < last100Headers.length && blocktimes.length < 60) { if (!algo || last100Headers[i].pow.pow_algo === algo) { blocktimes.push( (lastBlockTime - parseInt(last100Headers[i].timestamp.seconds)) / 60 - ) - lastBlockTime = parseInt(last100Headers[i].timestamp.seconds) + ); + lastBlockTime = parseInt(last100Headers[i].timestamp.seconds); } else { - blocktimes.push(0) + blocktimes.push(0); } - i++ + i++; } - return blocktimes + return blocktimes; } -module.exports = router +module.exports = router; diff --git a/applications/tari_explorer/routes/mempool.js b/applications/tari_explorer/routes/mempool.js index 1d8408b0fa..d24441fc9e 100644 --- a/applications/tari_explorer/routes/mempool.js +++ b/applications/tari_explorer/routes/mempool.js @@ -1,15 +1,15 @@ -var express = require("express") -const { createClient } = require("../baseNodeClient") -var router = express.Router() +var express = require("express"); +const { createClient } = require("../baseNodeClient"); +var router = express.Router(); /* GET mempool page. */ router.get("/:excessSigs", async function (req, res) { try { - let client = createClient() - let txId = req.params.excessSigs.split("+") - console.log(txId) - let mempool = await client.getMempoolTransactions({}) - let tx = null + let client = createClient(); + let txId = req.params.excessSigs.split("+"); + console.log(txId); + let mempool = await client.getMempoolTransactions({}); + let tx = null; for (let i = 0; i < mempool.length; i++) { for (let j = 0; j < mempool[i].transaction.body.kernels.length; j++) { for (let k = 0; k < txId.length; k++) { @@ -19,30 +19,30 @@ router.get("/:excessSigs", async function (req, res) { mempool[i].transaction.body.kernels[j].excess_sig.signature ).toString("hex") ) { - tx = mempool[i].transaction - break + tx = mempool[i].transaction; + break; } } if (tx) { - break + break; } } } if (!tx) { - res.status(404) - res.render("error", { error: "Tx not found" }) - return + res.status(404); + res.render("error", { error: "Tx not found" }); + return; } - console.log(tx) - console.log("===============") + console.log(tx); + console.log("==============="); res.render("Mempool", { tx, - }) + }); } catch (error) { - res.status(500) - res.render("error", { error: error }) + res.status(500); + res.render("error", { error: error }); } -}) +}); -module.exports = router +module.exports = router; diff --git a/applications/tari_explorer/routes/search.js b/applications/tari_explorer/routes/search.js index f59c7caaa9..120526793d 100644 --- a/applications/tari_explorer/routes/search.js +++ b/applications/tari_explorer/routes/search.js @@ -20,37 +20,37 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -var { createClient } = require("../baseNodeClient") +var { createClient } = require("../baseNodeClient"); -var express = require("express") -var router = express.Router() +var express = require("express"); +var router = express.Router(); router.get("/", async function (req, res) { - let client = createClient() + let client = createClient(); let commitments = ( req.query.comm || req.query.commitment || req.query.c || "" - ).split(",") + ).split(","); if (commitments.length === 0) { - res.status(404) - return + res.status(404); + return; } - let hexCommitments = [] + let hexCommitments = []; for (let i = 0; i < commitments.length; i++) { - hexCommitments.push(Buffer.from(commitments[i], "hex")) + hexCommitments.push(Buffer.from(commitments[i], "hex")); } - console.log(hexCommitments) + console.log(hexCommitments); let result = await client.searchUtxos({ hexCommitments, - }) + }); - console.log(result) + console.log(result); res.render("search", { items: result, - }) -}) + }); +}); -module.exports = router +module.exports = router; diff --git a/applications/tari_explorer/routes/validator.js b/applications/tari_explorer/routes/validator.js index 9bd11d2518..e5a0643ecb 100644 --- a/applications/tari_explorer/routes/validator.js +++ b/applications/tari_explorer/routes/validator.js @@ -19,26 +19,27 @@ // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -var {createClient: createValidatorNodeClient} = require('../validatorNodeClient') +var { + createClient: createValidatorNodeClient, +} = require("../validatorNodeClient"); -var express = require('express') -var router = express.Router() +var express = require("express"); +var router = express.Router(); router.get("/", async function (req, res) { - try { - let client = createValidatorNodeClient(); - let metadata = await client.getMetadata(); - console.log(metadata); + try { + let client = createValidatorNodeClient(); + let metadata = await client.getMetadata(); + console.log(metadata); - res.render('validator', { - title: `Validator node`, - sidechains: metadata.sidechains - }) - - } catch (error) { - res.status(500) - res.render('error', {error: error}) - } + res.render("validator", { + title: `Validator node`, + sidechains: metadata.sidechains, + }); + } catch (error) { + res.status(500); + res.render("error", { error: error }); + } }); -module.exports = router +module.exports = router; diff --git a/applications/tari_explorer/validatorNodeClient.js b/applications/tari_explorer/validatorNodeClient.js index 2a83954d29..f4cb4d3572 100644 --- a/applications/tari_explorer/validatorNodeClient.js +++ b/applications/tari_explorer/validatorNodeClient.js @@ -1,10 +1,9 @@ -var {Client} = require("validator-node-grpc-client"); +var { Client } = require("validator-node-grpc-client"); function createClient() { - return Client.connect("localhost:18144"); + return Client.connect("localhost:18144"); } module.exports = { - createClient -} - + createClient, +}; diff --git a/applications/tari_explorer/views/assets.hbs b/applications/tari_explorer/views/assets.hbs index 46e2073af3..f63fe806ef 100644 --- a/applications/tari_explorer/views/assets.hbs +++ b/applications/tari_explorer/views/assets.hbs @@ -1,7 +1,7 @@

{{this.title}}

Tokens

- +
diff --git a/applications/tari_explorer/views/blocks.hbs b/applications/tari_explorer/views/blocks.hbs index 3fa2cc8a60..f1fe50a674 100644 --- a/applications/tari_explorer/views/blocks.hbs +++ b/applications/tari_explorer/views/blocks.hbs @@ -1,12 +1,81 @@ Back to all blocks

{{title}}

- < Block {{prevHeight}} - Block {{nextHeight}} > + {{#if prevLink}} + < Block {{prevHeight}} + {{/if}} + {{#if nextLink}} + Block {{nextHeight}} > + {{/if}}

+
+

Header

+
Unique ID
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Hash{{hex this.header.hash}}
Proof of Work{{lookup this.pows this.header.pow.pow_algo}}
Height{{this.header.height}}
Version{{this.header.version}}
Timestamp{{timestamp this.header.timestamp}}
Previous Hash{{hex this.header.prev_hash}}
Nonce{{this.header.nonce}}
Output Merkle Root{{hex this.header.output_mr}}
Witness Merkle Root{{hex this.header.witness_mr}}
Kernel Merkle Root{{hex this.header.kernel_mr}}
Input Merkle Root{{hex this.header.input_mr}}
Kernel MMR Size{{this.header.kernel_mmr_size}}
Output MMR Size{{this.header.output_mmr_size}}
Total Kernel Offset{{hex this.header.total_kernel_offset}}
Total Script Offset{{hex this.header.total_script_offset}}
+

Kernels

- +
@@ -34,38 +103,40 @@

Outputs

-
Hash
+
- - - - + + + + {{#each this.block.body.outputs}} - - - - - - - - - - + + + + + + + + + + {{/each}}
Hash Commitment Flags MaturityParent PKUnique IdOther FeaturesScriptParent PKUnique IdOther FeaturesScript
{{hex hash}}{{hex commitment}}{{features.flags}}{{features.maturity}}{{ hex features.parent_public_key }}{{ hex features.unique_id}}{{ json features }}{{hex script}}
{{hex hash}}{{hex commitment}}{{features.flags}}{{features.maturity}}{{hex + features.parent_public_key + }}{{hex features.unique_id}}{{json features}}{{hex script}}

Spent Inputs

- +
diff --git a/applications/tari_explorer/views/index.hbs b/applications/tari_explorer/views/index.hbs index 6a3ba79797..f565983768 100644 --- a/applications/tari_explorer/views/index.hbs +++ b/applications/tari_explorer/views/index.hbs @@ -1,24 +1,24 @@

Tip

-
Hash
+
- + - +
Chain height Best blockPruning horizonPruned height
{{this.tipInfo.metadata.height_of_longest_chain}} {{hex this.tipInfo.metadata.best_block}}{{this.tipInfo.metadata.pruning_horizon}}{{this.tipInfo.metadata.pruned_height}}

Proof of work split

- +
@@ -42,7 +42,7 @@ - + @@ -53,7 +53,7 @@
 {{this.algoSplit.monero100}} {{percentbar this.algoSplit.monero100 this.algoSplit.sha100}}
Sha3SHA-3 {{this.algoSplit.sha10}} {{percentbar this.algoSplit.sha10 this.algoSplit.monero10}} {{this.algoSplit.sha20}} {{percentbar this.algoSplit.sha20 this.algoSplit.monero20}}

- +

Block times (minutes)

@@ -83,7 +83,7 @@

{{title}}

- +
@@ -123,7 +123,7 @@

Mempool

-
Height
+
diff --git a/applications/tari_explorer/views/layout.hbs b/applications/tari_explorer/views/layout.hbs index 3c0ee74010..9afc72630d 100644 --- a/applications/tari_explorer/views/layout.hbs +++ b/applications/tari_explorer/views/layout.hbs @@ -4,11 +4,17 @@

A simple, no Javascript, (almost) no CSS block explorer for Tari

+

tari.com


{{{body}}} diff --git a/applications/test_faucet/src/main.rs b/applications/test_faucet/src/main.rs index 05eb4061a4..5667055f3f 100644 --- a/applications/test_faucet/src/main.rs +++ b/applications/test_faucet/src/main.rs @@ -6,17 +6,30 @@ #![deny(unreachable_patterns)] #![deny(unknown_lints)] -use std::{fs::File, io::Write}; +use std::{ + fs::File, + io::{stdout, Write}, +}; use serde::Serialize; use tari_common_types::types::{Commitment, PrivateKey}; -use tari_core::transactions::{ - tari_amount::{MicroTari, T}, - test_helpers, - transaction::{KernelFeatures, OutputFeatures, TransactionKernel, TransactionOutput}, - CryptoFactories, +use tari_core::{ + covenants::Covenant, + transactions::{ + tari_amount::{MicroTari, T}, + test_helpers, + test_helpers::generate_keys, + transaction::{KernelFeatures, OutputFeatures, TransactionKernel, TransactionOutput}, + CryptoFactories, + }, +}; +use tari_crypto::{ + commitment::HomomorphicCommitmentFactory, + range_proof::RangeProofService, + script, + script::TariScript, + tari_utilities::hex::Hex, }; -use tari_crypto::{script, tari_utilities::hex::Hex}; use tokio::{sync::mpsc, task}; const NUM_KEYS: usize = 4000; @@ -63,8 +76,9 @@ async fn main() -> Result<(), Box> { task::spawn(async move { let result = task::spawn_blocking(move || { let script = script!(Nop); - let (utxo, key, _) = test_helpers::create_utxo(value, &fc, feature, &script, &Default::default()); + let (utxo, key, _) = create_utxo(value, &fc, feature, script, Covenant::default()); print!("."); + let _ = stdout().flush(); (utxo, key, value) }) .await @@ -137,3 +151,37 @@ impl Iterator for UTXOFeatures { Some(f) } } + +/// Create a new UTXO for the specified value and return the output and spending key +fn create_utxo( + value: MicroTari, + factories: &CryptoFactories, + features: OutputFeatures, + script: TariScript, + covenant: Covenant, +) -> (TransactionOutput, PrivateKey, PrivateKey) { + let keys = generate_keys(); + let offset_keys = generate_keys(); + let commitment = factories.commitment.commit_value(&keys.k, value.into()); + let proof = factories.range_proof.construct_proof(&keys.k, value.into()).unwrap(); + let metadata_sig = TransactionOutput::create_final_metadata_signature( + &value, + &keys.k, + &script, + &features, + &offset_keys.k, + &covenant, + ) + .unwrap(); + + let utxo = TransactionOutput::new_current_version( + features, + commitment, + proof.into(), + script, + offset_keys.pk, + metadata_sig, + covenant, + ); + (utxo, keys.k, offset_keys.k) +} diff --git a/base_layer/core/src/base_node/state_machine_service/states/horizon_state_sync/horizon_state_synchronization.rs b/base_layer/core/src/base_node/state_machine_service/states/horizon_state_sync/horizon_state_synchronization.rs index 9c5924a04f..80937f4d9b 100644 --- a/base_layer/core/src/base_node/state_machine_service/states/horizon_state_sync/horizon_state_synchronization.rs +++ b/base_layer/core/src/base_node/state_machine_service/states/horizon_state_sync/horizon_state_synchronization.rs @@ -199,10 +199,7 @@ impl<'a, B: BlockchainBackend + 'static> HorizonStateSynchronization<'a, B> { latency.unwrap_or_default().as_millis() ); - let mut current_header = self - .db() - .fetch_header_containing_kernel_mmr(local_num_kernels + 1) - .await?; + let mut current_header = self.db().fetch_header_containing_kernel_mmr(local_num_kernels).await?; let req = SyncKernelsRequest { start: local_num_kernels, end_header_hash: to_header.hash(), @@ -362,7 +359,7 @@ impl<'a, B: BlockchainBackend + 'static> HorizonStateSynchronization<'a, B> { include_pruned_utxos: true, }; - let mut current_header = self.db().fetch_header_containing_utxo_mmr(start + 1).await?; + let mut current_header = self.db().fetch_header_containing_utxo_mmr(start).await?; let mut output_stream = client.sync_utxos(req).await?; debug!( diff --git a/base_layer/core/src/base_node/sync/rpc/service.rs b/base_layer/core/src/base_node/sync/rpc/service.rs index adedcb23ef..891775ebc2 100644 --- a/base_layer/core/src/base_node/sync/rpc/service.rs +++ b/base_layer/core/src/base_node/sync/rpc/service.rs @@ -435,7 +435,7 @@ impl BaseNodeSyncService for BaseNodeSyncRpcServ let db = self.db(); let start_header = db - .fetch_header_containing_kernel_mmr(req.start + 1) + .fetch_header_containing_kernel_mmr(req.start) .await .map_err(RpcStatus::log_internal_error(LOG_TARGET))? .into_header(); diff --git a/base_layer/core/src/base_node/sync/rpc/sync_utxos_task.rs b/base_layer/core/src/base_node/sync/rpc/sync_utxos_task.rs index bf6c81c5d8..db1e46f94b 100644 --- a/base_layer/core/src/base_node/sync/rpc/sync_utxos_task.rs +++ b/base_layer/core/src/base_node/sync/rpc/sync_utxos_task.rs @@ -54,7 +54,7 @@ where B: BlockchainBackend + 'static ) -> Result<(), RpcStatus> { let start_header = self .db - .fetch_header_containing_utxo_mmr(request.start + 1) + .fetch_header_containing_utxo_mmr(request.start) .await .map_err(|err| { error!(target: LOG_TARGET, "{}", err); diff --git a/base_layer/core/src/chain_storage/blockchain_database.rs b/base_layer/core/src/chain_storage/blockchain_database.rs index 29b62b8a96..d5f68a7df5 100644 --- a/base_layer/core/src/chain_storage/blockchain_database.rs +++ b/base_layer/core/src/chain_storage/blockchain_database.rs @@ -214,9 +214,9 @@ where B: BlockchainBackend difficulty_calculator: Arc::new(difficulty_calculator), disable_add_block_flag: Arc::new(AtomicBool::new(false)), }; + let genesis_block = Arc::new(blockchain_db.consensus_manager.get_genesis_block()); if is_empty { info!(target: LOG_TARGET, "Blockchain db is empty. Adding genesis block."); - let genesis_block = Arc::new(blockchain_db.consensus_manager.get_genesis_block()); blockchain_db.insert_block(genesis_block.clone())?; let mut txn = DbTransaction::new(); let body = &genesis_block.block().body; @@ -230,6 +230,20 @@ where B: BlockchainBackend txn.set_horizon_data(kernel_sum, utxo_sum); blockchain_db.write(txn)?; blockchain_db.store_pruning_horizon(config.pruning_horizon)?; + } else if !blockchain_db.block_exists(genesis_block.accumulated_data().hash.clone())? { + // Check the genesis block in the DB. + error!( + target: LOG_TARGET, + "Genesis block in database does not match the supplied genesis block in the code! Hash in the code \ + {:?}, hash in the database {:?}", + blockchain_db.fetch_chain_header(0)?.hash(), + genesis_block.accumulated_data().hash + ); + return Err(ChainStorageError::CorruptedDatabase( + "Genesis block in database does not match the supplied genesis block in the code! Please delete and \ + resync your blockchain database." + .into(), + )); } if cleanup_orphans_at_startup { match blockchain_db.cleanup_all_orphans() { @@ -449,11 +463,6 @@ where B: BlockchainBackend Ok(chain_header) } - // TODO: this method is actually off by one. It returns the highest header where the kernel_mmr_count is <= - // mmr_position, but should probably only be <. - // E.g. if mmr_position == 2, it will return a header where kernel_mmr_count == 2, but this is - // confusing because mmr_position ==2 actually would be in the next header - // Either the caller needs to be updated or this method needs to be renamed pub fn fetch_header_containing_kernel_mmr(&self, mmr_position: u64) -> Result { let db = self.db_read_access()?; db.fetch_header_containing_kernel_mmr(mmr_position) diff --git a/base_layer/core/src/chain_storage/lmdb_db/lmdb_db.rs b/base_layer/core/src/chain_storage/lmdb_db/lmdb_db.rs index 14229c5cb3..7bbb2f67e9 100644 --- a/base_layer/core/src/chain_storage/lmdb_db/lmdb_db.rs +++ b/base_layer/core/src/chain_storage/lmdb_db/lmdb_db.rs @@ -1738,6 +1738,9 @@ impl BlockchainBackend for LMDBDatabase { fn fetch_header_containing_kernel_mmr(&self, mmr_position: u64) -> Result { let txn = self.read_transaction()?; + // LMDB returns the height at the position, so we have to offset the position by 1 so that the mmr_position arg + // is an index starting from 0 + let mmr_position = mmr_position + 1; let height = lmdb_first_after::<_, u64>(&txn, &self.kernel_mmr_size_index, &mmr_position.to_be_bytes())? .ok_or_else(|| ChainStorageError::ValueNotFound { @@ -1773,6 +1776,9 @@ impl BlockchainBackend for LMDBDatabase { // TODO: Can be merged with the method above fn fetch_header_containing_utxo_mmr(&self, mmr_position: u64) -> Result { let txn = self.read_transaction()?; + // LMDB returns the height at the position, so we have to offset the position by 1 so that the mmr_position arg + // is an index starting from 0 + let mmr_position = mmr_position + 1; let (height, _hash) = lmdb_first_after::<_, (u64, Vec)>(&txn, &self.output_mmr_size_index, &mmr_position.to_be_bytes())? diff --git a/base_layer/core/src/chain_storage/tests/blockchain_database.rs b/base_layer/core/src/chain_storage/tests/blockchain_database.rs index d6a8a10818..5bb31b4d19 100644 --- a/base_layer/core/src/chain_storage/tests/blockchain_database.rs +++ b/base_layer/core/src/chain_storage/tests/blockchain_database.rs @@ -575,7 +575,7 @@ mod fetch_header_containing_utxo_mmr { assert_eq!(header.height(), 0); mmr_position += 1; }); - let err = db.fetch_header_containing_utxo_mmr(4002).unwrap_err(); + let err = db.fetch_header_containing_utxo_mmr(mmr_position).unwrap_err(); matches!(err, ChainStorageError::ValueNotFound { .. }); } @@ -586,12 +586,16 @@ mod fetch_header_containing_utxo_mmr { let _ = add_many_chained_blocks(5, &db); let num_genesis_outputs = genesis.block().body.outputs().len() as u64; + let header = db.fetch_header_containing_utxo_mmr(num_genesis_outputs - 1).unwrap(); + assert_eq!(header.height(), 0); + for i in 1..=5 { - let header = db.fetch_header_containing_utxo_mmr(num_genesis_outputs + i).unwrap(); - assert_eq!(header.height(), i); + let index = num_genesis_outputs + i - 1; + let header = db.fetch_header_containing_utxo_mmr(index).unwrap(); + assert_eq!(header.height(), i, "Incorrect header for MMR index = {}", index); } let err = db - .fetch_header_containing_utxo_mmr(num_genesis_outputs + 5 + 1) + .fetch_header_containing_utxo_mmr(num_genesis_outputs + 5) .unwrap_err(); matches!(err, ChainStorageError::ValueNotFound { .. }); } @@ -605,13 +609,13 @@ mod fetch_header_containing_kernel_mmr { let db = setup(); let genesis = db.fetch_block(0).unwrap(); assert_eq!(genesis.block().body.kernels().len(), 2); - // let mut mmr_position = 0; - // genesis.block().body.kernels().iter().for_each(|_| { - // let header = db.fetch_header_containing_kernel_mmr(mmr_position).unwrap(); - // assert_eq!(header.height(), 0); - // mmr_position += 1; - // }); - let err = db.fetch_header_containing_kernel_mmr(3).unwrap_err(); + let mut mmr_position = 0; + genesis.block().body.kernels().iter().for_each(|_| { + let header = db.fetch_header_containing_kernel_mmr(mmr_position).unwrap(); + assert_eq!(header.height(), 0); + mmr_position += 1; + }); + let err = db.fetch_header_containing_kernel_mmr(mmr_position).unwrap_err(); matches!(err, ChainStorageError::ValueNotFound { .. }); } @@ -627,22 +631,22 @@ mod fetch_header_containing_kernel_mmr { db.add_block(block).unwrap(); let _ = add_many_chained_blocks(3, &db); - let header = db.fetch_header_containing_kernel_mmr(num_genesis_kernels).unwrap(); + let header = db.fetch_header_containing_kernel_mmr(num_genesis_kernels - 1).unwrap(); assert_eq!(header.height(), 0); - let header = db.fetch_header_containing_kernel_mmr(num_genesis_kernels + 1).unwrap(); + let header = db.fetch_header_containing_kernel_mmr(num_genesis_kernels).unwrap(); assert_eq!(header.height(), 1); - for i in 2..=3 { + for i in 1..=2 { let header = db.fetch_header_containing_kernel_mmr(num_genesis_kernels + i).unwrap(); assert_eq!(header.height(), 2); } - for i in 4..=6 { + for i in 3..=5 { let header = db.fetch_header_containing_kernel_mmr(num_genesis_kernels + i).unwrap(); - assert_eq!(header.height(), i - 1); + assert_eq!(header.height(), i); } let err = db - .fetch_header_containing_kernel_mmr(num_genesis_kernels + 6 + 1) + .fetch_header_containing_kernel_mmr(num_genesis_kernels + 6) .unwrap_err(); matches!(err, ChainStorageError::ValueNotFound { .. }); } diff --git a/base_layer/core/src/transactions/transaction_protocol/recipient.rs b/base_layer/core/src/transactions/transaction_protocol/recipient.rs index 1aca21dc84..7aae24f19d 100644 --- a/base_layer/core/src/transactions/transaction_protocol/recipient.rs +++ b/base_layer/core/src/transactions/transaction_protocol/recipient.rs @@ -30,7 +30,7 @@ use tari_common_types::{ use crate::transactions::{ crypto_factories::CryptoFactories, - transaction::{OutputFeatures, TransactionOutput}, + transaction::TransactionOutput, transaction_protocol::{ sender::{SingleRoundSenderData as SD, TransactionSenderMessage}, single_receiver::SingleReceiverTransactionProtocol, @@ -110,13 +110,12 @@ impl ReceiverTransactionProtocol { info: TransactionSenderMessage, nonce: PrivateKey, spending_key: PrivateKey, - features: OutputFeatures, factories: &CryptoFactories, ) -> ReceiverTransactionProtocol { let state = match info { TransactionSenderMessage::None => RecipientState::Failed(TransactionProtocolError::InvalidStateError), TransactionSenderMessage::Single(v) => { - ReceiverTransactionProtocol::single_round(nonce, spending_key, features, &v, factories, None) + ReceiverTransactionProtocol::single_round(nonce, spending_key, &v, factories, None) }, TransactionSenderMessage::Multiple => Self::multi_round(), }; @@ -129,20 +128,14 @@ impl ReceiverTransactionProtocol { info: TransactionSenderMessage, nonce: PrivateKey, spending_key: PrivateKey, - features: OutputFeatures, factories: &CryptoFactories, rewind_data: &RewindData, ) -> ReceiverTransactionProtocol { let state = match info { TransactionSenderMessage::None => RecipientState::Failed(TransactionProtocolError::InvalidStateError), - TransactionSenderMessage::Single(v) => ReceiverTransactionProtocol::single_round( - nonce, - spending_key, - features, - &v, - factories, - Some(rewind_data), - ), + TransactionSenderMessage::Single(v) => { + ReceiverTransactionProtocol::single_round(nonce, spending_key, &v, factories, Some(rewind_data)) + }, TransactionSenderMessage::Multiple => Self::multi_round(), }; ReceiverTransactionProtocol { state } @@ -178,12 +171,11 @@ impl ReceiverTransactionProtocol { fn single_round( nonce: PrivateKey, key: PrivateKey, - features: OutputFeatures, data: &SD, factories: &CryptoFactories, rewind_data: Option<&RewindData>, ) -> RecipientState { - let signer = SingleReceiverTransactionProtocol::create(data, nonce, key, features, factories, rewind_data); + let signer = SingleReceiverTransactionProtocol::create(data, nonce, key, factories, rewind_data); match signer { Ok(signed_data) => RecipientState::Finalized(Box::new(signed_data)), Err(e) => RecipientState::Failed(e), @@ -252,7 +244,7 @@ mod test { public_nonce: PublicKey::from_secret_key(&p.change_spend_key), // any random key will do metadata: m.clone(), message: "".to_string(), - features: features.clone(), + features, script, sender_offset_public_key: p.sender_offset_public_key, public_commitment_nonce: p.sender_public_commitment_nonce, @@ -260,8 +252,7 @@ mod test { }; let sender_info = TransactionSenderMessage::Single(Box::new(msg.clone())); let pubkey = PublicKey::from_secret_key(&p.spend_key); - let receiver = - ReceiverTransactionProtocol::new(sender_info, p.nonce.clone(), p.spend_key.clone(), features, &factories); + let receiver = ReceiverTransactionProtocol::new(sender_info, p.nonce.clone(), p.spend_key.clone(), &factories); assert!(receiver.is_finalized()); let data = receiver.get_signed_data().unwrap(); assert_eq!(data.tx_id.as_u64(), 15); @@ -300,7 +291,7 @@ mod test { public_nonce: PublicKey::from_secret_key(&p.change_spend_key), // any random key will do metadata: m, message: "".to_string(), - features: features.clone(), + features, script, sender_offset_public_key: p.sender_offset_public_key, public_commitment_nonce: p.sender_public_commitment_nonce, @@ -316,7 +307,6 @@ mod test { sender_info, p.nonce.clone(), p.spend_key.clone(), - features, &factories, &rewind_data, ); diff --git a/base_layer/core/src/transactions/transaction_protocol/sender.rs b/base_layer/core/src/transactions/transaction_protocol/sender.rs index d6cd156159..8c231d5b79 100644 --- a/base_layer/core/src/transactions/transaction_protocol/sender.rs +++ b/base_layer/core/src/transactions/transaction_protocol/sender.rs @@ -902,7 +902,7 @@ mod test { .with_offset(a.offset.clone()) .with_private_nonce(a.nonce.clone()) .with_input(utxo.clone(), input) - .with_recipient_data(0, script.clone(), PrivateKey::random(&mut OsRng), features.clone(), PrivateKey::random(&mut OsRng), Covenant::default()) + .with_recipient_data(0, script.clone(), PrivateKey::random(&mut OsRng), features, PrivateKey::random(&mut OsRng), Covenant::default()) .with_change_script(script, ExecutionStack::default(), PrivateKey::default()) // A little twist: Check the case where the change is less than the cost of another output .with_amount(0, MicroTari(1200) - fee - MicroTari(10)); @@ -918,7 +918,7 @@ mod test { // Receiver gets message, deserializes it etc, and creates his response let mut bob_info = - SingleReceiverTransactionProtocol::create(&msg, b.nonce, b.spend_key, features, &factories, None).unwrap(); // Alice gets message back, deserializes it, etc + SingleReceiverTransactionProtocol::create(&msg, b.nonce, b.spend_key, &factories, None).unwrap(); // Alice gets message back, deserializes it, etc alice .add_single_recipient_info(bob_info.clone(), &factories.range_proof) .unwrap(); @@ -968,7 +968,7 @@ mod test { 0, script.clone(), PrivateKey::random(&mut OsRng), - features.clone(), + features, PrivateKey::random(&mut OsRng), Covenant::default(), ) @@ -993,8 +993,7 @@ mod test { let mut alice = SenderTransactionProtocol::load_pending_transaction_to_be_sent(ser).unwrap(); // Receiver gets message, deserializes it etc, and creates his response - let bob_info = - SingleReceiverTransactionProtocol::create(&msg, b.nonce, b.spend_key, features, &factories, None).unwrap(); + let bob_info = SingleReceiverTransactionProtocol::create(&msg, b.nonce, b.spend_key, &factories, None).unwrap(); println!( "Bob's key: {}, Nonce: {}, Signature: {}, Commitment: {}", bob_info.public_spend_key.to_hex(), @@ -1049,7 +1048,7 @@ mod test { 0, script.clone(), PrivateKey::random(&mut OsRng), - features.clone(), + features, PrivateKey::random(&mut OsRng), Covenant::default(), ) @@ -1061,8 +1060,7 @@ mod test { // Send message down the wire....and wait for response assert!(alice.is_collecting_single_signature()); // Receiver gets message, deserializes it etc, and creates his response - let bob_info = - SingleReceiverTransactionProtocol::create(&msg, b.nonce, b.spend_key, features, &factories, None).unwrap(); // Alice gets message back, deserializes it, etc + let bob_info = SingleReceiverTransactionProtocol::create(&msg, b.nonce, b.spend_key, &factories, None).unwrap(); // Alice gets message back, deserializes it, etc match alice.add_single_recipient_info(bob_info, &factories.range_proof) { Ok(_) => panic!("Range proof should have failed to verify"), Err(e) => assert_eq!( @@ -1181,7 +1179,7 @@ mod test { 0, script.clone(), PrivateKey::random(&mut OsRng), - features.clone(), + features, PrivateKey::random(&mut OsRng), Covenant::default(), ) @@ -1205,8 +1203,7 @@ mod test { assert!(alice.is_collecting_single_signature()); // Receiver gets message, deserializes it etc, and creates his response - let bob_info = - SingleReceiverTransactionProtocol::create(&msg, b.nonce, b.spend_key, features, &factories, None).unwrap(); + let bob_info = SingleReceiverTransactionProtocol::create(&msg, b.nonce, b.spend_key, &factories, None).unwrap(); // Alice gets message back, deserializes it, etc alice diff --git a/base_layer/core/src/transactions/transaction_protocol/single_receiver.rs b/base_layer/core/src/transactions/transaction_protocol/single_receiver.rs index d51daa4242..19ffc76800 100644 --- a/base_layer/core/src/transactions/transaction_protocol/single_receiver.rs +++ b/base_layer/core/src/transactions/transaction_protocol/single_receiver.rs @@ -30,7 +30,7 @@ use tari_crypto::{ use crate::transactions::{ crypto_factories::CryptoFactories, - transaction::{OutputFeatures, TransactionOutput}, + transaction::TransactionOutput, transaction_protocol::{ build_challenge, recipient::RecipientSignedMessage as RD, @@ -53,18 +53,12 @@ impl SingleReceiverTransactionProtocol { sender_info: &SD, nonce: SK, spending_key: SK, - features: OutputFeatures, factories: &CryptoFactories, rewind_data: Option<&RewindData>, ) -> Result { SingleReceiverTransactionProtocol::validate_sender_data(sender_info)?; - let output = SingleReceiverTransactionProtocol::build_output( - sender_info, - &spending_key, - features, - factories, - rewind_data, - )?; + let output = + SingleReceiverTransactionProtocol::build_output(sender_info, &spending_key, factories, rewind_data)?; let public_nonce = PublicKey::from_secret_key(&nonce); let public_spending_key = PublicKey::from_secret_key(&spending_key); let e = build_challenge(&(&sender_info.public_nonce + &public_nonce), &sender_info.metadata); @@ -89,7 +83,6 @@ impl SingleReceiverTransactionProtocol { fn build_output( sender_info: &SD, spending_key: &SK, - features: OutputFeatures, factories: &CryptoFactories, rewind_data: Option<&RewindData>, ) -> Result { @@ -111,18 +104,20 @@ impl SingleReceiverTransactionProtocol { .construct_proof(spending_key, sender_info.amount.into())? }; + let sender_features = sender_info.features.clone(); + let partial_metadata_signature = TransactionOutput::create_partial_metadata_signature( &sender_info.amount, &spending_key.clone(), &sender_info.script, - &sender_info.features, + &sender_features, &sender_info.sender_offset_public_key, &sender_info.public_commitment_nonce, &sender_info.covenant, )?; let output = TransactionOutput::new_current_version( - features, + sender_features, commitment, RangeProof::from_bytes(&proof) .map_err(|_| TPE::RangeProofError(RangeProofError::ProofConstructionError))?, @@ -169,8 +164,8 @@ mod test { fn zero_amount_fails() { let factories = CryptoFactories::default(); let info = SingleRoundSenderData::default(); - let (r, k, of) = generate_output_parms(); - match SingleReceiverTransactionProtocol::create(&info, r, k, of, &factories, None) { + let (r, k, _) = generate_output_parms(); + match SingleReceiverTransactionProtocol::create(&info, r, k, &factories, None) { Ok(_) => panic!("Zero amounts should fail"), Err(TransactionProtocolError::ValidationError(s)) => assert_eq!(s, "Cannot send zero microTari"), Err(_) => panic!("Protocol fails for the wrong reason"), @@ -201,13 +196,13 @@ mod test { public_nonce: pub_rs.clone(), metadata: m.clone(), message: "".to_string(), - features: of.clone(), + features: of, script, sender_offset_public_key, public_commitment_nonce, covenant: Default::default(), }; - let prot = SingleReceiverTransactionProtocol::create(&info, r, k.clone(), of, &factories, None).unwrap(); + let prot = SingleReceiverTransactionProtocol::create(&info, r, k.clone(), &factories, None).unwrap(); assert_eq!(prot.tx_id.as_u64(), 500, "tx_id is incorrect"); // Check the signature assert_eq!(prot.public_spend_key, pubkey, "Public key is incorrect"); diff --git a/base_layer/wallet/src/output_manager_service/service.rs b/base_layer/wallet/src/output_manager_service/service.rs index 2a8aedd8ac..3f51a32f8f 100644 --- a/base_layer/wallet/src/output_manager_service/service.rs +++ b/base_layer/wallet/src/output_manager_service/service.rs @@ -648,7 +648,6 @@ where sender_message.clone(), nonce, spending_key, - single_round_sender_data.features.clone(), &self.resources.factories, self.resources.master_key_manager.rewind_data(), ); diff --git a/base_layer/wallet/src/transaction_service/service.rs b/base_layer/wallet/src/transaction_service/service.rs index 73252d36e5..e83538c4f6 100644 --- a/base_layer/wallet/src/transaction_service/service.rs +++ b/base_layer/wallet/src/transaction_service/service.rs @@ -939,7 +939,6 @@ where sender_message, PrivateKey::random(&mut OsRng), spend_key.clone(), - OutputFeatures::default(), &self.resources.factories, &rewind_data, ); @@ -1099,7 +1098,6 @@ where sender_message, PrivateKey::random(&mut OsRng), spend_key, - OutputFeatures::default(), &self.resources.factories, &rewind_data, ); diff --git a/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs b/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs index 02798d3f3c..8dc318d5e8 100644 --- a/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs +++ b/base_layer/wallet/src/transaction_service/storage/sqlite_db.rs @@ -2168,7 +2168,6 @@ mod test { TransactionSenderMessage::Single(Box::new(stp.build_single_round_message().unwrap())), PrivateKey::random(&mut OsRng), PrivateKey::random(&mut OsRng), - OutputFeatures::default(), &factories, ); diff --git a/base_layer/wallet/tests/transaction_service_tests/service.rs b/base_layer/wallet/tests/transaction_service_tests/service.rs index a1103ef294..b145f8ef8c 100644 --- a/base_layer/wallet/tests/transaction_service_tests/service.rs +++ b/base_layer/wallet/tests/transaction_service_tests/service.rs @@ -1430,7 +1430,6 @@ fn test_accepting_unknown_tx_id_and_malformed_reply() { sender_message.try_into().unwrap(), params.nonce, params.spend_key, - OutputFeatures::default(), &factories, ); @@ -2997,13 +2996,8 @@ fn test_restarting_transaction_protocols() { let tx_id = msg.tx_id; let sender_info = TransactionSenderMessage::Single(Box::new(msg.clone())); - let receiver_protocol = ReceiverTransactionProtocol::new( - sender_info, - alice.nonce.clone(), - alice.spend_key, - OutputFeatures::default(), - &factories, - ); + let receiver_protocol = + ReceiverTransactionProtocol::new(sender_info, alice.nonce.clone(), alice.spend_key, &factories); let alice_reply = receiver_protocol.get_signed_data().unwrap().clone(); @@ -4415,7 +4409,6 @@ fn test_resend_on_startup() { tx_sender_msg, PrivateKey::random(&mut OsRng), PrivateKey::random(&mut OsRng), - OutputFeatures::default(), &factories, ); diff --git a/base_layer/wallet/tests/transaction_service_tests/storage.rs b/base_layer/wallet/tests/transaction_service_tests/storage.rs index d9e616dac0..72b2cf2052 100644 --- a/base_layer/wallet/tests/transaction_service_tests/storage.rs +++ b/base_layer/wallet/tests/transaction_service_tests/storage.rs @@ -169,7 +169,6 @@ pub fn test_db_backend(backend: T) { TransactionSenderMessage::Single(Box::new(stp.clone().build_single_round_message().unwrap())), PrivateKey::random(&mut OsRng), PrivateKey::random(&mut OsRng), - OutputFeatures::default(), &factories, );
Excess