From 2522d2421e48e9b038b8ba0928de59d0d9dbb90f Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Sun, 28 Aug 2022 23:05:02 -0400 Subject: [PATCH 01/96] remove old cicd --- .cicd/build.sh | 46 ---- .cicd/helpers/buildkite.sh | 11 - .cicd/helpers/dependency-info.sh | 40 --- .cicd/helpers/general.sh | 6 - .cicd/metrics/test-metrics.js | 431 ------------------------------ .cicd/metrics/test-metrics.tar.gz | Bin 96551 -> 0 bytes .cicd/pipeline.yml | 38 --- .cicd/test.sh | 39 --- .github/workflows/ubuntu-2004.yml | 77 ------ 9 files changed, 688 deletions(-) delete mode 100755 .cicd/build.sh delete mode 100755 .cicd/helpers/buildkite.sh delete mode 100755 .cicd/helpers/dependency-info.sh delete mode 100644 .cicd/helpers/general.sh delete mode 100644 .cicd/metrics/test-metrics.js delete mode 100644 .cicd/metrics/test-metrics.tar.gz delete mode 100644 .cicd/pipeline.yml delete mode 100755 .cicd/test.sh delete mode 100644 .github/workflows/ubuntu-2004.yml diff --git a/.cicd/build.sh b/.cicd/build.sh deleted file mode 100755 index 42975cd0..00000000 --- a/.cicd/build.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash -set -eo pipefail -. ./.cicd/helpers/buildkite.sh -. ./.cicd/helpers/general.sh -. ./.cicd/helpers/dependency-info.sh -mkdir -p $BUILD_DIR -DOCKER_IMAGE=${DOCKER_IMAGE:-eosio/ci-contracts-builder:base-ubuntu-18.04-$SANITIZED_EOSIO_VERSION} -if [[ "$BUILDKITE" == 'true' ]]; then - buildkite-agent meta-data set cdt-url "$CDT_URL" - buildkite-agent meta-data set cdt-version "$CDT_VERSION" - buildkite-agent meta-data set docker-image "$DOCKER_IMAGE" -else - export CDT_URL - export CDT_VERSION - export DOCKER_IMAGE -fi -ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} -CDT_COMMANDS="dpkg -i $MOUNTED_DIR/eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/\\\$(ls /usr/opt/eosio.cdt/)/bin:\\\$PATH" -PRE_COMMANDS="$CDT_COMMANDS && cd /root/eosio/ && printf \\\"EOSIO commit: \\\$(git rev-parse --verify HEAD). Click \033]1339;url=https://github.com/EOSIO/eos/commit/\\\$(git rev-parse --verify HEAD);content=here\a for details.\n\\\" && cd $MOUNTED_DIR/build" -BUILD_COMMANDS="cmake -DBUILD_TESTS=true .. && make -j $JOBS" -COMMANDS="$PRE_COMMANDS && $BUILD_COMMANDS" -# Test CDT binary download to prevent failures due to eosio.cdt pipeline. -INDEX='1' -echo "$ curl -sSf $CDT_URL --output eosio.cdt.deb" -while ! $(curl -sSf $CDT_URL --output eosio.cdt.deb); do - echo "ERROR: Expected CDT binary for commit ${CDT_COMMIT} from $CDT_VERSION. It does not exist at $CDT_URL!" - printf "There must be a successful build against ${CDT_COMMIT} \033]1339;url=https://buildkite.com/EOSIO/eosio-dot-cdt/builds?commit=$CDT_COMMIT;content=here\a for this package to exist.\n" - echo "Attempt $INDEX, retry in 60 seconds..." - echo '' - INDEX=$(( $INDEX + 1 )) - sleep 60 -done -# retry docker pull to protect against failures due to race conditions with eosio pipeline -INDEX='1' -echo "$ docker pull $DOCKER_IMAGE" -while [[ "$(docker pull $DOCKER_IMAGE 2>&1 | grep -ice "manifest for $DOCKER_IMAGE not found")" != '0' ]]; do - echo "ERROR: Docker image \"$DOCKER_IMAGE\" not found for eosio \"$EOSIO_VERSION\""'!' - printf "There must be a successful build against ${EOSIO_VERSION} \033]1339;url=${EOSIO_BK_URL};content=here\a for this container to exist.\n" - echo "Attempt $INDEX, retry in 60 seconds..." - echo '' - INDEX=$(( $INDEX + 1 )) - sleep 60 -done -# run -echo "docker run $ARGS $(buildkite-intrinsics) $DOCKER_IMAGE bash -c \"$COMMANDS\"" -eval docker run $ARGS $(buildkite-intrinsics) $DOCKER_IMAGE bash -c \"$COMMANDS\" \ No newline at end of file diff --git a/.cicd/helpers/buildkite.sh b/.cicd/helpers/buildkite.sh deleted file mode 100755 index 1d2eee39..00000000 --- a/.cicd/helpers/buildkite.sh +++ /dev/null @@ -1,11 +0,0 @@ -# load buildkite intrinsic environment variables for use in docker run -function buildkite-intrinsics() -{ - BK_ENV='' - if [[ -f $BUILDKITE_ENV_FILE ]]; then - while read -r var; do - BK_ENV="$BK_ENV --env ${var%%=*}" - done < "$BUILDKITE_ENV_FILE" - fi - echo "$BK_ENV" -} \ No newline at end of file diff --git a/.cicd/helpers/dependency-info.sh b/.cicd/helpers/dependency-info.sh deleted file mode 100755 index ef7e1d05..00000000 --- a/.cicd/helpers/dependency-info.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash -set -eo pipefail -[[ "$RAW_PIPELINE_CONFIG" == '' ]] && export RAW_PIPELINE_CONFIG="$1" -[[ "$RAW_PIPELINE_CONFIG" == '' ]] && export RAW_PIPELINE_CONFIG='pipeline.jsonc' -[[ "$PIPELINE_CONFIG" == '' ]] && export PIPELINE_CONFIG='pipeline.json' -# read dependency file -if [[ -f "$RAW_PIPELINE_CONFIG" ]]; then - echo 'Reading pipeline configuration file...' - cat "$RAW_PIPELINE_CONFIG" | grep -Po '^[^"/]*("((?<=\\).|[^"])*"[^"/]*)*' | jq -c .\"eosio-dot-contracts\" > "$PIPELINE_CONFIG" - CDT_VERSION=$(cat "$PIPELINE_CONFIG" | jq -r '.dependencies."eosio.cdt"') - EOSIO_VERSION=$(cat "$PIPELINE_CONFIG" | jq -r '.dependencies.eosio') - SANITIZED_EOSIO_VERSION=$(echo $EOSIO_VERSION | sed 's/\//\_/') -else - echo 'ERROR: No pipeline configuration file or dependencies file found!' - exit 1 -fi -# search GitHub for commit hash by tag and branch, preferring tag if both match -if [[ "$BUILDKITE" == 'true' ]]; then - CDT_COMMIT=$((curl -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/tags/$CDT_VERSION && curl -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/heads/$CDT_VERSION) | jq '.object.sha' | sed "s/null//g" | sed "/^$/d" | tr -d '"' | sed -n '1p') - EOSIO_COMMIT=$((curl -s https://api.github.com/repos/EOSIO/eos/git/refs/tags/$EOSIO_VERSION && curl -s https://api.github.com/repos/EOSIO/eos/git/refs/heads/$EOSIO_VERSION) | jq '.object.sha' | sed "s/null//g" | sed "/^$/d" | tr -d '"' | sed -n '1p') - test -z "$CDT_COMMIT" && CDT_COMMIT=$(echo $CDT_VERSION | tr -d '"' | tr -d "''" | cut -d ' ' -f 1) # if both searches returned nothing, the version is probably specified by commit hash already - test -z "$EOSIO_COMMIT" && EOSIO_COMMIT=$(echo $EOSIO_VERSION | tr -d '"' | tr -d "''" | cut -d ' ' -f 1) # if both searches returned nothing, the version is probably specified by commit hash already -else - git clone https://github.com/EOSIO/eosio.cdt && cd eosio.cdt - git pull && git checkout $CDT_VERSION - CDT_COMMIT=$(git rev-parse --verify HEAD) - cd .. - git clone https://github.com/EOSIO/eos && cd eos - git pull && git checkout $EOSIO_VERSION - EOSIO_COMMIT=$(git rev-parse --verify HEAD) - cd .. -fi -if [[ "$EOSIO_COMMIT" == "$EOSIO_VERSION" ]]; then - EOSIO_BK_URL="https://buildkite.com/EOSIO/eosio/builds?commit=${EOSIO_COMMIT}" -else - EOSIO_BK_URL="https://buildkite.com/EOSIO/eosio/builds?branch=${EOSIO_VERSION}" -fi -echo "Using eosio \"$EOSIO_VERSION\"..." -echo "Using cdt ${CDT_COMMIT} from \"$CDT_VERSION\"..." -export CDT_URL="https://eos-public-oss-binaries.s3-us-west-2.amazonaws.com/${CDT_COMMIT:0:7}-eosio.cdt-ubuntu-18.04_amd64.deb" \ No newline at end of file diff --git a/.cicd/helpers/general.sh b/.cicd/helpers/general.sh deleted file mode 100644 index 42b04117..00000000 --- a/.cicd/helpers/general.sh +++ /dev/null @@ -1,6 +0,0 @@ -export ROOT_DIR=$( dirname "${BASH_SOURCE[0]}" )/../.. -export BUILD_DIR=$ROOT_DIR/build -export CICD_DIR=$ROOT_DIR/.cicd -export HELPERS_DIR=$CICD_DIR/helpers -export JOBS=${JOBS:-"$(getconf _NPROCESSORS_ONLN)"} -export MOUNTED_DIR='/workdir' diff --git a/.cicd/metrics/test-metrics.js b/.cicd/metrics/test-metrics.js deleted file mode 100644 index b995134d..00000000 --- a/.cicd/metrics/test-metrics.js +++ /dev/null @@ -1,431 +0,0 @@ -#!/usr/bin/env node -/* includes */ -const execSync = require('child_process').execSync; // run shell commands -const fetch = require('node-fetch'); // downloading -const fs = require('fs'); // file stream -const XML = require('xml2js'); // parse xml - -/* globals */ -const buildkiteAccessToken = `?access_token=${process.env.BUILDKITE_API_KEY}`; // import buildkite access token from environment -const debug = (process.env.DEBUG === 'true') ? true : false; -let errorCount = 0; // count number of jobs which caused an error -const EXIT_SUCCESS = 0; -const inBuildkite = (process.env.BUILDKITE === 'true') ? true : false; -const outputFile = 'test-metrics.json'; -const pipelineWhitelist = // the pipelines for which we run diagnostics -[ - 'eosio', - 'eosio-base-images', - 'eosio-beta', - 'eosio-build-unpinned', - 'eosio-debug', - 'eosio-lrt', - 'eosio-security' -]; - -/* functions */ -// given a url string, download a text document -async function download(url) -{ - if (debug) console.log(`download(${url.replace(buildkiteAccessToken, '')})`); // DEBUG - const httpResponse = await fetch(url); - const body = await httpResponse.text(); - if (isNullOrEmpty(body)) - { - console.log(`ERROR: URL returned nothing! URL: ${url.replace(buildkiteAccessToken, '')}`); - const error = - { - http: { body, response: httpResponse, url}, - message: 'http body is null or empty', - origin: 'download()', - } - throw error; - } - if (debug) console.log('Download complete.'); // DEBUG - return body; -} - -// given a pipeline and a build number, get a build object -async function getBuild(pipeline, buildNumber) -{ - if (debug) console.log(`getBuild(${pipeline}, ${buildNumber})`); // DEBUG - const httpResponse = await fetch(`https://api.buildkite.com/v2/organizations/EOSIO/pipelines/${pipeline}/builds/${buildNumber}${buildkiteAccessToken}`); - return httpResponse.json(); -} - -// given a buildkite job, return the environmental variables -async function getEnvironment(job) -{ - if (debug) console.log('getEnvironment()'); // DEBUG - const httpResponse = await fetch(`${job.build_url}/jobs/${job.id}/env${buildkiteAccessToken}`); - const environment = await httpResponse.json(); - return environment.env; -} - -// given a string to search, a key as regex or a string, and optionally a start index, return the lowest line number containing the key -function getLineNumber(text, key, startIndex) -{ - if (debug) console.log('getLineNumber()'); // DEBUG - const begin = (isNullOrEmpty(startIndex) || !Number.isInteger(startIndex) || startIndex < 1) ? 0 : startIndex; - let found = false; - let lineNumber = 0; - const regex = (key instanceof RegExp); - text.split('\n').some((line) => - { - if (lineNumber >= begin && ((regex && key.test(line)) || (!regex && line.includes(key)))) - { - found = true; - return true; // c-style break - } - lineNumber += 1; - return false; // for the linter, plz delete when linter is fixed - }); - return (found) ? lineNumber : -1; -} - -// given a buildkite job, return a sanitized log file -async function getLog(job) -{ - if (debug) console.log(`getLog(${job.raw_log_url})`); // DEBUG - const logText = await download(job.raw_log_url + buildkiteAccessToken); - // returns log lowercase, with single spaces and '\n' only, and only ascii-printable characters - return sanitize(logText); // made this a separate function for unit testing purposes -} - -// given a Buildkite environment, return the operating system used -function getOS(environment) -{ - if (debug) console.log(`getOS(${environment.BUILDKITE_LABEL})`); // DEBUG - if (isNullOrEmpty(environment) || isNullOrEmpty(environment.BUILDKITE_LABEL)) - { - console.log('ERROR: getOS() called with empty environment.BUILDKITE_LABEL!'); - console.log(JSON.stringify(environment)); - return null; - } - const label = environment.BUILDKITE_LABEL.toLowerCase(); - if ((/aws(?!.*[23])/.test(label) || /amazon(?!.*[23])/.test(label))) - return 'Amazon Linux 1'; - if (/aws.*2/.test(label) || /amazon.*2/.test(label)) - return 'Amazon Linux 2'; - if (/centos(?!.*[89])/.test(label)) - return 'CentOS 7'; - if (/fedora(?!.*2[89])/.test(label) && /fedora(?!.*3\d)/.test(label)) - return 'Fedora 27'; - if (/high.*sierra/.test(label)) - return 'High Sierra'; - if (/mojave/.test(label)) - return 'Mojave'; - if (/ubuntu.*16.*04/.test(label) || /ubuntu.*16(?!.*10)/.test(label)) - return 'Ubuntu 16.04'; - if (/ubuntu.*18.*04/.test(label) || /ubuntu.*18(?!.*10)/.test(label)) - return 'Ubuntu 18.04'; - if (/docker/.test(label)) - return 'Docker'; - return 'Unknown'; -} - -// given a Buildkite job, return the test-results.xml file as JSON -async function getXML(job) -{ - if (debug) console.log('getXML()'); // DEBUG - const xmlFilename = 'test-results.xml'; - const artifacts = await download(job.artifacts_url + buildkiteAccessToken); - const testResultsArtifact = JSON.parse(artifacts).filter(artifact => artifact.filename === xmlFilename); - if (isNullOrEmpty(testResultsArtifact)) - { - console.log(`WARNING: No ${xmlFilename} found for "${job.name}"! Link: ${job.web_url}`); - return null; - } - const urlBuildkite = testResultsArtifact[0].download_url; - const rawXML = await download(urlBuildkite + buildkiteAccessToken); - const xmlOptions = - { - attrNameProcessors: [function lower(name) { return name.toLowerCase(); }], - explicitArray: false, // do not put single strings in single-element arrays - mergeAttrs: true, // make attributes children of their node - normalizeTags: true, // convert all tag names to lowercase - }; - let xmlError, xmlTestResults; - await XML.parseString(rawXML, xmlOptions, (err, result) => {xmlTestResults = result; xmlError = err;}); - if (isNullOrEmpty(xmlError)) - return xmlTestResults; - console.log(`WARNING: Failed to parse xml for "${job.name}" job! Link: ${job.web_url}`); - console.log(JSON.stringify(xmlError)); - return null; -} - -// test if variable is empty -function isNullOrEmpty(str) -{ - return (str === null || str === undefined || str.length === 0 || /^\s*$/.test(str)); -} - -// return array of test results from a buildkite job log -function parseLog(logText) -{ - if (debug) console.log('parseLog()'); // DEBUG - const lines = logText.split('\n'); - const resultLines = lines.filter(line => /test\s+#\d+/.test(line)); // 'grep' for the test result lines - // parse the strings and make test records - return resultLines.map((line) => - { - const y = line.trim().split(/test\s+#\d+/).pop(); // remove everything before the test declaration - const parts = y.split(/\s+/).slice(1, -1); // split the line and remove the test number and time unit - const testName = parts[0]; - const testTime = parts[(parts.length - 1)]; - const rawResult = parts.slice(1, -1).join(); - let testResult; - if (rawResult.includes('failed')) - testResult = 'Failed'; - else if (rawResult.includes('passed')) - testResult = 'Passed'; - else - testResult = 'Exception'; - return { testName, testResult, testTime }; // create a test record - }); -} - -// return array of test results from an xUnit-formatted JSON object -function parseXunit(xUnit) -{ - if (debug) console.log('parseXunit()'); // DEBUG - if (isNullOrEmpty(xUnit)) - { - console.log('WARNING: xUnit is empty!'); - return null; - } - return xUnit.site.testing.test.map((test) => - { - const testName = test.name; - const testTime = test.results.namedmeasurement.filter(x => /execution\s+time/.test(x.name.toLowerCase()))[0].value; - let testResult; - if (test.status.includes('failed')) - testResult = 'Failed'; - else if (test.status.includes('passed')) - testResult = 'Passed'; - else - testResult = 'Exception'; - return { testName, testResult, testTime }; - }); -} - -// returns text lowercase, with single spaces and '\n' only, and only ascii-printable characters -function sanitize(text) -{ - if (debug) console.log(`sanitize(text) where text.length = ${text.length} bytes`); // DEBUG - const chunkSize = 131072; // process text in 128 kB chunks - if (text.length > chunkSize) - return sanitize(text.slice(0, chunkSize)).concat(sanitize(text.slice(chunkSize))); - return text - .replace(/(?!\n)\r(?!\n)/g, '\n').replace(/\r/g, '') // convert all line endings to '\n' - .replace(/[^\S\n]+/g, ' ') // convert all whitespace to ' ' - .replace(/[^ -~\n]+/g, '') // remove non-printable characters - .toLowerCase(); -} - -// input is array of whole lines containing "test #" and ("failed" or "exception") -function testDiagnostics(test, logText) -{ - if (debug) - { - console.log(`testDiagnostics(test, logText) where logText.length = ${logText.length} bytes and test is`); // DEBUG - console.log(JSON.stringify(test)); - } - // get basic information - const testResultLine = new RegExp(`test\\s+#\\d+.*${test.testName}`, 'g'); // regex defining "test #" line - const startIndex = getLineNumber(logText, testResultLine); - const output = { errorMsg: null, lineNumber: startIndex + 1, stackTrace: null }; // default output - // filter tests - if (test.testResult.toLowerCase() === 'passed') - return output; - output.errorMsg = 'test diangostics are not enabled for this pipeline'; - if (!pipelineWhitelist.includes(test.pipeline)) - return output; - // diagnostics - if (debug) console.log('Running diagnostics...'); // DEBUG - output.errorMsg = 'uncategorized'; - const testLog = logText.split(testResultLine)[1].split(/test\s*#/)[0].split('\n'); // get log output from this test only, as array of lines - let errorLine = testLog[0]; // first line, from "test ## name" to '\n' exclusive - if (/\.+ *\** *not run\s+0+\.0+ sec$/.test(errorLine)) // not run - output.errorMsg = 'test not run'; - else if (/\.+ *\** *time *out\s+\d+\.\d+ sec$/.test(errorLine)) // timeout - output.errorMsg = 'test timeout'; - else if (/exception/.test(errorLine)) // test exception - output.errorMsg = errorLine.split('exception')[1].replace(/[: \d.]/g, '').replace(/sec$/, ''); // isolate the error message after exception - else if (/fc::.*exception/.test(testLog.filter(line => !isNullOrEmpty(line))[1])) // fc exception - { - [, errorLine] = testLog.filter(line => !isNullOrEmpty(line)); // get first line - output.errorMsg = `fc::${errorLine.split('::')[1].replace(/['",]/g, '').split(' ')[0]}`; // isolate fx exception body - } - else if (testLog.join('\n').includes('ctest:')) // ctest exception - { - [errorLine] = testLog.filter(line => line.includes('ctest:')); - output.errorMsg = `ctest:${errorLine.split('ctest:')[1]}`; - } - else if (!isNullOrEmpty(testLog.filter(line => /boost.+exception/.test(line)))) // boost exception - { - [errorLine] = testLog.filter(line => /boost.+exception/.test(line)); - output.errorMsg = `boost: ${errorLine.replace(/[()]/g, '').split(/: (.+)/)[1]}`; // capturing parenthesis, split only at first ' :' - output.stackTrace = testLog.filter(line => /thread-\d+/.test(line))[0].split('thread-')[1].replace(/^\d+/, '').trim().replace(/[[]\d+m$/, ''); // get the bottom of the stack trace - } - else if (/unit[-_. ]+test/.test(test.testName) || /plugin[-_. ]+test/.test(test.testName)) // unit test, application exception - { - if (!isNullOrEmpty(testLog.filter(line => line.includes('exception: ')))) - { - [errorLine] = testLog.filter(line => line.includes('exception: ')); - [, output.errorMsg] = errorLine.replace(/[()]/g, '').split(/: (.+)/); // capturing parenthesis, split only at first ' :' - output.stackTrace = testLog.filter(line => /thread-\d+/.test(line))[0].split('thread-')[1].replace(/^\d+/, '').trim().replace(/[[]\d+m$/, ''); // get the bottom of the stack trace - } - // else uncategorized unit test - } - // else integration test, add cross-referencing code here (or uncategorized) - if (errorLine !== testLog[0]) // get real line number from log file - output.lineNumber = getLineNumber(logText, errorLine, startIndex) + 1; - return output; -} - -// return test metrics given a buildkite job or build -async function testMetrics(buildkiteObject) -{ - if (!isNullOrEmpty(buildkiteObject.type)) // input is a Buildkite job object - { - const job = buildkiteObject; - console.log(`Processing test metrics for "${job.name}"${(inBuildkite) ? '' : ` at ${job.web_url}`}...`); - if (isNullOrEmpty(job.exit_status)) - { - console.log(`${(inBuildkite) ? '+++ :warning: ' : ''}WARNING: "${job.name}" was skipped!`); - return null; - } - // get test results - const logText = await getLog(job); - let testResults; - let xUnit; - try - { - xUnit = await getXML(job); - testResults = parseXunit(xUnit); - } - catch (error) - { - console.log(`XML processing failed for "${job.name}"! Link: ${job.web_url}`); - console.log(JSON.stringify(error)); - testResults = null; - } - finally - { - if (isNullOrEmpty(testResults)) - testResults = parseLog(logText); - } - // get test metrics - const env = await getEnvironment(job); - env.BUILDKITE_REPO = env.BUILDKITE_REPO.replace(new RegExp('^git@github.com:(EOSIO/)?'), '').replace(new RegExp('.git$'), ''); - const metrics = []; - const os = getOS(env); - testResults.forEach((result) => - { - // add test properties - const test = - { - ...result, // add testName, testResult, testTime - agentName: env.BUILDKITE_AGENT_NAME, - agentRole: env.BUILDKITE_AGENT_META_DATA_QUEUE || env.BUILDKITE_AGENT_META_DATA_ROLE, - branch: env.BUILDKITE_BRANCH, - buildNumber: env.BUILDKITE_BUILD_NUMBER, - commit: env.BUILDKITE_COMMIT, - job: env.BUILDKITE_LABEL, - os, - pipeline: env.BUILDKITE_PIPELINE_SLUG, - repo: env.BUILDKITE_REPO, - testTime: parseFloat(result.testTime), - url: job.web_url, - }; - metrics.push({ ...test, ...testDiagnostics(test, logText) }); - }); - return metrics; - } - else if (!isNullOrEmpty(buildkiteObject.number)) // input is a Buildkite build object - { - const build = buildkiteObject; - console.log(`Processing test metrics for ${build.pipeline.slug} build ${build.number}${(inBuildkite) ? '' : ` at ${build.web_url}`}...`); - let metrics = [], promises = []; - // process test metrics - build.jobs.filter(job => job.type === 'script' && /test/.test(job.name.toLowerCase()) && ! /test metrics/.test(job.name.toLowerCase())).forEach((job) => - { - promises.push( - testMetrics(job) - .then((moreMetrics) => { - if (!isNullOrEmpty(moreMetrics)) - metrics = metrics.concat(moreMetrics); - else - console.log(`${(inBuildkite) ? '+++ :warning: ' : ''}WARNING: "${job.name}" metrics are empty!\nmetrics = ${JSON.stringify(moreMetrics)}`); - }).catch((error) => { - console.log(`${(inBuildkite) ? '+++ :no_entry: ' : ''}ERROR: Failed to process test metrics for "${job.name}"! Link: ${job.web_url}`); - console.log(JSON.stringify(error)); - errorCount++; - }) - ); - }); - await Promise.all(promises); - return metrics; - } - else // something else - { - console.log(`${(inBuildkite) ? '+++ :no_entry: ' : ''}ERROR: Buildkite object not recognized or not a test step!`); - console.log(JSON.stringify({buildkiteObject})); - return null; - } -} - -/* main */ -async function main() -{ - if (debug) console.log(`$ ${process.argv.join(' ')}`); - let build, metrics = null; - console.log(`${(inBuildkite) ? '+++ :evergreen_tree: ' : ''}Getting information from enviroment...`); - const buildNumber = process.env.BUILDKITE_BUILD_NUMBER || process.argv[2]; - const pipeline = process.env.BUILDKITE_PIPELINE_SLUG || process.argv[3]; - if (debug) - { - console.log(`BUILDKITE=${process.env.BUILDKITE}`); - console.log(`BUILDKITE_BUILD_NUMBER=${process.env.BUILDKITE_BUILD_NUMBER}`); - console.log(`BUILDKITE_PIPELINE_SLUG=${process.env.BUILDKITE_PIPELINE_SLUG}`); - console.log(' State:') - console.log(`inBuildkite = "${inBuildkite}"`); - console.log(`buildNumber = "${buildNumber}"`); - console.log(`pipeline = "${pipeline}"`); - } - if (isNullOrEmpty(buildNumber) || isNullOrEmpty(pipeline) || isNullOrEmpty(process.env.BUILDKITE_API_KEY)) - { - console.log(`${(inBuildkite) ? '+++ :no_entry: ' : ''}ERROR: Missing required inputs!`); - if (isNullOrEmpty(process.env.BUILDKITE_API_KEY)) console.log('- Buildkite API key, as BUILDKITE_API_KEY environment variable'); - if (isNullOrEmpty(buildNumber)) console.log('- Build Number, as BUILDKITE_BUILD_NUMBER or argument 1'); - if (isNullOrEmpty(pipeline)) console.log('- Pipeline Slug, as BUILDKITE_PIPELINE_SLUG or argument 2'); - errorCount = -1; - } - else - { - console.log(`${(inBuildkite) ? '+++ :bar_chart: ' : ''}Processing test metrics...`); - build = await getBuild(pipeline, buildNumber); - metrics = await testMetrics(build); - console.log('Done processing test metrics.'); - } - console.log(`${(inBuildkite) ? '+++ :pencil: ' : ''}Writing to file...`); - fs.writeFileSync(outputFile, JSON.stringify({ metrics })); - console.log(`Saved metrics to "${outputFile}" in "${process.cwd()}".`); - if (inBuildkite) - { - console.log('+++ :arrow_up: Uploading artifact...'); - execSync(`buildkite-agent artifact upload ${outputFile}`); - } - if (errorCount === 0) - console.log(`${(inBuildkite) ? '+++ :white_check_mark: ' : ''}Done!`); - else - { - console.log(`${(inBuildkite) ? '+++ :warning: ' : ''}Finished with errors.`); - console.log(`Please send automation a link to this job${(isNullOrEmpty(build)) ? '.' : `: ${build.web_url}`}`); - console.log('@kj4ezj or @zreyn on Telegram'); - } - return (inBuildkite) ? process.exit(EXIT_SUCCESS) : process.exit(errorCount); -}; - -main(); \ No newline at end of file diff --git a/.cicd/metrics/test-metrics.tar.gz b/.cicd/metrics/test-metrics.tar.gz deleted file mode 100644 index 2381787ca06196f1b95c636435a77b58ba1cc0aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 96551 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 Date: Sun, 28 Aug 2022 23:05:26 -0400 Subject: [PATCH 02/96] add cicd workflow based on .deb downloading --- .github/workflows/build.yaml | 79 ++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 .github/workflows/build.yaml diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 00000000..79ad1f2c --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,79 @@ +name: "Build & Test" + +on: + push: + branches: + - main + - "release/*" + pull_request: + workflow_dispatch: + inputs: + override-leap-dev: + description: 'Override leap-dev ref' + type: string + override-cdt: + description: 'Override cdt ref' + type: string + +defaults: + run: + shell: bash + +jobs: + build-test: + name: Build & Test + runs-on: ubuntu-20.04 + steps: + - name: Setup leap-dev & cdt versions + id: versions + run: | + if [[ "${{inputs.override-leap-dev}}" == "" ]]; then + echo "::set-output name=leap-dev-ref::*" #default leap-dev ref + else + echo "::set-output name=leap-dev-ref::${{inputs.override-leap-dev}}" + fi + if [[ "${{inputs.override-cdt}}" == "" ]]; then + echo "::set-output name=cdt-ref::*" #defect cdt ref + else + echo "::set-output name=cdt-ref::${{inputs.override-cdt}}" + fi + - name: Download cdt + uses: AntelopeIO/asset-artifact-download-action@v1 + with: + owner: AntelopeIO + repo: cdt + file: 'cdt_.*amd64.deb' + ref: '${{steps.versions.outputs.cdt-ref}}' + prereleases: true + artifact-name: cdt_ubuntu_package_amd64 + token: ${{github.token}} + - name: Download leap-dev + uses: AntelopeIO/asset-artifact-download-action@v1 + with: + owner: AntelopeIO + repo: leap + file: 'leap-dev.*x86_64.deb' + ref: '${{steps.versions.outputs.leap-dev-ref}}' + prereleases: true + artifact-name: leap-dev-ubuntu20-amd64 + container-package: experimental-binaries + token: ${{github.token}} + - name: Install packages + run: | + sudo apt install ./*.deb + sudo apt-get install cmake + rm ./*.deb + - uses: actions/checkout@v3 + with: + path: src + - name: Build & Test + run: | + cmake -S src -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=On + cmake --build build -- -j $(nproc) + tar zcf build.tar.gz build + cd build/tests; ctest --output-on-failure -j $(nproc) + - name: Upload builddir + uses: actions/upload-artifact@v3 + with: + name: builddir + path: build.tar.gz From 280468612f3117902df21517d5e527b4839af46e Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 14 Sep 2022 17:46:12 -0400 Subject: [PATCH 03/96] Change ICON_BASE_URL to a working address --- contracts/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/CMakeLists.txt b/contracts/CMakeLists.txt index f08da324..52a5a6a9 100644 --- a/contracts/CMakeLists.txt +++ b/contracts/CMakeLists.txt @@ -32,7 +32,7 @@ else() # INVALID OR MISMATCH ) endif(VERSION_OUTPUT STREQUAL "MATCH") -set(ICON_BASE_URL "http://127.0.0.1/ricardian_assets/eosio.contracts/icons") +set(ICON_BASE_URL "https://raw.githubusercontent.com/eosnetworkfoundation/eos-system-contracts/main/contracts/icons") set(ACCOUNT_ICON_URI "account.png#3d55a2fc3a5c20b456f5657faf666bc25ffd06f4836c5e8256f741149b0b294f") set(ADMIN_ICON_URI "admin.png#9bf1cec664863bd6aaac0f814b235f8799fb02c850e9aa5da34e8a004bd6518e") @@ -50,4 +50,4 @@ add_subdirectory(eosio.system) add_subdirectory(eosio.token) add_subdirectory(eosio.wrap) -add_subdirectory(test_contracts) \ No newline at end of file +add_subdirectory(test_contracts) From b62c318abb07d77aabb361acd0c756395b2c5282 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 20 Sep 2022 16:54:45 -0400 Subject: [PATCH 04/96] Replace usage of deque and map with vector --- .../include/eosio.system/eosio.system.hpp | 13 +++++-- contracts/eosio.system/src/rex.cpp | 37 +++++++++++++------ 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 6befec16..4c2574fa 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -435,12 +435,19 @@ namespace eosiosystem { typedef eosio::multi_index< "rexretpool"_n, rex_return_pool > rex_return_pool_table; + struct pair_time_point_sec_int64 { + time_point_sec first; + int64_t second; + + EOSLIB_SERIALIZE(pair_time_point_sec_int64, (first)(second)); + }; + // `rex_return_buckets` structure underlying the rex return buckets table. A rex return buckets table is defined by: // - `version` defaulted to zero, // - `return_buckets` buckets of proceeds accumulated in 12-hour intervals struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_buckets { - uint8_t version = 0; - std::map return_buckets; + uint8_t version = 0; + std::vector return_buckets; // sorted by first field uint64_t primary_key()const { return 0; } }; @@ -473,7 +480,7 @@ namespace eosiosystem { asset vote_stake; asset rex_balance; int64_t matured_rex = 0; - std::deque> rex_maturities; /// REX daily maturity buckets + std::vector rex_maturities; /// REX daily maturity buckets uint64_t primary_key()const { return owner.value; } }; diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 648239ef..5651b2b7 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -309,7 +309,7 @@ namespace eosiosystem { if ( !rb.rex_maturities.empty() && rb.rex_maturities.back().first == maturity ) { rb.rex_maturities.back().second += rex.amount; } else { - rb.rex_maturities.emplace_back( maturity, rex.amount ); + rb.rex_maturities.emplace_back( pair_time_point_sec_int64 { maturity, rex.amount } ); } }); put_rex_savings( bitr, rex_in_savings - rex.amount ); @@ -664,7 +664,25 @@ namespace eosiosystem { if ( new_return_bucket ) { _rexretbuckets.modify( ret_buckets_elem, same_payer, [&]( auto& rb ) { - rb.return_buckets[new_bucket_time] = new_bucket_rate; + auto& return_buckets = rb.return_buckets; + auto iter = return_buckets.begin(); + auto added = false; + // sort by first + while ( iter != return_buckets.end() ) { + if ( new_bucket_time < iter->first ) { + return_buckets.insert( iter, pair_time_point_sec_int64 { new_bucket_time, new_bucket_rate }); + added = true; + break; + } else if ( new_bucket_time == iter->first ) { + *iter = pair_time_point_sec_int64 { new_bucket_time, new_bucket_rate }; + added = true; + break; + } + ++iter; + } + if ( !added ) { + return_buckets.emplace_back( pair_time_point_sec_int64 { new_bucket_time, new_bucket_rate }); + } }); } } @@ -677,14 +695,11 @@ namespace eosiosystem { auto& return_buckets = rb.return_buckets; auto iter = return_buckets.begin(); while ( iter != return_buckets.end() && iter->first <= time_threshold ) { - auto next = iter; - ++next; const uint32_t overtime = get_elapsed_intervals( effective_time, iter->first + seconds(rex_return_pool::total_intervals * rex_return_pool::dist_interval) ); surplus += iter->second * overtime; expired_rate += iter->second; - return_buckets.erase(iter); - iter = next; + iter = return_buckets.erase(iter); } }); @@ -975,7 +990,7 @@ namespace eosiosystem { _rexbalance.modify( bitr, same_payer, [&]( auto& rb ) { while ( !rb.rex_maturities.empty() && rb.rex_maturities.front().first <= now ) { rb.matured_rex += rb.rex_maturities.front().second; - rb.rex_maturities.pop_front(); + rb.rex_maturities.erase(rb.rex_maturities.begin()); } }); } @@ -995,10 +1010,10 @@ namespace eosiosystem { rb.matured_rex = rex_in_sell_order.amount; while ( !rb.rex_maturities.empty() ) { total += rb.rex_maturities.front().second; - rb.rex_maturities.pop_front(); + rb.rex_maturities.erase(rb.rex_maturities.begin()); } if ( total > 0 ) { - rb.rex_maturities.emplace_back( get_rex_maturity(), total ); + rb.rex_maturities.emplace_back( pair_time_point_sec_int64{ get_rex_maturity(), total } ); } }); put_rex_savings( bitr, rex_in_savings ); @@ -1138,7 +1153,7 @@ namespace eosiosystem { if ( !rb.rex_maturities.empty() && rb.rex_maturities.back().first == maturity ) { rb.rex_maturities.back().second += rex_received.amount; } else { - rb.rex_maturities.emplace_back( maturity, rex_received.amount ); + rb.rex_maturities.emplace_back( pair_time_point_sec_int64 { maturity, rex_received.amount } ); } }); put_rex_savings( bitr, rex_in_savings ); @@ -1183,7 +1198,7 @@ namespace eosiosystem { if ( !rb.rex_maturities.empty() && rb.rex_maturities.back().first == end_of_days ) { rb.rex_maturities.back().second += rex; } else { - rb.rex_maturities.emplace_back( end_of_days, rex ); + rb.rex_maturities.emplace_back( pair_time_point_sec_int64{ end_of_days, rex } ); } }); } From fe3e582a98bc3ced21d4178571e0fbc534809ae8 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 20 Sep 2022 22:34:56 -0400 Subject: [PATCH 05/96] simplify return_buckets sorting and avoid erase iterator inside loop --- contracts/eosio.system/src/rex.cpp | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 5651b2b7..99542c13 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -664,24 +664,13 @@ namespace eosiosystem { if ( new_return_bucket ) { _rexretbuckets.modify( ret_buckets_elem, same_payer, [&]( auto& rb ) { - auto& return_buckets = rb.return_buckets; - auto iter = return_buckets.begin(); - auto added = false; - // sort by first - while ( iter != return_buckets.end() ) { - if ( new_bucket_time < iter->first ) { - return_buckets.insert( iter, pair_time_point_sec_int64 { new_bucket_time, new_bucket_rate }); - added = true; - break; - } else if ( new_bucket_time == iter->first ) { - *iter = pair_time_point_sec_int64 { new_bucket_time, new_bucket_rate }; - added = true; - break; - } - ++iter; - } - if ( !added ) { - return_buckets.emplace_back( pair_time_point_sec_int64 { new_bucket_time, new_bucket_rate }); + auto iter = std::lower_bound(rb.return_buckets.begin(), rb.return_buckets.end(), new_bucket_time, [](const pair_time_point_sec_int64& bucket, time_point_sec first) { + return bucket.first < first; + }); + if ((iter != rb.return_buckets.end()) && (iter->first == new_bucket_time)) { + iter->second = new_bucket_rate; + } else { + rb.return_buckets.insert(iter, pair_time_point_sec_int64{new_bucket_time, new_bucket_rate}); } }); } @@ -694,13 +683,13 @@ namespace eosiosystem { _rexretbuckets.modify( ret_buckets_elem, same_payer, [&]( auto& rb ) { auto& return_buckets = rb.return_buckets; auto iter = return_buckets.begin(); - while ( iter != return_buckets.end() && iter->first <= time_threshold ) { + for (; iter != return_buckets.end() && iter->first <= time_threshold; ++iter) { const uint32_t overtime = get_elapsed_intervals( effective_time, iter->first + seconds(rex_return_pool::total_intervals * rex_return_pool::dist_interval) ); surplus += iter->second * overtime; expired_rate += iter->second; - iter = return_buckets.erase(iter); } + return_buckets.erase(return_buckets.begin(), iter); }); _rexretpool.modify( ret_pool_elem, same_payer, [&]( auto& rp ) { From 7dbbb28e917a795f823a71910d21422a355049ce Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 27 Sep 2022 09:57:08 -0400 Subject: [PATCH 06/96] bump version to 3.1.1 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c2024914..81f6f130 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(eosio_contracts) set(VERSION_MAJOR 3) set(VERSION_MINOR 1) -set(VERSION_PATCH 0) +set(VERSION_PATCH 1) #set(VERSION_SUFFIX rc2) if(VERSION_SUFFIX) From 5b6c7a72cd54915e1a190764f7bd988ecbce8782 Mon Sep 17 00:00:00 2001 From: Eric Passmore Date: Thu, 4 Aug 2022 19:13:31 -0700 Subject: [PATCH 07/96] documentation fixes to power developer doc portal **Summary** * Reference to DUNE in place of old instructions * Removed meta-data link tag * Replace github references to EOS Network Foundation * Replace references to old documentation portal * Fix broken links **Files Changed**: Markdown files under `docs`
The 03_build_and_deploy document was three years old. The compilation instructions were out of date. This page now points to the DUNE README The developer documentation portal is powered by markdown files. We use MDX as the parsing engine. Removed *link-text* meta data at the top of the page because it caused formatting issues. Many times we found documentation pointing to old repositories that had not been updated in years. We updated the links and pointed to repositories that are better maintained. We made sure links to the documentation portal did not leak back to older, previous versions. We found relative links that no longer existed. We made sure to point the links to best location. Sometimes the links broke because were missing a key file extension. We made sure to add back the file extension. **Note:** This is essentially a no-op; however summarizing here for anyone following the commit history. Glossary and Protocol Guides were added and removed during the course of development. We had added a Glossary and Protocol Guides , and we decided to utilize the welcome repository as the source for both.
Squashed commit of the following: commit cfdf8461f05a8e703112081f6e57278fcabb4504 Author: Eric Passmore Date: Thu Aug 4 12:47:37 2022 -0700 fixed relative path hyphen not underscore commit 6724f3d277d2098eb060cd050619d56653ead0b4 Author: Eric Passmore Date: Thu Aug 4 11:02:32 2022 -0700 rm eos.io references commit b783c12263164e6b5a32413f9e0ff984c4a82b39 Author: Eric Passmore Date: Thu Aug 4 10:59:05 2022 -0700 removed eos.io references commit c6d6258827bf281f526a5b904433711aae66c0cd Author: Eric Passmore Date: Tue Aug 2 14:41:39 2022 -0700 fixed broken links commit d1758d7350a4b60685436c193468d2df44e4b00f Author: Eric Passmore Date: Tue Aug 2 10:45:00 2022 -0700 updating paths to docs.eosnetwork.com --- docs/01_key-concepts/01_system.md | 3 +- docs/01_key-concepts/02_ram.md | 13 +-- docs/01_key-concepts/03_cpu.md | 4 +- docs/01_key-concepts/04_net.md | 2 - docs/01_key-concepts/05_stake.md | 7 +- docs/01_key-concepts/06_vote.md | 1 - docs/03_build-and-deploy.md | 80 +------------------ ...ow-to-create-issue-and-transfer-a-token.md | 6 +- ...08_configure-use-powerup-resource-model.md | 6 +- 9 files changed, 18 insertions(+), 104 deletions(-) diff --git a/docs/01_key-concepts/01_system.md b/docs/01_key-concepts/01_system.md index eb14bb6d..1de221ce 100644 --- a/docs/01_key-concepts/01_system.md +++ b/docs/01_key-concepts/01_system.md @@ -1,9 +1,8 @@ --- content_title: System contracts, system accounts, privileged accounts -link_text: System contracts, system accounts, privileged accounts --- -At the genesis of an EOSIO-based blockchain, there is only one account present, `eosio` account, which is the main `system account`. There are other `system account`s, created by `eosio` account, which control specific actions of the `system contract`s [mentioned in previous section](../#system-contracts-defined-in-eosio.contracts). __Note__ the terms `system contract` and `system account`. `Privileged accounts` are accounts which can execute a transaction while skipping the standard authorization check. To ensure that this is not a security hole, the permission authority over these accounts is granted to `eosio.prods` system account. +At the genesis of an EOSIO-based blockchain, there is only one account present, `eosio` account, which is the main `system account`. There are other `system account`s, created by `eosio` account, which control specific actions of the `system contract`s [mentioned in previous section](/smart-contracts/mandel-contracts/about_system_contracts.md/#system-contracts-defined-in-eosio.contracts). __Note__ the terms `system contract` and `system account`. `Privileged accounts` are accounts which can execute a transaction while skipping the standard authorization check. To ensure that this is not a security hole, the permission authority over these accounts is granted to `eosio.prods` system account. As you just learned the relation between a `system account` and a `system contract`, it is also important to remember that not all system accounts contain a system contract, but each system account has important roles in the blockchain functionality, as follows: diff --git a/docs/01_key-concepts/02_ram.md b/docs/01_key-concepts/02_ram.md index a9d96fcd..27496212 100644 --- a/docs/01_key-concepts/02_ram.md +++ b/docs/01_key-concepts/02_ram.md @@ -1,6 +1,5 @@ --- content_title: RAM as system resource -link_text: RAM as system resource --- ## What is RAM @@ -9,13 +8,9 @@ RAM is the memory, the storage space, where the blockchain stores data. If your ### Related documentation articles -- Multi-index table [explainer documentation page](https://developers.eos.io/manuals/eosio.cdt/latest/group__multiindex) +- Multi-index table [reference documentation page](https://docs.eosnetwork.com/reference/mandel-cdt/classeosio_1_1multi__index.html) -- Multi-index table [how to documentation page](https://developers.eos.io/manuals/eosio.cdt/latest/how-to-guides/multi-index) - -- Singleton [reference documentation page](https://developers.eos.io/manuals/eosio.cdt/latest/group__singleton/#singleton-table) - -- Singleton [how to documentation page](https://developers.eos.io/manuals/eosio.cdt/latest/how-to-guides/multi-index/how-to-define-a-singleton) +- Singleton [reference documentation page](https://docs.eosnetwork.com/reference/mandel-cdt/classeosio_1_1singleton.html) ## RAM High Performance @@ -34,6 +29,6 @@ RAM is a very important system resource because of the following reasons: - A portion of the occupied RAM is freed by the smart contract. - More RAM is allocated to the smart contract account through the RAM buying process. -RAM is a scarce resource priced according to the unique Bancor liquidity algorithm which is implemented in the system contract [here](https://github.com/EOSIO/eos/blob/905e7c85714aee4286fa180ce946f15ceb4ce73c/contracts/eosio.system/exchange_state.hpp). +RAM is a scarce resource priced according to the unique Bancor liquidity algorithm which is implemented in the system contract [here](http://docs.eosnetwork.com/reference/mandel-contracts/structeosiosystem_1_1exchange__state.html). -The RAM system resource must be purchased using the system token. Refer to the [cleos manual](https://developers.eos.io/manuals/eos/v2.0/cleos/how-to-guides/how-to-buy-ram) to learn how to buy RAM via the command line interface. +The RAM system resource must be purchased using the system token. Refer to the [cleos manual](/developer-tools/02_cleos/02_how-to-guides/how-to-buy-ram.md) to learn how to buy RAM via the command line interface. diff --git a/docs/01_key-concepts/03_cpu.md b/docs/01_key-concepts/03_cpu.md index 6f60577f..147538d6 100644 --- a/docs/01_key-concepts/03_cpu.md +++ b/docs/01_key-concepts/03_cpu.md @@ -1,10 +1,8 @@ --- content_title: CPU as system resource -link_text: CPU as system resource --- The system resource CPU provides processing power to blockchain accounts. The amount of CPU an account has is measured in microseconds and it is referred to as `cpu bandwidth` on the `cleos get account` command output. The `cpu bandwidth` represents the amount of processing time an account has at its disposal when actions sent to its contract are executed by the blockchain. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient CPU must be staked in order for transactions to complete. For more details about EOSIO staking refer to the following: -* [Staking Mechanism](https://developers.eos.io/welcome/latest/overview/technical_features#staking-mechanism). -* [Staking on EOSIO-based blockchains](05_stake.md) \ No newline at end of file +* [Staking on EOSIO-based blockchains](05_stake.md) diff --git a/docs/01_key-concepts/04_net.md b/docs/01_key-concepts/04_net.md index f4f5b146..1bd9b9a3 100644 --- a/docs/01_key-concepts/04_net.md +++ b/docs/01_key-concepts/04_net.md @@ -1,10 +1,8 @@ --- content_title: NET as system resource -link_text: NET as system resource --- NET, as CPU and RAM, is a very important system resource in EOSIO-based blockchains. NET is measured by the byte size of the transactions saved in the blockchain database and it is referred to as `net bandwidth` on the cleos get account command result. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient NET must be staked in order for transactions to complete. For more details about EOSIO staking refer to the following: -* [Staking Mechanism](https://developers.eos.io/welcome/latest/overview/technical_features#staking-mechanism). * [Staking on EOSIO-based blockchains](05_stake.md) diff --git a/docs/01_key-concepts/05_stake.md b/docs/01_key-concepts/05_stake.md index d8904d9d..7561cfaf 100644 --- a/docs/01_key-concepts/05_stake.md +++ b/docs/01_key-concepts/05_stake.md @@ -1,6 +1,5 @@ --- content_title: Staking on EOSIO-based blockchains -link_text: Staking on EOSIO-based blockchains --- ## System Resources @@ -17,7 +16,7 @@ EOSIO-based blockchain accounts need sufficient system resources, RAM, CPU and N ### Stake NET and CPU -The CPU and NET system resources are allocated by the account owner via the staking mechanism. Refer to the [cleos manual](https://developers.eos.io/manuals/eos/v2.0/cleos/how-to-guides/how-to-stake-resource) on how to do it via the command line interface. +The CPU and NET system resources are allocated by the account owner via the staking mechanism. Refer to the [cleos manual](/developer-tools/02_cleos/02_how-to-guides/how-to-stake-resource.md) on how to do it via the command line interface. You will also find that staking/unstaking is at times referred to as delegating/undelegating. The economics of staking is also to provably commit to a promise that you will hold the staked tokens, either for NET or CPU, for a pre-established period of time, in spite of inflation caused by minting new tokens in order to reward BPs for their services every 24 hours. @@ -28,7 +27,7 @@ If an account consumes all its allocated CPU and NET resources, it has two optio * It can wait for the blockchain to replenish the consumed resources. You can read more details below about the [system resources replenish algorithm].(05_stake.md#System-Resources-Replenish-Algorithm). * It can allocate more resources through the staking mechanism. -When an account uses the allocated resources, the amount that can be used in one transaction is limited by predefine [maximum CPU](https://developers.eos.io/manuals/eosio.cdt/latest/structeosio_1_1blockchain__parameters#variable-max_transaction_cpu_usage), [minimum CPU](https://developers.eos.io/manuals/eosio.cdt/latest/structeosio_1_1blockchain__parameters#variable-min_transaction_cpu_usage), and [maximum NET](https://developers.eos.io/manuals/eosio.cdt/latest/structeosio_1_1blockchain__parameters#variable-max_transaction_net_usage) limits. Transactions executed by the blockchain contain one or more actions, and each transaction must consume an amount of CPU and NET which is in the limits defined by the aforementioned blockchain settings. +When an account uses the allocated resources, the amount that can be used in one transaction is limited by predefine [maximum CPU](http://docs.eosnetwork.com/reference/mandel-cdt/structeosio_1_1blockchain__parameters.html#a59893f31083ea0239eff0fdb47a3e9a2), [minimum CPU](http://docs.eosnetwork.com/reference/mandel-cdt/structeosio_1_1blockchain__parameters.html#a5c15c7c28e28d93183e85639ddd3dd83), and [maximum NET](http://docs.eosnetwork.com/reference/mandel-cdt/structeosio_1_1blockchain__parameters.html#aaffe7d6c7437826f208c68e9ee2acf65) limits. Transactions executed by the blockchain contain one or more actions, and each transaction must consume an amount of CPU and NET which is in the limits defined by the aforementioned blockchain settings. #### System Resources Replenish Algorithm @@ -47,4 +46,4 @@ This formula has the following outcomes: ### Buy RAM -The RAM resource must be bought using the system token. Refer to the [cleos manual](https://developers.eos.io/manuals/eos/v2.0/cleos/how-to-guides/how-to-buy-ram) to learn how to do it via the command line interface. When an account consumes all its allocated RAM can not store any additional information on the blockchain database until it frees some of the occupied RAM or more RAM is allocated to the account through the RAM buying process. +The RAM resource must be bought using the system token. Refer to the [cleos manual](/developer-tools/02_cleos/02_how-to-guides/how-to-buy-ram.md) to learn how to do it via the command line interface. When an account consumes all its allocated RAM can not store any additional information on the blockchain database until it frees some of the occupied RAM or more RAM is allocated to the account through the RAM buying process. diff --git a/docs/01_key-concepts/06_vote.md b/docs/01_key-concepts/06_vote.md index 4aa8ba6b..41840c65 100644 --- a/docs/01_key-concepts/06_vote.md +++ b/docs/01_key-concepts/06_vote.md @@ -1,6 +1,5 @@ --- content_title: Voting on EOSIO-based blockchains -link_text: Voting on EOSIO-based blockchains --- In a EOSIO-based network the blockchain is kept alive by nodes which are interconnected between each other, communicating with each other via peer to peer protocols. Some of these nodes are elected, via a voting process, by the token holders to be producer nodes. They produce blocks, validate them and reach consensus on what transactions are allowed in each block, their order, and what blocks are finalized and stored forever in the blockchain. This way the governance, the mechanism by which collective decisions are made, of the blockchain is achieved through the 21 active block producers which are appointed by token holders' votes. It's the 21 active block producers which continuously create the blockchain by creating blocks, and securing them by validating them, and reaching consensus. Consensus is reached when 2/3+1 active block producers agree on validity of a block, that is all transactions contained in it and their order. The 21 producers is the default value however it can be configured to be higher or smaller to meet each business case requirements. diff --git a/docs/03_build-and-deploy.md b/docs/03_build-and-deploy.md index b2db104f..cf56d5f8 100644 --- a/docs/03_build-and-deploy.md +++ b/docs/03_build-and-deploy.md @@ -1,83 +1,9 @@ --- content_title: How to build eosio.contracts -link_text: How to build eosio.contracts --- ## Preconditions -Ensure an appropriate version of `eosio.cdt` is installed. Installing `eosio.cdt` from binaries is sufficient, follow the [`eosio.cdt` installation instructions steps](https://developers.eos.io/manuals/eosio.cdt/latest/installation) to install it. To verify if you have `eosio.cdt` installed and its version run the following command +This step references [DUNE (Docker Utilities for Node Execution)](/developer-tools/DUNE/index.md) -```sh -eosio-cpp -v -``` - -### Build contracts using the build script - -#### To build contracts alone -Run the `build.sh` script in the top directory to build all the contracts. - -#### To build the contracts and unit tests -1. Ensure an appropriate version of `eosio` has been built from source and installed. Installing `eosio` from binaries `is not` sufficient. You can find instructions on how to do it [here](https://developers.eos.io/manuals/eos/latest/install/build-from-source) in section `Building from Sources`. -2. Run the `build.sh` script in the top directory with the `-t` flag to build all the contracts and the unit tests for these contracts. - -### Build contracts manually - -To build the `eosio.contracts` execute the following commands. - -On all platforms except macOS: -```sh -cd you_local_path_to/eosio.contracts/ -rm -fr build -mkdir build -cd build -cmake .. -make -j$( nproc ) -cd .. -``` - -For macOS: -```sh -cd you_local_path_to/eosio.contracts/ -rm -fr build -mkdir build -cd build -cmake .. -make -j$(sysctl -n hw.ncpu) -cd .. -``` - -### After build: -* If the build was configured to also build unit tests, the unit tests executable is placed in the _build/tests_ folder and is named __unit_test__. -* The contracts (both `.wasm` and `.abi` files) are built into their corresponding _build/contracts/\_ folder. -* Finally, simply use __cleos__ to _set contract_ by pointing to the previously mentioned directory for the specific contract. - -# How to deploy the eosio.contracts - -## To deploy eosio.bios contract execute the following command: -Let's assume your account name to which you want to deploy the contract is `testerbios` -``` -cleos set contract testerbios you_local_path_to/eosio.contracts/build/contracts/eosio.bios/ -p testerbios -``` - -## To deploy eosio.msig contract execute the following command: -Let's assume your account name to which you want to deploy the contract is `testermsig` -``` -cleos set contract testermsig you_local_path_to/eosio.contracts/build/contracts/eosio.msig/ -p testermsig -``` - -## To deploy eosio.system contract execute the following command: -Let's assume your account name to which you want to deploy the contract is `testersystem` -``` -cleos set contract testersystem you_local_path_to/eosio.contracts/build/contracts/eosio.system/ -p testersystem -``` - -## To deploy eosio.token contract execute the following command: -Let's assume your account name to which you want to deploy the contract is `testertoken` -``` -cleos set contract testertoken you_local_path_to/eosio.contracts/build/contracts/eosio.token/ -p testertoken -``` - -## To deploy eosio.wrap contract execute the following command: -Let's assume your account name to which you want to deploy the contract is `testerwrap` -``` -cleos set contract testerwrap you_local_path_to/eosio.contracts/build/contracts/eosio.wrap/ -p testerwrap -``` \ No newline at end of file +## Build contracts +Follow the [contract building steps](/developer-tools/DUNE/index.md#cmake-contract-development) in the DUNE Guide. diff --git a/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md b/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md index 0a2bf436..2f092c19 100644 --- a/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md +++ b/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md @@ -13,7 +13,7 @@ cd CONTRACTS_DIR Pull the source ```sh -git clone https://github.com/EOSIO/eosio.contracts --branch master --single-branch +git clone https://github.com/eosnetworkfoundation/mandel-contracts --branch master --single-branch ``` ```sh @@ -106,7 +106,7 @@ executed transaction: 60d334850151cb95c35fe31ce2e8b536b51441c5fd4c3f2fea98edcc6d # bob <= eosio.token::transfer {"from":"eosio","to":"bob","quantity":"25.0000 SYS","memo":"m"} warning: transaction executed locally, but may not be confirmed by the network yet ] ``` -Now check if "bob" got the tokens using [cleos get currency balance](https://developers.eos.io/manuals/eos/latest/cleos/command-reference/get/currency-balance) +Now check if "bob" got the tokens using [cleos get currency balance](/developer-tools/02_cleos/03_command-reference/get/currency-balance.md) ```shell cleos get currency balance eosio.token bob SYS @@ -126,4 +126,4 @@ cleos get currency balance eosio.token eosio SYS Result: ```console 75.00 SYS -``` \ No newline at end of file +``` diff --git a/docs/04_guides/08_configure-use-powerup-resource-model.md b/docs/04_guides/08_configure-use-powerup-resource-model.md index 35a6c933..5bcdedce 100644 --- a/docs/04_guides/08_configure-use-powerup-resource-model.md +++ b/docs/04_guides/08_configure-use-powerup-resource-model.md @@ -123,7 +123,7 @@ struct powerup_state { ``` ### Preparation for Upgrade -1. Build [eosio.contracts](https://github.com/EOSIO/eosio.contracts) with `powerup` code. Version **1.9.x** or greater . +1. Build [mandel contracts](https://github.com/eosnetworkfoundation/mandel-contracts) with `powerup` code. Version **1.9.x** or greater . 2. Deploy eosio.system contract to `eosio`. 3. Create account `eosio.reserv` and ensure the account has enough RAM, at least 4 KiB. 4. Deploy `powup.results.abi` to `eosio.reserv` account using `setabi`. The ABI can be found in the `build/contracts/eosio.system/.powerup/` directory. @@ -232,7 +232,7 @@ executed transaction: 82b7124601612b371b812e3bf65cf63bb44616802d3cd33a2c0422b583 # user <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 TST","memo":"transfer from user to eosio.rex"} # eosio.rex <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 TST","memo":"transfer from user to eosio.rex"} ``` -You can see how much NET and CPU weight was received as well as the fee by looking at the `eosio.reserv::powupresult` informational action. +You can see how much NET and CPU weight was received as well as the fee by looking at the `eosio.reserv::powupresult` informational action. *It is worth mentioning that the network being used for the example has not fully transitioned so the available resources are minimal therefore 1% of the resources are quite expensive. As the system continues the transition more resources are available to the `PowerUp` resource model and will become more affordable.* @@ -268,4 +268,4 @@ cleos push action eosio powerupexec '[user, 2]' -p user executed transaction: 93ab4ac900a7902e4e59e5e925e8b54622715328965150db10774aa09855dc98 104 bytes 363 us # eosio <= eosio::powerupexec {"user":"user","max":2} warning: transaction executed locally, but may not be confirmed by the network yet ] -``` \ No newline at end of file +``` From deb21cf7a0d018b4d7243e6a96c7c96dbfc52a56 Mon Sep 17 00:00:00 2001 From: Luis Date: Wed, 5 Oct 2022 14:06:51 -0400 Subject: [PATCH 08/96] fix anchor link to index file :doc --- docs/01_key-concepts/01_system.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/01_key-concepts/01_system.md b/docs/01_key-concepts/01_system.md index 1de221ce..ef3c3ae6 100644 --- a/docs/01_key-concepts/01_system.md +++ b/docs/01_key-concepts/01_system.md @@ -2,7 +2,7 @@ content_title: System contracts, system accounts, privileged accounts --- -At the genesis of an EOSIO-based blockchain, there is only one account present, `eosio` account, which is the main `system account`. There are other `system account`s, created by `eosio` account, which control specific actions of the `system contract`s [mentioned in previous section](/smart-contracts/mandel-contracts/about_system_contracts.md/#system-contracts-defined-in-eosio.contracts). __Note__ the terms `system contract` and `system account`. `Privileged accounts` are accounts which can execute a transaction while skipping the standard authorization check. To ensure that this is not a security hole, the permission authority over these accounts is granted to `eosio.prods` system account. +At the genesis of an EOSIO-based blockchain, there is only one account present, `eosio` account, which is the main `system account`. There are other `system account`s, created by `eosio` account, which control specific actions of the `system contract`s [mentioned in previous section](/index.md#system-contracts-defined-in-eosio.contracts). __Note__ the terms `system contract` and `system account`. `Privileged accounts` are accounts which can execute a transaction while skipping the standard authorization check. To ensure that this is not a security hole, the permission authority over these accounts is granted to `eosio.prods` system account. As you just learned the relation between a `system account` and a `system contract`, it is also important to remember that not all system accounts contain a system contract, but each system account has important roles in the blockchain functionality, as follows: From 9c462ac95f80489c6094fd7959d2f590eb01ba92 Mon Sep 17 00:00:00 2001 From: Luis Date: Wed, 5 Oct 2022 15:37:29 -0400 Subject: [PATCH 09/96] fix broken, inaccurate, or inapplicable links :doc --- docs/01_key-concepts/02_ram.md | 8 ++++---- docs/01_key-concepts/03_cpu.md | 1 + docs/01_key-concepts/04_net.md | 1 + docs/01_key-concepts/05_stake.md | 6 +++--- .../05_how-to-create-issue-and-transfer-a-token.md | 4 ++-- docs/04_guides/08_configure-use-powerup-resource-model.md | 2 +- 6 files changed, 12 insertions(+), 10 deletions(-) diff --git a/docs/01_key-concepts/02_ram.md b/docs/01_key-concepts/02_ram.md index 27496212..721ad64b 100644 --- a/docs/01_key-concepts/02_ram.md +++ b/docs/01_key-concepts/02_ram.md @@ -8,9 +8,9 @@ RAM is the memory, the storage space, where the blockchain stores data. If your ### Related documentation articles -- Multi-index table [reference documentation page](https://docs.eosnetwork.com/reference/mandel-cdt/classeosio_1_1multi__index.html) +- Multi-index table [reference documentation page](http://docs.eosnetwork.com/cdt/latest/reference/Modules/group__multiindex) -- Singleton [reference documentation page](https://docs.eosnetwork.com/reference/mandel-cdt/classeosio_1_1singleton.html) +- Singleton [reference documentation page](https://docs.eosnetwork.com/cdt/latest/reference/Classes/classeosio_1_1singleton) ## RAM High Performance @@ -29,6 +29,6 @@ RAM is a very important system resource because of the following reasons: - A portion of the occupied RAM is freed by the smart contract. - More RAM is allocated to the smart contract account through the RAM buying process. -RAM is a scarce resource priced according to the unique Bancor liquidity algorithm which is implemented in the system contract [here](http://docs.eosnetwork.com/reference/mandel-contracts/structeosiosystem_1_1exchange__state.html). +RAM is a scarce resource priced according to the unique Bancor liquidity algorithm which is implemented in the system contract [here](https://docs.eosnetwork.com/system-contracts/latest/reference/Classes/structeosiosystem_1_1exchange__state). -The RAM system resource must be purchased using the system token. Refer to the [cleos manual](/developer-tools/02_cleos/02_how-to-guides/how-to-buy-ram.md) to learn how to buy RAM via the command line interface. +The RAM system resource must be purchased using the system token. Refer to the [cleos manual](https://docs.eosnetwork.com/leap/latest/cleos/how-to-guides/how-to-buy-ram) to learn how to buy RAM via the command line interface. diff --git a/docs/01_key-concepts/03_cpu.md b/docs/01_key-concepts/03_cpu.md index 147538d6..f8506641 100644 --- a/docs/01_key-concepts/03_cpu.md +++ b/docs/01_key-concepts/03_cpu.md @@ -5,4 +5,5 @@ content_title: CPU as system resource The system resource CPU provides processing power to blockchain accounts. The amount of CPU an account has is measured in microseconds and it is referred to as `cpu bandwidth` on the `cleos get account` command output. The `cpu bandwidth` represents the amount of processing time an account has at its disposal when actions sent to its contract are executed by the blockchain. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient CPU must be staked in order for transactions to complete. For more details about EOSIO staking refer to the following: +* [Staking Mechanism](https://developers.eos.io/welcome/latest/overview/technical_features#staking-mechanism). * [Staking on EOSIO-based blockchains](05_stake.md) diff --git a/docs/01_key-concepts/04_net.md b/docs/01_key-concepts/04_net.md index 1bd9b9a3..1b68710b 100644 --- a/docs/01_key-concepts/04_net.md +++ b/docs/01_key-concepts/04_net.md @@ -5,4 +5,5 @@ content_title: NET as system resource NET, as CPU and RAM, is a very important system resource in EOSIO-based blockchains. NET is measured by the byte size of the transactions saved in the blockchain database and it is referred to as `net bandwidth` on the cleos get account command result. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient NET must be staked in order for transactions to complete. For more details about EOSIO staking refer to the following: +* [Staking Mechanism](https://developers.eos.io/welcome/latest/overview/technical_features#staking-mechanism). * [Staking on EOSIO-based blockchains](05_stake.md) diff --git a/docs/01_key-concepts/05_stake.md b/docs/01_key-concepts/05_stake.md index 7561cfaf..6ebbbb93 100644 --- a/docs/01_key-concepts/05_stake.md +++ b/docs/01_key-concepts/05_stake.md @@ -16,7 +16,7 @@ EOSIO-based blockchain accounts need sufficient system resources, RAM, CPU and N ### Stake NET and CPU -The CPU and NET system resources are allocated by the account owner via the staking mechanism. Refer to the [cleos manual](/developer-tools/02_cleos/02_how-to-guides/how-to-stake-resource.md) on how to do it via the command line interface. +The CPU and NET system resources are allocated by the account owner via the staking mechanism. Refer to the [cleos manual](https://docs.eosnetwork.com/leap/latest/cleos/how-to-guides/how-to-stake-resource) on how to do it via the command line interface. You will also find that staking/unstaking is at times referred to as delegating/undelegating. The economics of staking is also to provably commit to a promise that you will hold the staked tokens, either for NET or CPU, for a pre-established period of time, in spite of inflation caused by minting new tokens in order to reward BPs for their services every 24 hours. @@ -27,7 +27,7 @@ If an account consumes all its allocated CPU and NET resources, it has two optio * It can wait for the blockchain to replenish the consumed resources. You can read more details below about the [system resources replenish algorithm].(05_stake.md#System-Resources-Replenish-Algorithm). * It can allocate more resources through the staking mechanism. -When an account uses the allocated resources, the amount that can be used in one transaction is limited by predefine [maximum CPU](http://docs.eosnetwork.com/reference/mandel-cdt/structeosio_1_1blockchain__parameters.html#a59893f31083ea0239eff0fdb47a3e9a2), [minimum CPU](http://docs.eosnetwork.com/reference/mandel-cdt/structeosio_1_1blockchain__parameters.html#a5c15c7c28e28d93183e85639ddd3dd83), and [maximum NET](http://docs.eosnetwork.com/reference/mandel-cdt/structeosio_1_1blockchain__parameters.html#aaffe7d6c7437826f208c68e9ee2acf65) limits. Transactions executed by the blockchain contain one or more actions, and each transaction must consume an amount of CPU and NET which is in the limits defined by the aforementioned blockchain settings. +When an account uses the allocated resources, the amount that can be used in one transaction is limited by predefine [maximum CPU](https://docs.eosnetwork.com/cdt/latest/reference/Classes/structeosio_1_1blockchain__parameters#variable-max-transaction-cpu-usage), [minimum CPU](https://docs.eosnetwork.com/cdt/latest/reference/Classes/structeosio_1_1blockchain__parameters#variable-min-transaction-cpu-usage), and [maximum NET](https://docs.eosnetwork.com/cdt/latest/reference/Classes/structeosio_1_1blockchain__parameters#variable-max-transaction-net-usage) limits. Transactions executed by the blockchain contain one or more actions, and each transaction must consume an amount of CPU and NET which is in the limits defined by the aforementioned blockchain settings. #### System Resources Replenish Algorithm @@ -46,4 +46,4 @@ This formula has the following outcomes: ### Buy RAM -The RAM resource must be bought using the system token. Refer to the [cleos manual](/developer-tools/02_cleos/02_how-to-guides/how-to-buy-ram.md) to learn how to do it via the command line interface. When an account consumes all its allocated RAM can not store any additional information on the blockchain database until it frees some of the occupied RAM or more RAM is allocated to the account through the RAM buying process. +The RAM resource must be bought using the system token. Refer to the [cleos manual](https://docs.eosnetwork.com/leap/latest/cleos/how-to-guides/how-to-buy-ram) to learn how to do it via the command line interface. When an account consumes all its allocated RAM can not store any additional information on the blockchain database until it frees some of the occupied RAM or more RAM is allocated to the account through the RAM buying process. diff --git a/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md b/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md index 2f092c19..7ced242f 100644 --- a/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md +++ b/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md @@ -13,7 +13,7 @@ cd CONTRACTS_DIR Pull the source ```sh -git clone https://github.com/eosnetworkfoundation/mandel-contracts --branch master --single-branch +git clone https://github.com/eosnetworkfoundation/eos-system-contracts --branch release/3.1 --single-branch ``` ```sh @@ -106,7 +106,7 @@ executed transaction: 60d334850151cb95c35fe31ce2e8b536b51441c5fd4c3f2fea98edcc6d # bob <= eosio.token::transfer {"from":"eosio","to":"bob","quantity":"25.0000 SYS","memo":"m"} warning: transaction executed locally, but may not be confirmed by the network yet ] ``` -Now check if "bob" got the tokens using [cleos get currency balance](/developer-tools/02_cleos/03_command-reference/get/currency-balance.md) +Now check if "bob" got the tokens using [cleos get currency balance](https://docs.eosnetwork.com/leap/latest/cleos/command-reference/get/currency-balance) ```shell cleos get currency balance eosio.token bob SYS diff --git a/docs/04_guides/08_configure-use-powerup-resource-model.md b/docs/04_guides/08_configure-use-powerup-resource-model.md index 5bcdedce..1fa210ea 100644 --- a/docs/04_guides/08_configure-use-powerup-resource-model.md +++ b/docs/04_guides/08_configure-use-powerup-resource-model.md @@ -123,7 +123,7 @@ struct powerup_state { ``` ### Preparation for Upgrade -1. Build [mandel contracts](https://github.com/eosnetworkfoundation/mandel-contracts) with `powerup` code. Version **1.9.x** or greater . +1. Build [eos-system-contracts](https://github.com/eosnetworkfoundation/eos-system-contracts) with `powerup` code. Version **1.9.x** or greater . 2. Deploy eosio.system contract to `eosio`. 3. Create account `eosio.reserv` and ensure the account has enough RAM, at least 4 KiB. 4. Deploy `powup.results.abi` to `eosio.reserv` account using `setabi`. The ABI can be found in the `build/contracts/eosio.system/.powerup/` directory. From 75331eb400a4d3622ec21c0ef12e1d6f3c4ae0e3 Mon Sep 17 00:00:00 2001 From: Luis Date: Wed, 5 Oct 2022 15:39:30 -0400 Subject: [PATCH 10/96] update/fix DUNE links for build and deploy :doc --- docs/03_build-and-deploy.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/03_build-and-deploy.md b/docs/03_build-and-deploy.md index cf56d5f8..58f172a2 100644 --- a/docs/03_build-and-deploy.md +++ b/docs/03_build-and-deploy.md @@ -3,7 +3,7 @@ content_title: How to build eosio.contracts --- ## Preconditions -This step references [DUNE (Docker Utilities for Node Execution)](/developer-tools/DUNE/index.md) +This step references [DUNE (Docker Utilities for Node Execution)](https://github.com/AntelopeIO/DUNE/blob/main/README.md) ## Build contracts -Follow the [contract building steps](/developer-tools/DUNE/index.md#cmake-contract-development) in the DUNE Guide. +Follow the [contract building steps](https://github.com/AntelopeIO/DUNE/blob/main/README.md#contract-development) in the DUNE Guide. From e1ffadf5a9996a1a7bada70103bcf928e025647f Mon Sep 17 00:00:00 2001 From: Luis Date: Wed, 5 Oct 2022 15:42:13 -0400 Subject: [PATCH 11/96] remove obsolete/inapplicable version refs :doc --- docs/04_guides/08_configure-use-powerup-resource-model.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/04_guides/08_configure-use-powerup-resource-model.md b/docs/04_guides/08_configure-use-powerup-resource-model.md index 1fa210ea..835b4355 100644 --- a/docs/04_guides/08_configure-use-powerup-resource-model.md +++ b/docs/04_guides/08_configure-use-powerup-resource-model.md @@ -123,7 +123,7 @@ struct powerup_state { ``` ### Preparation for Upgrade -1. Build [eos-system-contracts](https://github.com/eosnetworkfoundation/eos-system-contracts) with `powerup` code. Version **1.9.x** or greater . +1. Build [eos-system-contracts](https://github.com/eosnetworkfoundation/eos-system-contracts) with `powerup` code. 2. Deploy eosio.system contract to `eosio`. 3. Create account `eosio.reserv` and ensure the account has enough RAM, at least 4 KiB. 4. Deploy `powup.results.abi` to `eosio.reserv` account using `setabi`. The ABI can be found in the `build/contracts/eosio.system/.powerup/` directory. From 8b103d8e8c961cb3c88d54d8b172a5d46c692f63 Mon Sep 17 00:00:00 2001 From: Luis Date: Wed, 5 Oct 2022 15:43:57 -0400 Subject: [PATCH 12/96] rename welcome to docs in links :doc --- docs/01_key-concepts/03_cpu.md | 2 +- docs/01_key-concepts/04_net.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/01_key-concepts/03_cpu.md b/docs/01_key-concepts/03_cpu.md index f8506641..d56378ec 100644 --- a/docs/01_key-concepts/03_cpu.md +++ b/docs/01_key-concepts/03_cpu.md @@ -5,5 +5,5 @@ content_title: CPU as system resource The system resource CPU provides processing power to blockchain accounts. The amount of CPU an account has is measured in microseconds and it is referred to as `cpu bandwidth` on the `cleos get account` command output. The `cpu bandwidth` represents the amount of processing time an account has at its disposal when actions sent to its contract are executed by the blockchain. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient CPU must be staked in order for transactions to complete. For more details about EOSIO staking refer to the following: -* [Staking Mechanism](https://developers.eos.io/welcome/latest/overview/technical_features#staking-mechanism). +* [Staking Mechanism](https://developers.eos.io/docs/latest/overview/technical_features#staking-mechanism). * [Staking on EOSIO-based blockchains](05_stake.md) diff --git a/docs/01_key-concepts/04_net.md b/docs/01_key-concepts/04_net.md index 1b68710b..9826d863 100644 --- a/docs/01_key-concepts/04_net.md +++ b/docs/01_key-concepts/04_net.md @@ -5,5 +5,5 @@ content_title: NET as system resource NET, as CPU and RAM, is a very important system resource in EOSIO-based blockchains. NET is measured by the byte size of the transactions saved in the blockchain database and it is referred to as `net bandwidth` on the cleos get account command result. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient NET must be staked in order for transactions to complete. For more details about EOSIO staking refer to the following: -* [Staking Mechanism](https://developers.eos.io/welcome/latest/overview/technical_features#staking-mechanism). +* [Staking Mechanism](https://developers.eos.io/docs/latest/overview/technical_features#staking-mechanism). * [Staking on EOSIO-based blockchains](05_stake.md) From 52df1fac1a558e78f452b27cbf6757496d35d4f7 Mon Sep 17 00:00:00 2001 From: Luis Date: Wed, 5 Oct 2022 16:45:11 -0400 Subject: [PATCH 13/96] add doc links to singleton and multidex table back :doc --- docs/01_key-concepts/02_ram.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/01_key-concepts/02_ram.md b/docs/01_key-concepts/02_ram.md index 721ad64b..6c761b2a 100644 --- a/docs/01_key-concepts/02_ram.md +++ b/docs/01_key-concepts/02_ram.md @@ -10,8 +10,12 @@ RAM is the memory, the storage space, where the blockchain stores data. If your - Multi-index table [reference documentation page](http://docs.eosnetwork.com/cdt/latest/reference/Modules/group__multiindex) +- Multi-index table [how to documentation page](https://docs.eosnetwork.com/cdt/latest/how-to-guides/multi-index) + - Singleton [reference documentation page](https://docs.eosnetwork.com/cdt/latest/reference/Classes/classeosio_1_1singleton) +- Singleton [how to documentation page](https://docs.eosnetwork.com/cdt/latest/how-to-guides/multi-index/how-to-define-a-singleton) + ## RAM High Performance The EOSIO-based blockchains are known for their high performance, which is achieved also because the data stored on the blockchain is using RAM as the storage medium, and thus access to blockchain data is very fast, helping the performance benchmarks to reach levels no other blockchain has been able to. From 7ef69694313d5dd71f34619e8a26552e033092b6 Mon Sep 17 00:00:00 2001 From: Luis Date: Wed, 5 Oct 2022 16:51:04 -0400 Subject: [PATCH 14/96] replace build instructions with link to readme :doc --- docs/03_build-and-deploy.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/docs/03_build-and-deploy.md b/docs/03_build-and-deploy.md index 58f172a2..7e2c9592 100644 --- a/docs/03_build-and-deploy.md +++ b/docs/03_build-and-deploy.md @@ -1,9 +1,5 @@ --- -content_title: How to build eosio.contracts +content_title: How to build the EOS system contracts --- -## Preconditions -This step references [DUNE (Docker Utilities for Node Execution)](https://github.com/AntelopeIO/DUNE/blob/main/README.md) - -## Build contracts -Follow the [contract building steps](https://github.com/AntelopeIO/DUNE/blob/main/README.md#contract-development) in the DUNE Guide. +For building instructions, refer to the [Building](https://github.com/eosnetworkfoundation/eos-system-contracts#building) section. From a34366f7f8ea46c5d46fc546df7eb8db3134d1bc Mon Sep 17 00:00:00 2001 From: Luis Date: Fri, 14 Oct 2022 02:05:38 -0400 Subject: [PATCH 15/96] rename EOSIO to Antelope where applicable :doc --- docs/01_key-concepts/01_system.md | 6 +++--- docs/01_key-concepts/02_ram.md | 4 ++-- docs/01_key-concepts/03_cpu.md | 4 ++-- docs/01_key-concepts/04_net.md | 6 +++--- docs/01_key-concepts/05_stake.md | 10 +++++----- docs/01_key-concepts/06_vote.md | 4 ++-- docs/04_guides/07_how-to-use-eosio.wrap.md | 2 +- docs/index.md | 4 ++-- 8 files changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/01_key-concepts/01_system.md b/docs/01_key-concepts/01_system.md index ef3c3ae6..fb8352ac 100644 --- a/docs/01_key-concepts/01_system.md +++ b/docs/01_key-concepts/01_system.md @@ -2,16 +2,16 @@ content_title: System contracts, system accounts, privileged accounts --- -At the genesis of an EOSIO-based blockchain, there is only one account present, `eosio` account, which is the main `system account`. There are other `system account`s, created by `eosio` account, which control specific actions of the `system contract`s [mentioned in previous section](/index.md#system-contracts-defined-in-eosio.contracts). __Note__ the terms `system contract` and `system account`. `Privileged accounts` are accounts which can execute a transaction while skipping the standard authorization check. To ensure that this is not a security hole, the permission authority over these accounts is granted to `eosio.prods` system account. +At the genesis of an Antelope-based blockchain, there is only one account present, `eosio` account, which is the main `system account`. There are other `system account`s, created by `eosio` account, which control specific actions of the `system contract`s [mentioned in previous section](/index.md#system-contracts-defined-in-eosio.contracts). __Note__ the terms `system contract` and `system account`. `Privileged accounts` are accounts which can execute a transaction while skipping the standard authorization check. To ensure that this is not a security hole, the permission authority over these accounts is granted to `eosio.prods` system account. As you just learned the relation between a `system account` and a `system contract`, it is also important to remember that not all system accounts contain a system contract, but each system account has important roles in the blockchain functionality, as follows: |Account|Privileged|Has contract|Description| |---|---|---|---| -|eosio|Yes|It contains the `eosio.system` contract|The main system account on an EOSIO-based blockchain.| +|eosio|Yes|It contains the `eosio.system` contract|The main system account on an Antelope-based blockchain.| |eosio.msig|Yes|It contains the `eosio.msig` contract|Allows the signing of a multi-sig transaction proposal for later execution if all required parties sign the proposal before the expiration time.| |eosio.wrap|Yes|It contains the `eosio.wrap` contract.|Simplifies block producer superuser actions by making them more readable and easier to audit.| -|eosio.token|No|It contains the `eosio.token` contract.|Defines the structures and actions allowing users to create, issue, and manage tokens on EOSIO-based blockchains.| +|eosio.token|No|It contains the `eosio.token` contract.|Defines the structures and actions allowing users to create, issue, and manage tokens on Antelope-based blockchains.| |eosio.names|No|No|The account which is holding funds from namespace auctions.| |eosio.bpay|No|No|The account that pays the block producers for producing blocks. It assigns 0.25% of the inflation based on the amount of blocks a block producer created in the last 24 hours.| |eosio.prods|No|No|The account representing the union of all current active block producers permissions.| diff --git a/docs/01_key-concepts/02_ram.md b/docs/01_key-concepts/02_ram.md index 6c761b2a..0089afd2 100644 --- a/docs/01_key-concepts/02_ram.md +++ b/docs/01_key-concepts/02_ram.md @@ -18,13 +18,13 @@ RAM is the memory, the storage space, where the blockchain stores data. If your ## RAM High Performance -The EOSIO-based blockchains are known for their high performance, which is achieved also because the data stored on the blockchain is using RAM as the storage medium, and thus access to blockchain data is very fast, helping the performance benchmarks to reach levels no other blockchain has been able to. +The Antelope-based blockchains are known for their high performance, which is achieved also because the data stored on the blockchain is using RAM as the storage medium, and thus access to blockchain data is very fast, helping the performance benchmarks to reach levels no other blockchain has been able to. ## RAM Importance RAM is a very important system resource because of the following reasons: -- It is a limited resource, each EOSIO-based blockchain can have different policies and rules around RAM; for example the public EOS blockchain started with 64GB of RAM and after that the block producers decided to increase the memory with 1KB per block, thus increasing constantly the supply of RAM for its price to not grow too high due to the increased demand from blockchain applications. +- It is a limited resource, each Antelope-based blockchain can have different policies and rules around RAM; for example the public EOS blockchain started with 64GB of RAM and after that the block producers decided to increase the memory with 1KB per block, thus increasing constantly the supply of RAM for its price to not grow too high due to the increased demand from blockchain applications. - RAM is used in executing many actions sent to the blockchain; creating a new account action, for example, it needs to store in the blockchain memory the new account's information; also when an account accepts a new type of token a new record has to be created, somewhere in the blockchain memory, that holds the balance of the new token accepted, and that memory, the storage space on the blockchain, has to be purchased either by the account that transfers the token or by the account that accepts the new token type. diff --git a/docs/01_key-concepts/03_cpu.md b/docs/01_key-concepts/03_cpu.md index d56378ec..f094beb7 100644 --- a/docs/01_key-concepts/03_cpu.md +++ b/docs/01_key-concepts/03_cpu.md @@ -4,6 +4,6 @@ content_title: CPU as system resource The system resource CPU provides processing power to blockchain accounts. The amount of CPU an account has is measured in microseconds and it is referred to as `cpu bandwidth` on the `cleos get account` command output. The `cpu bandwidth` represents the amount of processing time an account has at its disposal when actions sent to its contract are executed by the blockchain. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient CPU must be staked in order for transactions to complete. -For more details about EOSIO staking refer to the following: +For more details about staking on Antelope-based blockchains refer to the following: * [Staking Mechanism](https://developers.eos.io/docs/latest/overview/technical_features#staking-mechanism). -* [Staking on EOSIO-based blockchains](05_stake.md) +* [Staking on Antelope-based blockchains](05_stake.md) diff --git a/docs/01_key-concepts/04_net.md b/docs/01_key-concepts/04_net.md index 9826d863..c7a6e79d 100644 --- a/docs/01_key-concepts/04_net.md +++ b/docs/01_key-concepts/04_net.md @@ -2,8 +2,8 @@ content_title: NET as system resource --- -NET, as CPU and RAM, is a very important system resource in EOSIO-based blockchains. NET is measured by the byte size of the transactions saved in the blockchain database and it is referred to as `net bandwidth` on the cleos get account command result. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient NET must be staked in order for transactions to complete. +NET, as CPU and RAM, is a very important system resource in Antelope-based blockchains. NET is measured by the byte size of the transactions saved in the blockchain database and it is referred to as `net bandwidth` on the cleos get account command result. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient NET must be staked in order for transactions to complete. -For more details about EOSIO staking refer to the following: +For more details about staking on Antelope-based blockchains refer to the following: * [Staking Mechanism](https://developers.eos.io/docs/latest/overview/technical_features#staking-mechanism). -* [Staking on EOSIO-based blockchains](05_stake.md) +* [Staking on Antelope-based blockchains](05_stake.md) diff --git a/docs/01_key-concepts/05_stake.md b/docs/01_key-concepts/05_stake.md index 6ebbbb93..31b29f58 100644 --- a/docs/01_key-concepts/05_stake.md +++ b/docs/01_key-concepts/05_stake.md @@ -1,10 +1,10 @@ --- -content_title: Staking on EOSIO-based blockchains +content_title: Staking on Antelope-based blockchains --- ## System Resources -EOSIO-based blockchains work with three system resources: +Antelope-based blockchains work with three system resources: * [RAM](02_ram.md) * [CPU](03_cpu.md) @@ -12,7 +12,7 @@ EOSIO-based blockchains work with three system resources: ## How To Allocate System Resources -EOSIO-based blockchain accounts need sufficient system resources, RAM, CPU and NET, to interact with the smart contracts deployed on the blockchain. +Antelope-based blockchain accounts need sufficient system resources, RAM, CPU and NET, to interact with the smart contracts deployed on the blockchain. ### Stake NET and CPU @@ -31,13 +31,13 @@ When an account uses the allocated resources, the amount that can be used in one #### System Resources Replenish Algorithm -EOSIO-based blockchains replenish automatically the consumed CPU and NET system resources. Before a transaction is executed, by the blockchain, it first calculates how many resources the account executing the transaction can consume. The calculation uses an exponential moving average with linear extrapolation when data is missing, and it multiplies the currently accumulated average by `(number of blocks in the window - number of blocks since last update) / (number of blocks in the window)`. The window is set as 24 hours window. +Antelope-based blockchains replenish automatically the consumed CPU and NET system resources. Before a transaction is executed, by the blockchain, it first calculates how many resources the account executing the transaction can consume. The calculation uses an exponential moving average with linear extrapolation when data is missing, and it multiplies the currently accumulated average by `(number of blocks in the window - number of blocks since last update) / (number of blocks in the window)`. The window is set as 24 hours window. This formula has the following outcomes: * If an account waited `number of blocks in the window` without executing any transaction it resets to zero usage. -* If an account issues a transaction with every block it would always be `(number of blocks in the window - 1) / (number of blocks in the window)`, a very small value, very close to zero. Mathematically it _never_ reaches zero but the EOSIO implementation truncates off the tiny numbers to zero. +* If an account issues a transaction with every block it would always be `(number of blocks in the window - 1) / (number of blocks in the window)`, a very small value, very close to zero. Mathematically it _never_ reaches zero but the Antelope implementation truncates off the tiny numbers to zero. * The accounts that execute transactions more often than the ones that execute less transactions, replenish their resources slower than the later. In other words, the more transactions an account executes the slower the replenish of resources. diff --git a/docs/01_key-concepts/06_vote.md b/docs/01_key-concepts/06_vote.md index 41840c65..c2344c3c 100644 --- a/docs/01_key-concepts/06_vote.md +++ b/docs/01_key-concepts/06_vote.md @@ -1,5 +1,5 @@ --- -content_title: Voting on EOSIO-based blockchains +content_title: Voting on Antelope-based blockchains --- -In a EOSIO-based network the blockchain is kept alive by nodes which are interconnected between each other, communicating with each other via peer to peer protocols. Some of these nodes are elected, via a voting process, by the token holders to be producer nodes. They produce blocks, validate them and reach consensus on what transactions are allowed in each block, their order, and what blocks are finalized and stored forever in the blockchain. This way the governance, the mechanism by which collective decisions are made, of the blockchain is achieved through the 21 active block producers which are appointed by token holders' votes. It's the 21 active block producers which continuously create the blockchain by creating blocks, and securing them by validating them, and reaching consensus. Consensus is reached when 2/3+1 active block producers agree on validity of a block, that is all transactions contained in it and their order. The 21 producers is the default value however it can be configured to be higher or smaller to meet each business case requirements. +In an Antelope-based network the blockchain is kept alive by nodes which are interconnected between each other, communicating with each other via peer to peer protocols. Some of these nodes are elected, via a voting process, by the token holders to be producer nodes. They produce blocks, validate them and reach consensus on what transactions are allowed in each block, their order, and what blocks are finalized and stored forever in the blockchain. This way the governance, the mechanism by which collective decisions are made, of the blockchain is achieved through the 21 active block producers which are appointed by token holders' votes. It's the 21 active block producers which continuously create the blockchain by creating blocks, and securing them by validating them, and reaching consensus. Consensus is reached when 2/3+1 active block producers agree on validity of a block, that is all transactions contained in it and their order. The 21 producers is the default value however it can be configured to be higher or smaller to meet each business case requirements. diff --git a/docs/04_guides/07_how-to-use-eosio.wrap.md b/docs/04_guides/07_how-to-use-eosio.wrap.md index 807441c2..25f04e10 100644 --- a/docs/04_guides/07_how-to-use-eosio.wrap.md +++ b/docs/04_guides/07_how-to-use-eosio.wrap.md @@ -638,7 +638,7 @@ If the two hashes match then the local WebAssembly code is the one deployed on t ## 2.1 Example: Updating owner authority of an arbitrary account -This example will demonstrate how to use the deployed eosio.wrap contract together with the eosio.msig contract to allow a greater than two-thirds supermajority of block producers of an EOSIO blockchain to change the owner authority of an arbitrary account. The example will use cleos: in particular, the `cleos multisig` command, the `cleos set account permission` sub-command, and the `cleos wrap exec` sub-command. However, the guide also demonstrates what to do if the `cleos wrap exec` sub-command is not available. +This example will demonstrate how to use the deployed eosio.wrap contract together with the eosio.msig contract to allow a greater than two-thirds supermajority of block producers of an Antelope blockchain to change the owner authority of an arbitrary account. The example will use cleos: in particular, the `cleos multisig` command, the `cleos set account permission` sub-command, and the `cleos wrap exec` sub-command. However, the guide also demonstrates what to do if the `cleos wrap exec` sub-command is not available. This guide assumes that there are 21 active block producers on the chain with account names: `blkproducera`, `blkproducerb`, ..., `blkproduceru`. Block producer `blkproducera` will act as the lead block producer handling the proposal of the transaction. diff --git a/docs/index.md b/docs/index.md index 37759d12..67f4e8f7 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,11 +2,11 @@ content_title: About System Contracts --- -The EOSIO blockchain platform is unique in that the features and characteristics of the blockchain built on it are flexible, that is, they can be changed, or modified completely to suit each business case requirement. Core blockchain features such as consensus, fee schedules, account creation and modification, token economics, block producer registration, voting, multi-sig, etc., are implemented inside smart contracts which are deployed on the blockchain built on the EOSIO platform. +The Antelope blockchain platform is unique in that the features and characteristics of the blockchain built on it are flexible, that is, they can be changed, or modified completely to suit each business case requirement. Core blockchain features such as consensus, fee schedules, account creation and modification, token economics, block producer registration, voting, multi-sig, etc., are implemented inside smart contracts which are deployed on the blockchain built on the Antelope platform. ## System contracts defined in eosio.contracts -Block.one implements and maintains EOSIO open source platform which contains, as an example, the system contracts encapsulating the base functionality for an EOSIO based blockchain. +The `eos-system-contracts` repository contains the system contracts encapsulating the base functionality for the EOS blockchain. 1. [eosio.bios](action-reference/eosio.bios) 2. [eosio.system](action-reference/eosio.system) From 94039caa1c9e3ba3d20fcce728bd67cdb686788d Mon Sep 17 00:00:00 2001 From: Luis Date: Fri, 14 Oct 2022 02:18:21 -0400 Subject: [PATCH 16/96] minor edits and rename platform to framework :doc --- docs/01_key-concepts/05_stake.md | 2 +- docs/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/01_key-concepts/05_stake.md b/docs/01_key-concepts/05_stake.md index 31b29f58..c7bffe21 100644 --- a/docs/01_key-concepts/05_stake.md +++ b/docs/01_key-concepts/05_stake.md @@ -37,7 +37,7 @@ This formula has the following outcomes: * If an account waited `number of blocks in the window` without executing any transaction it resets to zero usage. -* If an account issues a transaction with every block it would always be `(number of blocks in the window - 1) / (number of blocks in the window)`, a very small value, very close to zero. Mathematically it _never_ reaches zero but the Antelope implementation truncates off the tiny numbers to zero. +* If an account issues a transaction with every block it would always be `(number of blocks in the window - 1) / (number of blocks in the window)`, a very small value, very close to zero. Mathematically it _never_ reaches zero but the EOS implementation truncates off the tiny numbers to zero. * The accounts that execute transactions more often than the ones that execute less transactions, replenish their resources slower than the later. In other words, the more transactions an account executes the slower the replenish of resources. diff --git a/docs/index.md b/docs/index.md index 67f4e8f7..60875409 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,7 +2,7 @@ content_title: About System Contracts --- -The Antelope blockchain platform is unique in that the features and characteristics of the blockchain built on it are flexible, that is, they can be changed, or modified completely to suit each business case requirement. Core blockchain features such as consensus, fee schedules, account creation and modification, token economics, block producer registration, voting, multi-sig, etc., are implemented inside smart contracts which are deployed on the blockchain built on the Antelope platform. +The Antelope blockchain framework is unique in that the features and characteristics of the blockchain built on it are flexible, that is, they can be changed, or modified completely to suit each business case requirement. Core blockchain features such as consensus, fee schedules, account creation and modification, token economics, block producer registration, voting, multi-sig, etc., are implemented inside smart contracts which are deployed on the blockchain built on the Antelope framework. ## System contracts defined in eosio.contracts From 8042365d4ba441f1840881f1c603b1877d81bc9d Mon Sep 17 00:00:00 2001 From: Dmytro Sydorchenko Date: Thu, 6 Oct 2022 19:10:18 -0400 Subject: [PATCH 17/96] porting msig changes from eosio.contracts --- contracts/eosio.msig/src/eosio.msig.cpp | 10 +- tests/contracts.hpp.in | 2 + tests/eosio.msig_tests.cpp | 276 +++++++++++++++++++++--- tests/eosio.system_tests.cpp | 14 +- tests/eosio.wrap_tests.cpp | 80 +++++-- tests/sendinline.cpp | 25 +++ 6 files changed, 359 insertions(+), 48 deletions(-) create mode 100644 tests/sendinline.cpp diff --git a/contracts/eosio.msig/src/eosio.msig.cpp b/contracts/eosio.msig/src/eosio.msig.cpp index 17692192..843063bf 100644 --- a/contracts/eosio.msig/src/eosio.msig.cpp +++ b/contracts/eosio.msig/src/eosio.msig.cpp @@ -145,9 +145,14 @@ void multisig::exec( name proposer, name proposal_name, name executer ) { proposals proptable( get_self(), proposer.value ); auto& prop = proptable.get( proposal_name.value, "proposal not found" ); transaction_header trx_header; + std::vector context_free_actions; + std::vector actions; datastream ds( prop.packed_transaction.data(), prop.packed_transaction.size() ); ds >> trx_header; check( trx_header.expiration >= eosio::time_point_sec(current_time_point()), "transaction expired" ); + ds >> context_free_actions; + check( context_free_actions.empty(), "not allowed to `exec` a transaction with context-free actions" ); + ds >> actions; approvals apptable( get_self(), proposer.value ); auto apps_it = apptable.find( proposal_name.value ); @@ -182,8 +187,9 @@ void multisig::exec( name proposer, name proposal_name, name executer ) { check( res > 0, "transaction authorization failed" ); - send_deferred( (uint128_t(proposer.value) << 64) | proposal_name.value, executer, - prop.packed_transaction.data(), prop.packed_transaction.size() ); + for (const auto& act : actions) { + act.send(); + } proptable.erase(prop); } diff --git a/tests/contracts.hpp.in b/tests/contracts.hpp.in index 19babc5f..27fddd5b 100644 --- a/tests/contracts.hpp.in +++ b/tests/contracts.hpp.in @@ -24,6 +24,8 @@ struct contracts { static std::vector system_abi_old() { return read_abi("${CMAKE_CURRENT_SOURCE_DIR}/test_contracts/old_versions/v1.2.1/eosio.system/eosio.system.abi"); } static std::vector msig_wasm_old() { return read_wasm("${CMAKE_CURRENT_SOURCE_DIR}/test_contracts/old_versions/v1.2.1/eosio.msig/eosio.msig.wasm"); } static std::vector msig_abi_old() { return read_abi("${CMAKE_CURRENT_SOURCE_DIR}/test_contracts/old_versions/v1.2.1/eosio.msig/eosio.msig.abi"); } + static std::vector sendinline_wasm() {return read_wasm("${CMAKE_CURRENT_SOURCE_DIR}/test_contracts/old_versions/v1.8.3/sendinline/sendinline.wasm"); } + static std::vector sendinline_abi() {return read_abi("${CMAKE_CURRENT_SOURCE_DIR}/test_contracts/old_versions/v1.8.3/sendinline/sendinline.abi"); } }; }; diff --git a/tests/eosio.msig_tests.cpp b/tests/eosio.msig_tests.cpp index 685c87db..6b4e692f 100644 --- a/tests/eosio.msig_tests.cpp +++ b/tests/eosio.msig_tests.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -210,8 +211,7 @@ BOOST_FIXTURE_TEST_CASE( propose_approve_execute, eosio_msig_tester ) try { transaction_trace_ptr trace; control->applied_transaction.connect( [&]( std::tuple p ) { - const auto& t = std::get<0>(p); - if( t->scheduled ) { trace = t; } + trace = std::get<0>(p); } ); push_action( "alice"_n, "exec"_n, mvo() ("proposer", "alice") @@ -296,8 +296,7 @@ BOOST_FIXTURE_TEST_CASE( propose_approve_by_two, eosio_msig_tester ) try { transaction_trace_ptr trace; control->applied_transaction.connect( [&]( std::tuple p ) { - const auto& t = std::get<0>(p); - if( t->scheduled ) { trace = t; } + trace = std::get<0>(p); } ); push_action( "alice"_n, "exec"_n, mvo() @@ -329,6 +328,14 @@ BOOST_FIXTURE_TEST_CASE( propose_with_wrong_requested_auth, eosio_msig_tester ) BOOST_FIXTURE_TEST_CASE( big_transaction, eosio_msig_tester ) try { + //change `default_max_inline_action_size` to 512 KB + eosio::chain::chain_config params = control->get_global_properties().configuration; + params.max_inline_action_size = 512 * 1024; + base_tester::push_action( config::system_account_name, N(setparams), config::system_account_name, mutable_variant_object() + ("params", params) ); + + produce_blocks(); + vector perm = { { "alice"_n, config::active_name }, { "bob"_n, config::active_name } }; auto wasm = contracts::util::exchange_wasm(); @@ -379,8 +386,7 @@ BOOST_FIXTURE_TEST_CASE( big_transaction, eosio_msig_tester ) try { transaction_trace_ptr trace; control->applied_transaction.connect( [&]( std::tuple p ) { - const auto& t = std::get<0>(p); - if( t->scheduled ) { trace = t; } + trace = std::get<0>(p); } ); push_action( "alice"_n, "exec"_n, mvo() @@ -503,11 +509,10 @@ BOOST_FIXTURE_TEST_CASE( update_system_contract_all_approve, eosio_msig_tester ) ("level", permission_level{ "carol"_n, config::active_name }) ); // execute by alice to replace the eosio system contract - transaction_trace_ptr trace; + transaction_trace_ptr trx_trace; control->applied_transaction.connect( [&]( std::tuple p ) { - const auto& t = std::get<0>(p); - if( t->scheduled ) { trace = t; } + trx_trace = std::get<0>(p); } ); push_action( "alice"_n, "exec"_n, mvo() @@ -516,9 +521,29 @@ BOOST_FIXTURE_TEST_CASE( update_system_contract_all_approve, eosio_msig_tester ) ("executer", "alice") ); - BOOST_REQUIRE( bool(trace) ); - BOOST_REQUIRE_EQUAL( 1, trace->action_traces.size() ); - BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); + BOOST_REQUIRE( bool(trx_trace) ); + BOOST_REQUIRE( trx_trace->receipt.valid() ); + BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); + BOOST_REQUIRE_EQUAL( 2, trx_trace->action_traces.size() ); + + BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(0).action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).closest_unnotified_ancestor_action_ordinal ); + // EOSIO 1.8 N() macro returns a uint64_t rather than a struct name + BOOST_REQUIRE_EQUAL( name{N(eosio.msig)}, action_name{trx_trace->action_traces.at(0).receiver} ); + BOOST_REQUIRE_EQUAL( name{N(eosio.msig)}, name{trx_trace->action_traces.at(0).act.account} ); + BOOST_REQUIRE_EQUAL( name{N(exec)}, name{trx_trace->action_traces.at(0).act.name} ); + BOOST_REQUIRE_EQUAL( name{N(alice)}, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); + + BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(1).action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).closest_unnotified_ancestor_action_ordinal ); + BOOST_REQUIRE_EQUAL( name{N(eosio)}, action_name{trx_trace->action_traces.at(1).receiver} ); + BOOST_REQUIRE_EQUAL( name{N(eosio)}, name{trx_trace->action_traces.at(1).act.account} ); + BOOST_REQUIRE_EQUAL( name{N(setcode)}, name{trx_trace->action_traces.at(1).act.name} ); + BOOST_REQUIRE_EQUAL( name{N(eosio)}, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); // can't create account because system contract was replaced by the reject_all contract @@ -640,11 +665,10 @@ BOOST_FIXTURE_TEST_CASE( update_system_contract_major_approve, eosio_msig_tester ("level", permission_level{ "apple"_n, config::active_name }) ); // execute by alice to replace the eosio system contract - transaction_trace_ptr trace; + transaction_trace_ptr trx_trace; control->applied_transaction.connect( [&]( std::tuple p ) { - const auto& t = std::get<0>(p); - if( t->scheduled ) { trace = t; } + trx_trace = std::get<0>(p); } ); // execute by another producer different from proposer @@ -654,9 +678,29 @@ BOOST_FIXTURE_TEST_CASE( update_system_contract_major_approve, eosio_msig_tester ("executer", "apple") ); - BOOST_REQUIRE( bool(trace) ); - BOOST_REQUIRE_EQUAL( 1, trace->action_traces.size() ); - BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); + BOOST_REQUIRE( bool(trx_trace) ); + BOOST_REQUIRE( trx_trace->receipt.valid() ); + BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); + BOOST_REQUIRE_EQUAL( 2, trx_trace->action_traces.size() ); + + BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(0).action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).closest_unnotified_ancestor_action_ordinal ); + // EOSIO 1.8 N() macro returns a uint64_t rather than a struct name + BOOST_REQUIRE_EQUAL( name{N(eosio.msig)}, action_name{trx_trace->action_traces.at(0).receiver} ); + BOOST_REQUIRE_EQUAL( name{N(eosio.msig)}, name{trx_trace->action_traces.at(0).act.account} ); + BOOST_REQUIRE_EQUAL( name{N(exec)}, name{trx_trace->action_traces.at(0).act.name} ); + BOOST_REQUIRE_EQUAL( name{N(apple)}, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); + + BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(1).action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).closest_unnotified_ancestor_action_ordinal ); + BOOST_REQUIRE_EQUAL( name{N(eosio)}, action_name{trx_trace->action_traces.at(1).receiver} ); + BOOST_REQUIRE_EQUAL( name{N(eosio)}, name{trx_trace->action_traces.at(1).act.account} ); + BOOST_REQUIRE_EQUAL( name{N(setcode)}, name{trx_trace->action_traces.at(1).act.name} ); + BOOST_REQUIRE_EQUAL( name{N(eosio)}, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); // can't create account because system contract was replaced by the reject_all contract @@ -745,8 +789,7 @@ BOOST_FIXTURE_TEST_CASE( propose_invalidate_approve, eosio_msig_tester ) try { transaction_trace_ptr trace; control->applied_transaction.connect( [&]( std::tuple p ) { - const auto& t = std::get<0>(p); - if( t->scheduled ) { trace = t; } + trace = std::get<0>(p); } ); push_action( "bob"_n, "exec"_n, mvo() @@ -788,8 +831,7 @@ BOOST_FIXTURE_TEST_CASE( approve_execute_old, eosio_msig_tester ) try { transaction_trace_ptr trace; control->applied_transaction.connect( [&]( std::tuple p ) { - const auto& t = std::get<0>(p); - if( t->scheduled ) { trace = t; } + trace = std::get<0>(p); } ); push_action( "alice"_n, "exec"_n, mvo() @@ -892,8 +934,7 @@ BOOST_FIXTURE_TEST_CASE( approve_by_two_old, eosio_msig_tester ) try { transaction_trace_ptr trace; control->applied_transaction.connect( [&]( std::tuple p ) { - const auto& t = std::get<0>(p); - if( t->scheduled ) { trace = t; } + trace = std::get<0>(p); } ); push_action( "alice"_n, "exec"_n, mvo() @@ -942,8 +983,7 @@ BOOST_FIXTURE_TEST_CASE( approve_with_hash, eosio_msig_tester ) try { transaction_trace_ptr trace; control->applied_transaction.connect( [&]( std::tuple p ) { - const auto& t = std::get<0>(p); - if( t->scheduled ) { trace = t; } + trace = std::get<0>(p); } ); push_action( "alice"_n, "exec"_n, mvo() @@ -999,4 +1039,188 @@ BOOST_FIXTURE_TEST_CASE( switch_proposal_and_fail_approve_with_hash, eosio_msig_ ); } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE( sendinline, eosio_msig_tester ) try { + create_accounts( {N(sendinline)} ); + set_code( N(sendinline), contracts::util::sendinline_wasm() ); + set_abi( N(sendinline), contracts::util::sendinline_abi().data() ); + + create_accounts( {N(wrongcon)} ); + set_code( N(wrongcon), contracts::util::sendinline_wasm() ); + set_abi( N(wrongcon), contracts::util::sendinline_abi().data() ); + produce_blocks(); + + action act = get_action( config::system_account_name, N(reqauth), {}, mvo()("from", "alice")); + + BOOST_REQUIRE_EXCEPTION( base_tester::push_action( N(sendinline), N(send), N(bob), mvo() + ("contract", "eosio") + ("action_name", "reqauth") + ("auths", std::vector{ {N(alice), config::active_name} }) + ("payload", act.data) + ), + unsatisfied_authorization, + fc_exception_message_starts_with("transaction declares authority") + ); + + base_tester::push_action(config::system_account_name, N(updateauth), N(alice), mvo() + ("account", "alice") + ("permission", "perm") + ("parent", "active") + ("auth", authority{ 1, {}, {permission_level_weight{ {N(sendinline), config::eosio_code_name}, 1}}, {} }) + ); + produce_blocks(); + + base_tester::push_action( config::system_account_name, N(linkauth), N(alice), mvo() + ("account", "alice") + ("code", "eosio") + ("type", "reqauth") + ("requirement", "perm") + ); + produce_blocks(); + + transaction_trace_ptr trx_trace; + trx_trace = base_tester::push_action( N(sendinline), N(send), N(bob), mvo() + ("contract", "eosio") + ("action_name", "reqauth") + ("auths", std::vector{ {N(alice), N(perm)} }) + ("payload", act.data) + ); + produce_blocks(); + + BOOST_REQUIRE( bool(trx_trace) ); + BOOST_REQUIRE( trx_trace->receipt.valid() ); + BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); + BOOST_REQUIRE_EQUAL( 2, trx_trace->action_traces.size() ); + + BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(0).action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).closest_unnotified_ancestor_action_ordinal ); + // EOSIO 1.8 N() macro returns a uint64_t rather than a struct name + BOOST_REQUIRE_EQUAL( name{N(sendinline)}, action_name{trx_trace->action_traces.at(0).receiver} ); + BOOST_REQUIRE_EQUAL( name{N(sendinline)}, name{trx_trace->action_traces.at(0).act.account} ); + BOOST_REQUIRE_EQUAL( name{N(send)}, name{trx_trace->action_traces.at(0).act.name} ); + BOOST_REQUIRE_EQUAL( name{N(bob)}, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); + + BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(1).action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).closest_unnotified_ancestor_action_ordinal ); + BOOST_REQUIRE_EQUAL( name{N(eosio)}, action_name{trx_trace->action_traces.at(1).receiver} ); + BOOST_REQUIRE_EQUAL( name{N(eosio)}, name{trx_trace->action_traces.at(1).act.account} ); + BOOST_REQUIRE_EQUAL( name{N(reqauth)}, name{trx_trace->action_traces.at(1).act.name} ); + BOOST_REQUIRE_EQUAL( name{N(alice)}, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( name{N(perm)}, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); + + + base_tester::push_action(config::system_account_name, updateauth::get_name(), N(sendinline), mvo() + ("account", "sendinline") + ("permission", name(config::active_name)) + ("parent", name(config::owner_name)) + ("auth", authority(1, {key_weight{get_public_key("sendinline", "active"), 1}}, { + permission_level_weight{{"sendinline", config::eosio_code_name}, 1} + } + )) + ); + produce_blocks(); + + action approve_act = get_action(N(eosio.msig), N(approve), {}, mvo() + ("proposer", "bob") + ("proposal_name", "first") + ("level", permission_level{N(sendinline), N(eosio.code)}) + ); + + action unapprove_act = get_action(N(eosio.msig), N(unapprove), {}, mvo() + ("proposer", "bob") + ("proposal_name", "first") + ("level", permission_level{N(sendinline), N(eosio.code)}) + ); + + transaction trx = reqauth( N(alice), {permission_level{N(alice), N(perm)}}, abi_serializer_max_time ); + + base_tester::push_action( N(eosio.msig), N(propose), N(bob), mvo() + ("proposer", "bob") + ("proposal_name", "first") + ("trx", trx) + ("requested", std::vector{{ N(sendinline), N(eosio.code) }}) + ); + produce_blocks(); +#if 0 + // `approve` shall fail when being sent from the wrong contract + BOOST_REQUIRE_EXCEPTION( base_tester::push_action( N(wrongcon), N(send), N(bob), mvo() + ("contract", "eosio.msig") + ("action_name", "approve") + ("auths", std::vector{{N(bob), config::active_name}}) + ("payload", approve_act.data) + ), + eosio_assert_message_exception, + eosio_assert_message_is("wrong contract sent `approve` action for eosio.code permmission") + ); + // `approve` shall succeed when being sent from the correct contract + base_tester::push_action( N(sendinline), N(send), N(bob), mvo() + ("contract", "eosio.msig") + ("action_name", "approve") + ("auths", std::vector{{N(bob), config::eosio_code_name}}) + ("payload", approve_act.data) + ); + produce_blocks(); + + // `unapprove` shall fail when being sent from the wrong contract + BOOST_REQUIRE_EXCEPTION( base_tester::push_action( N(wrongcon), N(send), N(bob), mvo() + ("contract", N(eosio.msig)) + ("action_name", "unapprove") + ("auths", std::vector{}) + ("payload", unapprove_act.data) + ), + eosio_assert_message_exception, + eosio_assert_message_is("wrong contract sent `unapprove` action for eosio.code permmission") + ); + + // `unapprove` shall succeed when being sent from the correct contract + base_tester::push_action( N(sendinline), N(send), N(bob), mvo() + ("contract", N(eosio.msig)) + ("action_name", "unapprove") + ("auths", std::vector{}) + ("payload", unapprove_act.data) + ); + produce_blocks(); +#endif + // `approve` to get back into a state ready for `exec` + base_tester::push_action( N(sendinline), N(send), N(bob), mvo() + ("contract", "eosio.msig") + ("action_name", "approve") + ("auths", std::vector{{N(sendinline), config::active_name}}) + ("payload", approve_act.data) + ); + produce_blocks(); + + trx_trace = base_tester::push_action( N(eosio.msig), N(exec), N(bob), mvo() + ("proposer", "bob") + ("proposal_name", "first") + ("executer", "bob") + ); + + BOOST_REQUIRE( bool(trx_trace) ); + BOOST_REQUIRE( trx_trace->receipt.valid() ); + BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); + BOOST_REQUIRE_EQUAL( 2, trx_trace->action_traces.size() ); + + BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(0).action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).closest_unnotified_ancestor_action_ordinal ); + BOOST_REQUIRE_EQUAL( name{N(eosio.msig)}, action_name{trx_trace->action_traces.at(0).receiver} ); + BOOST_REQUIRE_EQUAL( name{N(eosio.msig)}, name{trx_trace->action_traces.at(0).act.account} ); + BOOST_REQUIRE_EQUAL( name{N(exec)}, name{trx_trace->action_traces.at(0).act.name} ); + BOOST_REQUIRE_EQUAL( name{N(bob)}, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); + + BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(1).action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).closest_unnotified_ancestor_action_ordinal ); + BOOST_REQUIRE_EQUAL( name{N(eosio)}, action_name{trx_trace->action_traces.at(1).receiver} ); + BOOST_REQUIRE_EQUAL( name{N(eosio)}, name{trx_trace->action_traces.at(1).act.account} ); + BOOST_REQUIRE_EQUAL( name{N(reqauth)}, name{trx_trace->action_traces.at(1).act.name} ); + BOOST_REQUIRE_EQUAL( name{N(alice)}, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( name{N(perm)}, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); + +} FC_LOG_AND_RETHROW() + BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 1989d8f6..aff4a4b4 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -2729,6 +2729,14 @@ BOOST_FIXTURE_TEST_CASE(producers_upgrade_system_contract, eosio_system_tester) abi_serializer msig_abi_ser = initialize_multisig(); auto producer_names = active_and_vote_producers(); + //change `default_max_inline_action_size` to 512 KB + eosio::chain::chain_config params = control->get_global_properties().configuration; + params.max_inline_action_size = 512 * 1024; + base_tester::push_action( config::system_account_name, N(setparams), config::system_account_name, mutable_variant_object() + ("params", params) ); + + produce_blocks(); + //helper function auto push_action_msig = [&]( const account_name& signer, const action_name &name, const variant_object &data, bool auth = true ) -> action_result { string action_type_name = msig_abi_ser.get_action_type(name); @@ -2816,8 +2824,7 @@ BOOST_FIXTURE_TEST_CASE(producers_upgrade_system_contract, eosio_system_tester) transaction_trace_ptr trace; control->applied_transaction.connect( [&]( std::tuple p ) { - const auto& t = std::get<0>(p); - if( t->scheduled ) { trace = t; } + trace = std::get<0>(p); } ); BOOST_REQUIRE_EQUAL(success(), push_action_msig( "alice1111111"_n, "exec"_n, mvo() @@ -3578,8 +3585,7 @@ BOOST_FIXTURE_TEST_CASE( setparams, eosio_system_tester ) try { transaction_trace_ptr trace; control->applied_transaction.connect( [&]( std::tuple p ) { - const auto& t = std::get<0>(p); - if( t->scheduled ) { trace = t; } + trace = std::get<0>(p); } ); BOOST_REQUIRE_EQUAL(success(), push_action_msig( "alice1111111"_n, "exec"_n, mvo() diff --git a/tests/eosio.wrap_tests.cpp b/tests/eosio.wrap_tests.cpp index 094c3502..4e2b9d49 100644 --- a/tests/eosio.wrap_tests.cpp +++ b/tests/eosio.wrap_tests.cpp @@ -220,17 +220,15 @@ BOOST_FIXTURE_TEST_CASE( wrap_with_msig, eosio_wrap_tester ) try { vector traces; control->applied_transaction.connect( [&]( std::tuple p ) { - const auto& t = std::get<0>(p); - if( t->scheduled ) { - traces.push_back( t ); - } + traces.push_back( std::get<0>(p) ); } ); // Now the proposal should be ready to execute - push_action( "eosio.msig"_n, "exec"_n, "alice"_n, mvo() - ("proposer", "carol") - ("proposal_name", "first") - ("executer", "alice") + transaction_trace_ptr trx_trace; + trx_trace = push_action( "eosio.msig"_n, "exec"_n, "alice"_n, mvo() + ("proposer", "carol") + ("proposal_name", "first") + ("executer", "alice") ); produce_block(); @@ -247,6 +245,32 @@ BOOST_FIXTURE_TEST_CASE( wrap_with_msig, eosio_wrap_tester ) try { BOOST_REQUIRE_EQUAL( "reqauth"_n, name{traces[1]->action_traces[0].act.name} ); BOOST_REQUIRE_EQUAL( transaction_receipt::executed, traces[1]->receipt->status ); + BOOST_REQUIRE( bool(trx_trace) ); + BOOST_REQUIRE( trx_trace->receipt.valid() ); + BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); + BOOST_REQUIRE_EQUAL( 2, trx_trace->action_traces.size() ); + + BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(0).action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).closest_unnotified_ancestor_action_ordinal ); + // EOSIO 1.8 N() macro returns a uint64_t rather than a struct name + BOOST_REQUIRE_EQUAL( name{N(eosio.msig)}, action_name{trx_trace->action_traces.at(0).receiver} ); + BOOST_REQUIRE_EQUAL( name{N(eosio.msig)}, name{trx_trace->action_traces.at(0).act.account} ); + BOOST_REQUIRE_EQUAL( name{N(exec)}, name{trx_trace->action_traces.at(0).act.name} ); + BOOST_REQUIRE_EQUAL( name{N(alice)}, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); + + BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(1).action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).closest_unnotified_ancestor_action_ordinal ); + BOOST_REQUIRE_EQUAL( name{N(eosio.wrap)}, action_name{trx_trace->action_traces.at(1).receiver} ); + BOOST_REQUIRE_EQUAL( name{N(eosio.wrap)}, name{trx_trace->action_traces.at(1).act.account} ); + BOOST_REQUIRE_EQUAL( name{N(exec)}, name{trx_trace->action_traces.at(1).act.name} ); + BOOST_REQUIRE_EQUAL( name{N(alice)}, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); + BOOST_REQUIRE_EQUAL( name{N(eosio.wrap)}, name{trx_trace->action_traces.at(1).act.authorization[1].actor} ); + BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(1).act.authorization[1].permission} ); + } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( wrap_with_msig_unapprove, eosio_wrap_tester ) try { @@ -336,17 +360,15 @@ BOOST_FIXTURE_TEST_CASE( wrap_with_msig_producers_change, eosio_wrap_tester ) tr vector traces; control->applied_transaction.connect( [&]( std::tuple p ) { - const auto& t = std::get<0>(p); - if( t->scheduled ) { - traces.push_back( t ); - } + traces.push_back( std::get<0>(p) ); } ); // Now the proposal should be ready to execute - push_action( "eosio.msig"_n, "exec"_n, "alice"_n, mvo() - ("proposer", "carol") - ("proposal_name", "first") - ("executer", "alice") + transaction_trace_ptr trx_trace; + trx_trace = push_action( "eosio.msig"_n, "exec"_n, "alice"_n, mvo() + ("proposer", "carol") + ("proposal_name", "first") + ("executer", "alice") ); produce_block(); @@ -363,6 +385,32 @@ BOOST_FIXTURE_TEST_CASE( wrap_with_msig_producers_change, eosio_wrap_tester ) tr BOOST_REQUIRE_EQUAL( "reqauth"_n, name{traces[1]->action_traces[0].act.name} ); BOOST_REQUIRE_EQUAL( transaction_receipt::executed, traces[1]->receipt->status ); + BOOST_REQUIRE( bool(trx_trace) ); + BOOST_REQUIRE( trx_trace->receipt.valid() ); + BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); + BOOST_REQUIRE_EQUAL( 2, trx_trace->action_traces.size() ); + + BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(0).action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).closest_unnotified_ancestor_action_ordinal ); + // EOSIO 1.8 N() macro returns a uint64_t rather than a struct name + BOOST_REQUIRE_EQUAL( name{N(eosio.msig)}, action_name{trx_trace->action_traces.at(0).receiver} ); + BOOST_REQUIRE_EQUAL( name{N(eosio.msig)}, name{trx_trace->action_traces.at(0).act.account} ); + BOOST_REQUIRE_EQUAL( name{N(exec)}, name{trx_trace->action_traces.at(0).act.name} ); + BOOST_REQUIRE_EQUAL( name{N(alice)}, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); + + BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(1).action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).closest_unnotified_ancestor_action_ordinal ); + BOOST_REQUIRE_EQUAL( name{N(eosio.wrap)}, action_name{trx_trace->action_traces.at(1).receiver} ); + BOOST_REQUIRE_EQUAL( name{N(eosio.wrap)}, name{trx_trace->action_traces.at(1).act.account} ); + BOOST_REQUIRE_EQUAL( name{N(exec)}, name{trx_trace->action_traces.at(1).act.name} ); + BOOST_REQUIRE_EQUAL( name{N(alice)}, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); + BOOST_REQUIRE_EQUAL( name{N(eosio.wrap)}, name{trx_trace->action_traces.at(1).act.authorization[1].actor} ); + BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(1).act.authorization[1].permission} ); + } FC_LOG_AND_RETHROW() BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/sendinline.cpp b/tests/sendinline.cpp new file mode 100644 index 00000000..88c0c01e --- /dev/null +++ b/tests/sendinline.cpp @@ -0,0 +1,25 @@ +#include +#include +#include +#include +#include + +/// `eosio.code` is a virtual permission (there is no private or public +/// key associated with it). Therefore, this test tests how `eosio.msig` +/// contract reacts to a smart contract submitting a proposal and +/// approving/unnapproving itself. +class [[eosio::contract]] +sendinline : public eosio::contract { +public: + using contract::contract; + + [[eosio::action]] + void send( eosio::name contract, eosio::name action_name, std::vector auths, std::vector payload) { + eosio::action act; + act.account = contract; + act.name = action_name; + act.authorization = auths; + act.data = std::move(payload); + act.send(); + } +}; From abe3d6df67f74d27100fbb5266c1be11a20e1cb6 Mon Sep 17 00:00:00 2001 From: Dmytro Sydorchenko Date: Fri, 7 Oct 2022 18:30:27 -0400 Subject: [PATCH 18/96] fix build issues --- tests/eosio.msig_tests.cpp | 156 +++++++++--------- tests/eosio.system_tests.cpp | 2 +- tests/eosio.wrap_tests.cpp | 50 +++--- .../test_contracts/sendinline/CMakeLists.txt | 4 + .../sendinline/src}/sendinline.cpp | 0 5 files changed, 105 insertions(+), 107 deletions(-) create mode 100644 tests/test_contracts/sendinline/CMakeLists.txt rename tests/{ => test_contracts/sendinline/src}/sendinline.cpp (100%) diff --git a/tests/eosio.msig_tests.cpp b/tests/eosio.msig_tests.cpp index 6b4e692f..e81a759e 100644 --- a/tests/eosio.msig_tests.cpp +++ b/tests/eosio.msig_tests.cpp @@ -331,7 +331,7 @@ BOOST_FIXTURE_TEST_CASE( big_transaction, eosio_msig_tester ) try { //change `default_max_inline_action_size` to 512 KB eosio::chain::chain_config params = control->get_global_properties().configuration; params.max_inline_action_size = 512 * 1024; - base_tester::push_action( config::system_account_name, N(setparams), config::system_account_name, mutable_variant_object() + base_tester::push_action( config::system_account_name, "setparams"_n, config::system_account_name, mutable_variant_object() ("params", params) ); produce_blocks(); @@ -522,7 +522,6 @@ BOOST_FIXTURE_TEST_CASE( update_system_contract_all_approve, eosio_msig_tester ) ); BOOST_REQUIRE( bool(trx_trace) ); - BOOST_REQUIRE( trx_trace->receipt.valid() ); BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); BOOST_REQUIRE_EQUAL( 2, trx_trace->action_traces.size() ); @@ -530,20 +529,20 @@ BOOST_FIXTURE_TEST_CASE( update_system_contract_all_approve, eosio_msig_tester ) BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).creator_action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).closest_unnotified_ancestor_action_ordinal ); // EOSIO 1.8 N() macro returns a uint64_t rather than a struct name - BOOST_REQUIRE_EQUAL( name{N(eosio.msig)}, action_name{trx_trace->action_traces.at(0).receiver} ); - BOOST_REQUIRE_EQUAL( name{N(eosio.msig)}, name{trx_trace->action_traces.at(0).act.account} ); - BOOST_REQUIRE_EQUAL( name{N(exec)}, name{trx_trace->action_traces.at(0).act.name} ); - BOOST_REQUIRE_EQUAL( name{N(alice)}, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, action_name{trx_trace->action_traces.at(0).receiver} ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, name{trx_trace->action_traces.at(0).act.account} ); + BOOST_REQUIRE_EQUAL( "exec"_n, name{trx_trace->action_traces.at(0).act.name} ); + BOOST_REQUIRE_EQUAL( "alice"_n, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( "ctive"_n, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(1).action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).creator_action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( name{N(eosio)}, action_name{trx_trace->action_traces.at(1).receiver} ); - BOOST_REQUIRE_EQUAL( name{N(eosio)}, name{trx_trace->action_traces.at(1).act.account} ); - BOOST_REQUIRE_EQUAL( name{N(setcode)}, name{trx_trace->action_traces.at(1).act.name} ); - BOOST_REQUIRE_EQUAL( name{N(eosio)}, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); + BOOST_REQUIRE_EQUAL( "eosio"_n, action_name{trx_trace->action_traces.at(1).receiver} ); + BOOST_REQUIRE_EQUAL( "eosio"_n, name{trx_trace->action_traces.at(1).act.account} ); + BOOST_REQUIRE_EQUAL( "setcode"_n, name{trx_trace->action_traces.at(1).act.name} ); + BOOST_REQUIRE_EQUAL( "eosio"_n, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); // can't create account because system contract was replaced by the reject_all contract @@ -679,7 +678,6 @@ BOOST_FIXTURE_TEST_CASE( update_system_contract_major_approve, eosio_msig_tester ); BOOST_REQUIRE( bool(trx_trace) ); - BOOST_REQUIRE( trx_trace->receipt.valid() ); BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); BOOST_REQUIRE_EQUAL( 2, trx_trace->action_traces.size() ); @@ -687,20 +685,20 @@ BOOST_FIXTURE_TEST_CASE( update_system_contract_major_approve, eosio_msig_tester BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).creator_action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).closest_unnotified_ancestor_action_ordinal ); // EOSIO 1.8 N() macro returns a uint64_t rather than a struct name - BOOST_REQUIRE_EQUAL( name{N(eosio.msig)}, action_name{trx_trace->action_traces.at(0).receiver} ); - BOOST_REQUIRE_EQUAL( name{N(eosio.msig)}, name{trx_trace->action_traces.at(0).act.account} ); - BOOST_REQUIRE_EQUAL( name{N(exec)}, name{trx_trace->action_traces.at(0).act.name} ); - BOOST_REQUIRE_EQUAL( name{N(apple)}, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, action_name{trx_trace->action_traces.at(0).receiver} ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, name{trx_trace->action_traces.at(0).act.account} ); + BOOST_REQUIRE_EQUAL( "exec"_n, name{trx_trace->action_traces.at(0).act.name} ); + BOOST_REQUIRE_EQUAL( "apple"_n, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(1).action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).creator_action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( name{N(eosio)}, action_name{trx_trace->action_traces.at(1).receiver} ); - BOOST_REQUIRE_EQUAL( name{N(eosio)}, name{trx_trace->action_traces.at(1).act.account} ); - BOOST_REQUIRE_EQUAL( name{N(setcode)}, name{trx_trace->action_traces.at(1).act.name} ); - BOOST_REQUIRE_EQUAL( name{N(eosio)}, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); + BOOST_REQUIRE_EQUAL( "eosio"_n, action_name{trx_trace->action_traces.at(1).receiver} ); + BOOST_REQUIRE_EQUAL( "eosio"_n, name{trx_trace->action_traces.at(1).act.account} ); + BOOST_REQUIRE_EQUAL( "setcode"_n, name{trx_trace->action_traces.at(1).act.name} ); + BOOST_REQUIRE_EQUAL( "eosio"_n, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); // can't create account because system contract was replaced by the reject_all contract @@ -1040,36 +1038,36 @@ BOOST_FIXTURE_TEST_CASE( switch_proposal_and_fail_approve_with_hash, eosio_msig_ } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( sendinline, eosio_msig_tester ) try { - create_accounts( {N(sendinline)} ); - set_code( N(sendinline), contracts::util::sendinline_wasm() ); - set_abi( N(sendinline), contracts::util::sendinline_abi().data() ); + create_accounts( {"sendinline"_n} ); + set_code( "sendinline"_n, contracts::util::sendinline_wasm() ); + set_abi( "sendinline"_n, contracts::util::sendinline_abi().data() ); - create_accounts( {N(wrongcon)} ); - set_code( N(wrongcon), contracts::util::sendinline_wasm() ); - set_abi( N(wrongcon), contracts::util::sendinline_abi().data() ); + create_accounts( {"wrongcon"_n} ); + set_code( "wrongcon"_n, contracts::util::sendinline_wasm() ); + set_abi( "wrongcon"_n, contracts::util::sendinline_abi().data() ); produce_blocks(); - action act = get_action( config::system_account_name, N(reqauth), {}, mvo()("from", "alice")); + action act = get_action( config::system_account_name, "reqauth"_n, {}, mvo()("from", "alice")); - BOOST_REQUIRE_EXCEPTION( base_tester::push_action( N(sendinline), N(send), N(bob), mvo() + BOOST_REQUIRE_EXCEPTION( base_tester::push_action( "sendinline"_n, "send"_n, "bob"_n, mvo() ("contract", "eosio") ("action_name", "reqauth") - ("auths", std::vector{ {N(alice), config::active_name} }) + ("auths", std::vector{ {"alice"_n, config::active_name} }) ("payload", act.data) ), unsatisfied_authorization, fc_exception_message_starts_with("transaction declares authority") ); - base_tester::push_action(config::system_account_name, N(updateauth), N(alice), mvo() + base_tester::push_action(config::system_account_name, "updateauth"_n, "alice"_n, mvo() ("account", "alice") ("permission", "perm") ("parent", "active") - ("auth", authority{ 1, {}, {permission_level_weight{ {N(sendinline), config::eosio_code_name}, 1}}, {} }) + ("auth", authority{ 1, {}, {permission_level_weight{ {"sendinline"_n, config::eosio_code_name}, 1}}, {} }) ); produce_blocks(); - base_tester::push_action( config::system_account_name, N(linkauth), N(alice), mvo() + base_tester::push_action( config::system_account_name, "linkauth"_n, "alice"_n, mvo() ("account", "alice") ("code", "eosio") ("type", "reqauth") @@ -1078,16 +1076,15 @@ BOOST_FIXTURE_TEST_CASE( sendinline, eosio_msig_tester ) try { produce_blocks(); transaction_trace_ptr trx_trace; - trx_trace = base_tester::push_action( N(sendinline), N(send), N(bob), mvo() + trx_trace = base_tester::push_action( "sendinline"_n, "send"_n, "bob"_n, mvo() ("contract", "eosio") ("action_name", "reqauth") - ("auths", std::vector{ {N(alice), N(perm)} }) + ("auths", std::vector{ {"alice"_n, "perm"_n} }) ("payload", act.data) ); produce_blocks(); BOOST_REQUIRE( bool(trx_trace) ); - BOOST_REQUIRE( trx_trace->receipt.valid() ); BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); BOOST_REQUIRE_EQUAL( 2, trx_trace->action_traces.size() ); @@ -1095,77 +1092,77 @@ BOOST_FIXTURE_TEST_CASE( sendinline, eosio_msig_tester ) try { BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).creator_action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).closest_unnotified_ancestor_action_ordinal ); // EOSIO 1.8 N() macro returns a uint64_t rather than a struct name - BOOST_REQUIRE_EQUAL( name{N(sendinline)}, action_name{trx_trace->action_traces.at(0).receiver} ); - BOOST_REQUIRE_EQUAL( name{N(sendinline)}, name{trx_trace->action_traces.at(0).act.account} ); - BOOST_REQUIRE_EQUAL( name{N(send)}, name{trx_trace->action_traces.at(0).act.name} ); - BOOST_REQUIRE_EQUAL( name{N(bob)}, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); + BOOST_REQUIRE_EQUAL( "sendinline"_n, action_name{trx_trace->action_traces.at(0).receiver} ); + BOOST_REQUIRE_EQUAL( "sendinline"_n, name{trx_trace->action_traces.at(0).act.account} ); + BOOST_REQUIRE_EQUAL( "send"_n, name{trx_trace->action_traces.at(0).act.name} ); + BOOST_REQUIRE_EQUAL( "bob"_n, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(1).action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).creator_action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( name{N(eosio)}, action_name{trx_trace->action_traces.at(1).receiver} ); - BOOST_REQUIRE_EQUAL( name{N(eosio)}, name{trx_trace->action_traces.at(1).act.account} ); - BOOST_REQUIRE_EQUAL( name{N(reqauth)}, name{trx_trace->action_traces.at(1).act.name} ); - BOOST_REQUIRE_EQUAL( name{N(alice)}, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( name{N(perm)}, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); + BOOST_REQUIRE_EQUAL( "eosio"_n, action_name{trx_trace->action_traces.at(1).receiver} ); + BOOST_REQUIRE_EQUAL( "eosio"_n, name{trx_trace->action_traces.at(1).act.account} ); + BOOST_REQUIRE_EQUAL( "reqauth"_n, name{trx_trace->action_traces.at(1).act.name} ); + BOOST_REQUIRE_EQUAL( "alice"_n, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( "perm"_n, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); - base_tester::push_action(config::system_account_name, updateauth::get_name(), N(sendinline), mvo() + base_tester::push_action(config::system_account_name, updateauth::get_name(), "sendinline"_n, mvo() ("account", "sendinline") ("permission", name(config::active_name)) ("parent", name(config::owner_name)) - ("auth", authority(1, {key_weight{get_public_key("sendinline", "active"), 1}}, { - permission_level_weight{{"sendinline", config::eosio_code_name}, 1} + ("auth", authority(1, {key_weight{get_public_key("sendinline"_n, "active"), 1}}, { + permission_level_weight{{"sendinline"_n, config::eosio_code_name}, 1} } )) ); produce_blocks(); - action approve_act = get_action(N(eosio.msig), N(approve), {}, mvo() + action approve_act = get_action("eosio.msig"_n, "approve"_n, {}, mvo() ("proposer", "bob") ("proposal_name", "first") - ("level", permission_level{N(sendinline), N(eosio.code)}) + ("level", permission_level{"sendinline"_n, "eosio.code"_n}) ); - action unapprove_act = get_action(N(eosio.msig), N(unapprove), {}, mvo() + action unapprove_act = get_action("eosio.msig"_n, "unapprove"_n, {}, mvo() ("proposer", "bob") ("proposal_name", "first") - ("level", permission_level{N(sendinline), N(eosio.code)}) + ("level", permission_level{"sendinline"_n, "eosio.code"_n}) ); - transaction trx = reqauth( N(alice), {permission_level{N(alice), N(perm)}}, abi_serializer_max_time ); + transaction trx = reqauth( "alice"_n, {permission_level{"alice"_n, "perm"_n}}, abi_serializer_max_time ); - base_tester::push_action( N(eosio.msig), N(propose), N(bob), mvo() + base_tester::push_action( "eosio.msig"_n, "propose"_n, "bob"_n, mvo() ("proposer", "bob") ("proposal_name", "first") ("trx", trx) - ("requested", std::vector{{ N(sendinline), N(eosio.code) }}) + ("requested", std::vector{{ "sendinline"_n, "eosio.code"_n }}) ); produce_blocks(); #if 0 // `approve` shall fail when being sent from the wrong contract - BOOST_REQUIRE_EXCEPTION( base_tester::push_action( N(wrongcon), N(send), N(bob), mvo() + BOOST_REQUIRE_EXCEPTION( base_tester::push_action( "wrongcon"_n, "send"_n, "bob"_n, mvo() ("contract", "eosio.msig") ("action_name", "approve") - ("auths", std::vector{{N(bob), config::active_name}}) + ("auths", std::vector{{"bob"_n, config::active_name}}) ("payload", approve_act.data) ), eosio_assert_message_exception, eosio_assert_message_is("wrong contract sent `approve` action for eosio.code permmission") ); // `approve` shall succeed when being sent from the correct contract - base_tester::push_action( N(sendinline), N(send), N(bob), mvo() + base_tester::push_action( "sendinline"_n "send"_n, "bob"_n, mvo() ("contract", "eosio.msig") ("action_name", "approve") - ("auths", std::vector{{N(bob), config::eosio_code_name}}) + ("auths", std::vector{{"bob"_n, config::eosio_code_name}}) ("payload", approve_act.data) ); produce_blocks(); // `unapprove` shall fail when being sent from the wrong contract - BOOST_REQUIRE_EXCEPTION( base_tester::push_action( N(wrongcon), N(send), N(bob), mvo() - ("contract", N(eosio.msig)) + BOOST_REQUIRE_EXCEPTION( base_tester::push_action( "wrongcon"_n, "send"_n, "bob"_n, mvo() + ("contract", "eosio.msig"_n) ("action_name", "unapprove") ("auths", std::vector{}) ("payload", unapprove_act.data) @@ -1175,8 +1172,8 @@ BOOST_FIXTURE_TEST_CASE( sendinline, eosio_msig_tester ) try { ); // `unapprove` shall succeed when being sent from the correct contract - base_tester::push_action( N(sendinline), N(send), N(bob), mvo() - ("contract", N(eosio.msig)) + base_tester::push_action( "sendinline"_n, "send"_n, "bob"_n, mvo() + ("contract", "eosio.msig"_n) ("action_name", "unapprove") ("auths", std::vector{}) ("payload", unapprove_act.data) @@ -1184,42 +1181,41 @@ BOOST_FIXTURE_TEST_CASE( sendinline, eosio_msig_tester ) try { produce_blocks(); #endif // `approve` to get back into a state ready for `exec` - base_tester::push_action( N(sendinline), N(send), N(bob), mvo() + base_tester::push_action( "sendinline"_n, "send"_n, "bob"_n, mvo() ("contract", "eosio.msig") ("action_name", "approve") - ("auths", std::vector{{N(sendinline), config::active_name}}) + ("auths", std::vector{{"sendinline"_n, config::active_name}}) ("payload", approve_act.data) ); produce_blocks(); - trx_trace = base_tester::push_action( N(eosio.msig), N(exec), N(bob), mvo() + trx_trace = base_tester::push_action( "eosio.msig"_n, "exec"_n, "bob"_n, mvo() ("proposer", "bob") ("proposal_name", "first") ("executer", "bob") ); BOOST_REQUIRE( bool(trx_trace) ); - BOOST_REQUIRE( trx_trace->receipt.valid() ); BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); BOOST_REQUIRE_EQUAL( 2, trx_trace->action_traces.size() ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(0).action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).creator_action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( name{N(eosio.msig)}, action_name{trx_trace->action_traces.at(0).receiver} ); - BOOST_REQUIRE_EQUAL( name{N(eosio.msig)}, name{trx_trace->action_traces.at(0).act.account} ); - BOOST_REQUIRE_EQUAL( name{N(exec)}, name{trx_trace->action_traces.at(0).act.name} ); - BOOST_REQUIRE_EQUAL( name{N(bob)}, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, action_name{trx_trace->action_traces.at(0).receiver} ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, name{trx_trace->action_traces.at(0).act.account} ); + BOOST_REQUIRE_EQUAL( "exec"_n, name{trx_trace->action_traces.at(0).act.name} ); + BOOST_REQUIRE_EQUAL( "bob"_n, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(1).action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).creator_action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( name{N(eosio)}, action_name{trx_trace->action_traces.at(1).receiver} ); - BOOST_REQUIRE_EQUAL( name{N(eosio)}, name{trx_trace->action_traces.at(1).act.account} ); - BOOST_REQUIRE_EQUAL( name{N(reqauth)}, name{trx_trace->action_traces.at(1).act.name} ); - BOOST_REQUIRE_EQUAL( name{N(alice)}, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( name{N(perm)}, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); + BOOST_REQUIRE_EQUAL( "eosio"_n, action_name{trx_trace->action_traces.at(1).receiver} ); + BOOST_REQUIRE_EQUAL( "eosio"_n, name{trx_trace->action_traces.at(1).act.account} ); + BOOST_REQUIRE_EQUAL( "reqauth"_n, name{trx_trace->action_traces.at(1).act.name} ); + BOOST_REQUIRE_EQUAL( "alice"_n, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( "perm"_n, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); } FC_LOG_AND_RETHROW() diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index aff4a4b4..1c476c03 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -2732,7 +2732,7 @@ BOOST_FIXTURE_TEST_CASE(producers_upgrade_system_contract, eosio_system_tester) //change `default_max_inline_action_size` to 512 KB eosio::chain::chain_config params = control->get_global_properties().configuration; params.max_inline_action_size = 512 * 1024; - base_tester::push_action( config::system_account_name, N(setparams), config::system_account_name, mutable_variant_object() + base_tester::push_action( config::system_account_name, "setparams"_n, config::system_account_name, mutable_variant_object() ("params", params) ); produce_blocks(); diff --git a/tests/eosio.wrap_tests.cpp b/tests/eosio.wrap_tests.cpp index 4e2b9d49..6910f724 100644 --- a/tests/eosio.wrap_tests.cpp +++ b/tests/eosio.wrap_tests.cpp @@ -246,7 +246,6 @@ BOOST_FIXTURE_TEST_CASE( wrap_with_msig, eosio_wrap_tester ) try { BOOST_REQUIRE_EQUAL( transaction_receipt::executed, traces[1]->receipt->status ); BOOST_REQUIRE( bool(trx_trace) ); - BOOST_REQUIRE( trx_trace->receipt.valid() ); BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); BOOST_REQUIRE_EQUAL( 2, trx_trace->action_traces.size() ); @@ -254,22 +253,22 @@ BOOST_FIXTURE_TEST_CASE( wrap_with_msig, eosio_wrap_tester ) try { BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).creator_action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).closest_unnotified_ancestor_action_ordinal ); // EOSIO 1.8 N() macro returns a uint64_t rather than a struct name - BOOST_REQUIRE_EQUAL( name{N(eosio.msig)}, action_name{trx_trace->action_traces.at(0).receiver} ); - BOOST_REQUIRE_EQUAL( name{N(eosio.msig)}, name{trx_trace->action_traces.at(0).act.account} ); - BOOST_REQUIRE_EQUAL( name{N(exec)}, name{trx_trace->action_traces.at(0).act.name} ); - BOOST_REQUIRE_EQUAL( name{N(alice)}, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, action_name{trx_trace->action_traces.at(0).receiver} ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, name{trx_trace->action_traces.at(0).act.account} ); + BOOST_REQUIRE_EQUAL( "exec"_n, name{trx_trace->action_traces.at(0).act.name} ); + BOOST_REQUIRE_EQUAL( "alice"_n, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(1).action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).creator_action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( name{N(eosio.wrap)}, action_name{trx_trace->action_traces.at(1).receiver} ); - BOOST_REQUIRE_EQUAL( name{N(eosio.wrap)}, name{trx_trace->action_traces.at(1).act.account} ); - BOOST_REQUIRE_EQUAL( name{N(exec)}, name{trx_trace->action_traces.at(1).act.name} ); - BOOST_REQUIRE_EQUAL( name{N(alice)}, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); - BOOST_REQUIRE_EQUAL( name{N(eosio.wrap)}, name{trx_trace->action_traces.at(1).act.authorization[1].actor} ); - BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(1).act.authorization[1].permission} ); + BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, action_name{trx_trace->action_traces.at(1).receiver} ); + BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, name{trx_trace->action_traces.at(1).act.account} ); + BOOST_REQUIRE_EQUAL( "exec"_n, name{trx_trace->action_traces.at(1).act.name} ); + BOOST_REQUIRE_EQUAL( "alice"_n, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); + BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, name{trx_trace->action_traces.at(1).act.authorization[1].actor} ); + BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(1).act.authorization[1].permission} ); } FC_LOG_AND_RETHROW() @@ -386,7 +385,6 @@ BOOST_FIXTURE_TEST_CASE( wrap_with_msig_producers_change, eosio_wrap_tester ) tr BOOST_REQUIRE_EQUAL( transaction_receipt::executed, traces[1]->receipt->status ); BOOST_REQUIRE( bool(trx_trace) ); - BOOST_REQUIRE( trx_trace->receipt.valid() ); BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); BOOST_REQUIRE_EQUAL( 2, trx_trace->action_traces.size() ); @@ -394,22 +392,22 @@ BOOST_FIXTURE_TEST_CASE( wrap_with_msig_producers_change, eosio_wrap_tester ) tr BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).creator_action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).closest_unnotified_ancestor_action_ordinal ); // EOSIO 1.8 N() macro returns a uint64_t rather than a struct name - BOOST_REQUIRE_EQUAL( name{N(eosio.msig)}, action_name{trx_trace->action_traces.at(0).receiver} ); - BOOST_REQUIRE_EQUAL( name{N(eosio.msig)}, name{trx_trace->action_traces.at(0).act.account} ); - BOOST_REQUIRE_EQUAL( name{N(exec)}, name{trx_trace->action_traces.at(0).act.name} ); - BOOST_REQUIRE_EQUAL( name{N(alice)}, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, action_name{trx_trace->action_traces.at(0).receiver} ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, name{trx_trace->action_traces.at(0).act.account} ); + BOOST_REQUIRE_EQUAL( "exec"_n, name{trx_trace->action_traces.at(0).act.name} ); + BOOST_REQUIRE_EQUAL( "alice"_n, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(1).action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).creator_action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( name{N(eosio.wrap)}, action_name{trx_trace->action_traces.at(1).receiver} ); - BOOST_REQUIRE_EQUAL( name{N(eosio.wrap)}, name{trx_trace->action_traces.at(1).act.account} ); - BOOST_REQUIRE_EQUAL( name{N(exec)}, name{trx_trace->action_traces.at(1).act.name} ); - BOOST_REQUIRE_EQUAL( name{N(alice)}, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); - BOOST_REQUIRE_EQUAL( name{N(eosio.wrap)}, name{trx_trace->action_traces.at(1).act.authorization[1].actor} ); - BOOST_REQUIRE_EQUAL( name{N(active)}, name{trx_trace->action_traces.at(1).act.authorization[1].permission} ); + BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, action_name{trx_trace->action_traces.at(1).receiver} ); + BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, name{trx_trace->action_traces.at(1).act.account} ); + BOOST_REQUIRE_EQUAL( "exec"_n, name{trx_trace->action_traces.at(1).act.name} ); + BOOST_REQUIRE_EQUAL( "alice"_n, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); + BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, name{trx_trace->action_traces.at(1).act.authorization[1].actor} ); + BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(1).act.authorization[1].permission} ); } FC_LOG_AND_RETHROW() diff --git a/tests/test_contracts/sendinline/CMakeLists.txt b/tests/test_contracts/sendinline/CMakeLists.txt new file mode 100644 index 00000000..9c03a8d7 --- /dev/null +++ b/tests/test_contracts/sendinline/CMakeLists.txt @@ -0,0 +1,4 @@ +find_package(eosio.cdt) +add_contract(sendinline sendinline ${CMAKE_CURRENT_SOURCE_DIR}/src/sendinline.cpp) +target_include_directories(sendinline.wasm PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) +set_target_properties(sendinline.wasm PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") \ No newline at end of file diff --git a/tests/sendinline.cpp b/tests/test_contracts/sendinline/src/sendinline.cpp similarity index 100% rename from tests/sendinline.cpp rename to tests/test_contracts/sendinline/src/sendinline.cpp From c9e4be1d6290ee50f6318f0c7bcceff795d0e051 Mon Sep 17 00:00:00 2001 From: Dmytro Sydorchenko Date: Fri, 7 Oct 2022 18:52:48 -0400 Subject: [PATCH 19/96] Switch test to active permission from code and removed unused code --- tests/eosio.msig_tests.cpp | 50 ++------------------------------------ 1 file changed, 2 insertions(+), 48 deletions(-) diff --git a/tests/eosio.msig_tests.cpp b/tests/eosio.msig_tests.cpp index e81a759e..d612b8fd 100644 --- a/tests/eosio.msig_tests.cpp +++ b/tests/eosio.msig_tests.cpp @@ -1063,7 +1063,7 @@ BOOST_FIXTURE_TEST_CASE( sendinline, eosio_msig_tester ) try { ("account", "alice") ("permission", "perm") ("parent", "active") - ("auth", authority{ 1, {}, {permission_level_weight{ {"sendinline"_n, config::eosio_code_name}, 1}}, {} }) + ("auth", authority{ 1, {}, {permission_level_weight{ {"sendinline"_n, config::active_name}, 1}}, {} }) ); produce_blocks(); @@ -1125,12 +1125,6 @@ BOOST_FIXTURE_TEST_CASE( sendinline, eosio_msig_tester ) try { ("level", permission_level{"sendinline"_n, "eosio.code"_n}) ); - action unapprove_act = get_action("eosio.msig"_n, "unapprove"_n, {}, mvo() - ("proposer", "bob") - ("proposal_name", "first") - ("level", permission_level{"sendinline"_n, "eosio.code"_n}) - ); - transaction trx = reqauth( "alice"_n, {permission_level{"alice"_n, "perm"_n}}, abi_serializer_max_time ); base_tester::push_action( "eosio.msig"_n, "propose"_n, "bob"_n, mvo() @@ -1140,47 +1134,7 @@ BOOST_FIXTURE_TEST_CASE( sendinline, eosio_msig_tester ) try { ("requested", std::vector{{ "sendinline"_n, "eosio.code"_n }}) ); produce_blocks(); -#if 0 - // `approve` shall fail when being sent from the wrong contract - BOOST_REQUIRE_EXCEPTION( base_tester::push_action( "wrongcon"_n, "send"_n, "bob"_n, mvo() - ("contract", "eosio.msig") - ("action_name", "approve") - ("auths", std::vector{{"bob"_n, config::active_name}}) - ("payload", approve_act.data) - ), - eosio_assert_message_exception, - eosio_assert_message_is("wrong contract sent `approve` action for eosio.code permmission") - ); - // `approve` shall succeed when being sent from the correct contract - base_tester::push_action( "sendinline"_n "send"_n, "bob"_n, mvo() - ("contract", "eosio.msig") - ("action_name", "approve") - ("auths", std::vector{{"bob"_n, config::eosio_code_name}}) - ("payload", approve_act.data) - ); - produce_blocks(); - - // `unapprove` shall fail when being sent from the wrong contract - BOOST_REQUIRE_EXCEPTION( base_tester::push_action( "wrongcon"_n, "send"_n, "bob"_n, mvo() - ("contract", "eosio.msig"_n) - ("action_name", "unapprove") - ("auths", std::vector{}) - ("payload", unapprove_act.data) - ), - eosio_assert_message_exception, - eosio_assert_message_is("wrong contract sent `unapprove` action for eosio.code permmission") - ); - - // `unapprove` shall succeed when being sent from the correct contract - base_tester::push_action( "sendinline"_n, "send"_n, "bob"_n, mvo() - ("contract", "eosio.msig"_n) - ("action_name", "unapprove") - ("auths", std::vector{}) - ("payload", unapprove_act.data) - ); - produce_blocks(); -#endif - // `approve` to get back into a state ready for `exec` + base_tester::push_action( "sendinline"_n, "send"_n, "bob"_n, mvo() ("contract", "eosio.msig") ("action_name", "approve") From 9047a565c101c8e5493f2567f1cfe0956c273906 Mon Sep 17 00:00:00 2001 From: Dmytro Sydorchenko Date: Fri, 7 Oct 2022 20:31:38 -0400 Subject: [PATCH 20/96] Patch of OOB Patch to v1.8.3 --- .../include/eosio.msig/eosio.msig.hpp | 272 +++++++++++++++--- contracts/eosio.msig/src/eosio.msig.cpp | 189 +++++++----- 2 files changed, 358 insertions(+), 103 deletions(-) diff --git a/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp b/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp index 19f2600c..62b85110 100644 --- a/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp +++ b/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp @@ -6,6 +6,203 @@ #include namespace eosio { + /** + * Clone of `eosio::binary_extension` that includes `operator=` to avoid + * bumping the `eosio.cdt` dependency version of the v1.8.x patch release of + * `eosio.contracts`. + */ + template + class eosio_msig_binary_extension { + public: + using value_type = T; + + constexpr eosio_msig_binary_extension() {} + constexpr eosio_msig_binary_extension( const T& ext ) + :_has_value(true) + { + ::new (&_data) T(ext); + } + constexpr eosio_msig_binary_extension( T&& ext ) + :_has_value(true) + { + ::new (&_data) T(std::move(ext)); + } + /** construct contained type in place */ + template + constexpr eosio_msig_binary_extension( std::in_place_t, Args&&... args ) + :_has_value(true) + { + ::new (&_data) T(std::forward(args)...); + } + + constexpr eosio_msig_binary_extension( const eosio_msig_binary_extension& other ) + :_has_value(other._has_value) + { + if( other._has_value ) ::new (&_data) T( *other ); + } + + constexpr eosio_msig_binary_extension( eosio_msig_binary_extension&& other ) + :_has_value(other._has_value) + { + if( other._has_value ) { + ::new (&_data) T( *std::move(other) ); + other._has_value = false; + } + } + + /// @cond INTERNAL + ~eosio_msig_binary_extension() { reset(); } + + /// @cond INTERNAL + constexpr eosio_msig_binary_extension& operator= (const eosio_msig_binary_extension& other) { + if (has_value()) + reset(); + + if (other.has_value()) { + ::new (&_data) T(*other); + _has_value = true; + } + return *this; + } + + /// @cond INTERNAL + constexpr eosio_msig_binary_extension& operator= (eosio_msig_binary_extension&& other) { + if (has_value()) + reset(); + + if (other.has_value()) { + ::new (&_data) T(*other); + _has_value = true; + other._has_value = false; + } + return *this; + } + /** test if container is holding a value */ + constexpr explicit operator bool()const { return _has_value; } + /** test if container is holding a value */ + constexpr bool has_value()const { return _has_value; } + + /** get the contained value */ + constexpr T& value()& { + if (!_has_value) { + check(false, "cannot get value of empty eosio_msig_binary_extension"); + } + return _get(); + } + + /// @cond INTERNAL + + /** get the contained value */ + constexpr const T& value()const & { + if (!_has_value) { + check(false, "cannot get value of empty eosio_msig_binary_extension"); + } + return _get(); + } + + /** get the contained value or a user specified default + * @pre def should be convertible to type T + * */ + template + constexpr auto value_or( U&& def ) -> std::enable_if_t::value, T&>& { + if (_has_value) + return _get(); + return def; + } + + constexpr T value_or() const { return (-_has_value) ? _get() : T{}; } + + constexpr T* operator->() { + return &_get(); + } + constexpr const T* operator->()const { + return &_get(); + } + + constexpr T& operator*()& { + return _get(); + } + constexpr const T& operator*()const& { + return _get(); + } + constexpr const T&& operator*()const&& { + return std::move(_get()); + } + constexpr T&& operator*()&& { + return std::move(_get()); + } + + template + T& emplace(Args&& ... args)& { + if (_has_value) { + reset(); + } + + ::new (&_data) T( std::forward(args)... ); + _has_value = true; + + return _get(); + } + + void reset() { + if( _has_value ) { + _get().~value_type(); + _has_value = false; + } + } + + /// @endcond + + private: + bool _has_value = false; + typename std::aligned_storage::type _data; + + constexpr T& _get() { + return *reinterpret_cast(&_data); + } + + constexpr const T& _get()const { + return *reinterpret_cast(&_data); + } + }; + + /// @cond IMPLEMENTATIONS + + /** + * Serialize a eosio_msig_binary_extension into a stream + * + * @ingroup eosio_msig_binary_extension + * @brief Serialize a eosio_msig_binary_extension + * @param ds - The stream to write + * @param opt - The value to serialize + * @tparam DataStream - Type of datastream buffer + * @return DataStream& - Reference to the datastream + */ + template + inline DataStream& operator<<(DataStream& ds, const eosio::eosio_msig_binary_extension& be) { + ds << be.value_or(); + return ds; + } + + /** + * Deserialize a eosio_msig_binary_extension from a stream + * + * @ingroup eosio_msig_binary_extension + * @brief Deserialize a eosio_msig_binary_extension + * @param ds - The stream to read + * @param opt - The destination for deserialized value + * @tparam DataStream - Type of datastream buffer + * @return DataStream& - Reference to the datastream + */ + template + inline DataStream& operator>>(DataStream& ds, eosio::eosio_msig_binary_extension& be) { + if( ds.remaining() ) { + T val; + ds >> val; + be.emplace(val); + } + return ds; + } /** * The `eosio.msig` system contract allows for creation of proposed transactions which require authorization from a list of accounts, approval of the proposed transactions by those accounts required to approve it, and finally, it also allows the execution of the approved transactions on the blockchain. @@ -37,8 +234,8 @@ namespace eosio { * @param trx - Proposed transaction */ [[eosio::action]] - void propose(ignore proposer, ignore proposal_name, - ignore> requested, ignore trx); + void propose(name proposer, name proposal_name, + std::vector requested, ignore trx); /** * Approve action approves an existing proposal. Allows an account, the owner of `level` permission, to approve a proposal `proposal_name` * proposed by `proposer`. If the proposal's requested approval list contains the `level` @@ -113,50 +310,49 @@ namespace eosio { using exec_action = eosio::action_wrapper<"exec"_n, &multisig::exec>; using invalidate_action = eosio::action_wrapper<"invalidate"_n, &multisig::invalidate>; - private: - struct [[eosio::table]] proposal { - name proposal_name; - std::vector packed_transaction; - - uint64_t primary_key()const { return proposal_name.value; } - }; + struct [[eosio::table]] proposal { + name proposal_name; + std::vector packed_transaction; + eosio::eosio_msig_binary_extension< std::optional > earliest_exec_time; - typedef eosio::multi_index< "proposal"_n, proposal > proposals; + uint64_t primary_key()const { return proposal_name.value; } + }; + typedef eosio::multi_index< "proposal"_n, proposal > proposals; - struct [[eosio::table]] old_approvals_info { - name proposal_name; - std::vector requested_approvals; - std::vector provided_approvals; + struct [[eosio::table]] old_approvals_info { + name proposal_name; + std::vector requested_approvals; + std::vector provided_approvals; - uint64_t primary_key()const { return proposal_name.value; } - }; - typedef eosio::multi_index< "approvals"_n, old_approvals_info > old_approvals; + uint64_t primary_key()const { return proposal_name.value; } + }; + typedef eosio::multi_index< "approvals"_n, old_approvals_info > old_approvals; - struct approval { - permission_level level; - time_point time; - }; + struct approval { + permission_level level; + time_point time; + }; - struct [[eosio::table]] approvals_info { - uint8_t version = 1; - name proposal_name; - //requested approval doesn't need to cointain time, but we want requested approval - //to be of exact the same size ad provided approval, in this case approve/unapprove - //doesn't change serialized data size. So, we use the same type. - std::vector requested_approvals; - std::vector provided_approvals; + struct [[eosio::table]] approvals_info { + uint8_t version = 1; + name proposal_name; + //requested approval doesn't need to contain time, but we want requested approval + //to be of exactly the same size as provided approval, in this case approve/unapprove + //doesn't change serialized data size. So, we use the same type. + std::vector requested_approvals; + std::vector provided_approvals; - uint64_t primary_key()const { return proposal_name.value; } - }; - typedef eosio::multi_index< "approvals2"_n, approvals_info > approvals; + uint64_t primary_key()const { return proposal_name.value; } + }; + typedef eosio::multi_index< "approvals2"_n, approvals_info > approvals; - struct [[eosio::table]] invalidation { - name account; - time_point last_invalidation_time; + struct [[eosio::table]] invalidation { + name account; + time_point last_invalidation_time; - uint64_t primary_key() const { return account.value; } - }; + uint64_t primary_key() const { return account.value; } + }; - typedef eosio::multi_index< "invals"_n, invalidation > invalidations; + typedef eosio::multi_index< "invals"_n, invalidation > invalidations; }; } /// namespace eosio diff --git a/contracts/eosio.msig/src/eosio.msig.cpp b/contracts/eosio.msig/src/eosio.msig.cpp index 843063bf..e24e9688 100644 --- a/contracts/eosio.msig/src/eosio.msig.cpp +++ b/contracts/eosio.msig/src/eosio.msig.cpp @@ -6,54 +6,87 @@ namespace eosio { -void multisig::propose( ignore proposer, - ignore proposal_name, - ignore> requested, +transaction_header get_trx_header(const char* ptr, size_t sz); +bool trx_is_authorized(const std::vector& approvals, const std::vector& packed_trx); + +template +std::vector get_approvals_and_adjust_table(name self, name proposer, name proposal_name, Function&& table_op) { + multisig::approvals approval_table( self, proposer.value ); + auto approval_table_iter = approval_table.find( proposal_name.value ); + std::vector approvals_vector; + multisig::invalidations invalidations_table( self, self.value ); + + if ( approval_table_iter != approval_table.end() ) { + approvals_vector.reserve( approval_table_iter->provided_approvals.size() ); + for ( const auto& permission : approval_table_iter->provided_approvals ) { + auto iter = invalidations_table.find( permission.level.actor.value ); + if ( iter == invalidations_table.end() || iter->last_invalidation_time < permission.time ) { + approvals_vector.push_back(permission.level); + } + } + table_op( approval_table, approval_table_iter ); + } else { + multisig::old_approvals old_approval_table( self, proposer.value ); + const auto& old_approvals_obj = old_approval_table.get( proposal_name.value, "proposal not found" ); + for ( const auto& permission : old_approvals_obj.provided_approvals ) { + auto iter = invalidations_table.find( permission.actor.value ); + if ( iter == invalidations_table.end() ) { + approvals_vector.push_back( permission ); + } + } + table_op( old_approval_table, old_approvals_obj ); + } + return approvals_vector; +} + +void multisig::propose( name proposer, + name proposal_name, + std::vector requested, ignore trx ) { - name _proposer; - name _proposal_name; - std::vector _requested; - transaction_header _trx_header; + require_auth( proposer ); + auto& ds = get_datastream(); - _ds >> _proposer >> _proposal_name >> _requested; + const char* trx_pos = ds.pos(); + size_t size = ds.remaining(); - const char* trx_pos = _ds.pos(); - size_t size = _ds.remaining(); - _ds >> _trx_header; - - require_auth( _proposer ); - check( _trx_header.expiration >= eosio::time_point_sec(current_time_point()), "transaction expired" ); - //check( trx_header.actions.size() > 0, "transaction must have at least one action" ); + transaction_header trx_header; + std::vector context_free_actions; + ds >> trx_header; + check( trx_header.expiration >= eosio::time_point_sec(current_time_point()), "transaction expired" ); + ds >> context_free_actions; + check( context_free_actions.empty(), "not allowed to `propose` a transaction with context-free actions" ); - proposals proptable( get_self(), _proposer.value ); - check( proptable.find( _proposal_name.value ) == proptable.end(), "proposal with the same name exists" ); + proposals proptable( get_self(), proposer.value ); + check( proptable.find( proposal_name.value ) == proptable.end(), "proposal with the same name exists" ); - auto packed_requested = pack(_requested); + auto packed_requested = pack(requested); auto res = check_transaction_authorization( trx_pos, size, (const char*)0, 0, packed_requested.data(), packed_requested.size() - ); + ); check( res > 0, "transaction authorization failed" ); - + std::vector pkd_trans; pkd_trans.resize(size); memcpy((char*)pkd_trans.data(), trx_pos, size); - proptable.emplace( _proposer, [&]( auto& prop ) { - prop.proposal_name = _proposal_name; - prop.packed_transaction = pkd_trans; - }); - - approvals apptable( get_self(), _proposer.value ); - apptable.emplace( _proposer, [&]( auto& a ) { - a.proposal_name = _proposal_name; - a.requested_approvals.reserve( _requested.size() ); - for ( auto& level : _requested ) { - a.requested_approvals.push_back( approval{ level, time_point{ microseconds{0} } } ); - } - }); + + proptable.emplace( proposer, [&]( auto& prop ) { + prop.proposal_name = proposal_name; + prop.packed_transaction = pkd_trans; + prop.earliest_exec_time = std::optional{}; + }); + + approvals apptable( get_self(), proposer.value ); + apptable.emplace( proposer, [&]( auto& a ) { + a.proposal_name = proposal_name; + a.requested_approvals.reserve( requested.size() ); + for ( auto& level : requested ) { + a.requested_approvals.push_back( approval{ level, time_point{ microseconds{0} } } ); + } + }); } void multisig::approve( name proposer, name proposal_name, permission_level level, @@ -61,9 +94,10 @@ void multisig::approve( name proposer, name proposal_name, permission_level leve { require_auth( level ); + proposals proptable( get_self(), proposer.value ); + auto& prop = proptable.get( proposal_name.value, "proposal not found" ); + if( proposal_hash ) { - proposals proptable( get_self(), proposer.value ); - auto& prop = proptable.get( proposal_name.value, "proposal not found" ); assert_sha256( prop.packed_transaction.data(), prop.packed_transaction.size(), *proposal_hash ); } @@ -89,6 +123,21 @@ void multisig::approve( name proposer, name proposal_name, permission_level leve a.requested_approvals.erase( itr ); }); } + + transaction_header trx_header = get_trx_header(prop.packed_transaction.data(), prop.packed_transaction.size()); + + if( prop.earliest_exec_time.has_value() ) { + if( !prop.earliest_exec_time->has_value() ) { + auto table_op = [](auto&&, auto&&){}; + if( trx_is_authorized(get_approvals_and_adjust_table(get_self(), proposer, proposal_name, table_op), prop.packed_transaction) ) { + proptable.modify( prop, proposer, [&]( auto& p ) { + p.earliest_exec_time = std::optional{ current_time_point() + eosio::seconds(trx_header.delay_sec.value)}; + }); + } + } + } else { + check( trx_header.delay_sec.value == 0, "old proposals are not allowed to have non-zero `delay_sec`; cancel and retry" ); + } } void multisig::unapprove( name proposer, name proposal_name, permission_level level ) { @@ -113,6 +162,23 @@ void multisig::unapprove( name proposer, name proposal_name, permission_level le a.provided_approvals.erase( itr ); }); } + + proposals proptable( get_self(), proposer.value ); + auto& prop = proptable.get( proposal_name.value, "proposal not found" ); + + if( prop.earliest_exec_time.has_value() ) { + if( prop.earliest_exec_time->has_value() ) { + auto table_op = [](auto&&, auto&&){}; + if( !trx_is_authorized(get_approvals_and_adjust_table(get_self(), proposer, proposal_name, table_op), prop.packed_transaction) ) { + proptable.modify( prop, proposer, [&]( auto& p ) { + p.earliest_exec_time = std::optional{}; + }); + } + } + } else { + transaction_header trx_header = get_trx_header(prop.packed_transaction.data(), prop.packed_transaction.size()); + check( trx_header.delay_sec.value == 0, "old proposals are not allowed to have non-zero `delay_sec`; cancel and retry" ); + } } void multisig::cancel( name proposer, name proposal_name, name canceler ) { @@ -154,38 +220,15 @@ void multisig::exec( name proposer, name proposal_name, name executer ) { check( context_free_actions.empty(), "not allowed to `exec` a transaction with context-free actions" ); ds >> actions; - approvals apptable( get_self(), proposer.value ); - auto apps_it = apptable.find( proposal_name.value ); - std::vector approvals; - invalidations inv_table( get_self(), get_self().value ); - if ( apps_it != apptable.end() ) { - approvals.reserve( apps_it->provided_approvals.size() ); - for ( auto& p : apps_it->provided_approvals ) { - auto it = inv_table.find( p.level.actor.value ); - if ( it == inv_table.end() || it->last_invalidation_time < p.time ) { - approvals.push_back(p.level); - } - } - apptable.erase(apps_it); + auto table_op = [](auto&& table, auto&& table_iter) { table.erase(table_iter); }; + bool ok = trx_is_authorized(get_approvals_and_adjust_table(get_self(), proposer, proposal_name, table_op), prop.packed_transaction); + check( ok, "transaction authorization failed" ); + + if ( prop.earliest_exec_time.has_value() && prop.earliest_exec_time->has_value() ) { + check( **prop.earliest_exec_time <= current_time_point(), "too early to execute" ); } else { - old_approvals old_apptable( get_self(), proposer.value ); - auto& apps = old_apptable.get( proposal_name.value, "proposal not found" ); - for ( auto& level : apps.provided_approvals ) { - auto it = inv_table.find( level.actor.value ); - if ( it == inv_table.end() ) { - approvals.push_back( level ); - } - } - old_apptable.erase(apps); + check( trx_header.delay_sec.value == 0, "old proposals are not allowed to have non-zero `delay_sec`; cancel and retry" ); } - auto packed_provided_approvals = pack(approvals); - auto res = check_transaction_authorization( - prop.packed_transaction.data(), prop.packed_transaction.size(), - (const char*)0, 0, - packed_provided_approvals.data(), packed_provided_approvals.size() - ); - - check( res > 0, "transaction authorization failed" ); for (const auto& act : actions) { act.send(); @@ -210,4 +253,20 @@ void multisig::invalidate( name account ) { } } +transaction_header get_trx_header(const char* ptr, size_t sz) { + datastream ds = {ptr, sz}; + transaction_header trx_header; + ds >> trx_header; + return trx_header; +} + +bool trx_is_authorized(const std::vector& approvals, const std::vector& packed_trx) { + auto packed_approvals = pack(approvals); + return check_transaction_authorization( + packed_trx.data(), packed_trx.size(), + (const char*)0, 0, + packed_approvals.data(), packed_approvals.size() + ); +} + } /// namespace eosio From eaa601171836096247222fb4cc0dacac2311b64b Mon Sep 17 00:00:00 2001 From: Dmytro Sydorchenko Date: Fri, 7 Oct 2022 20:36:48 -0400 Subject: [PATCH 21/96] Fix typo --- contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp b/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp index 62b85110..cc6809cf 100644 --- a/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp +++ b/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp @@ -110,7 +110,7 @@ namespace eosio { return def; } - constexpr T value_or() const { return (-_has_value) ? _get() : T{}; } + constexpr T value_or() const { return (_has_value) ? _get() : T{}; } constexpr T* operator->() { return &_get(); From fe5282ee82a6735e7de03b7714a85bbcd3b0de40 Mon Sep 17 00:00:00 2001 From: Dmytro Sydorchenko Date: Fri, 7 Oct 2022 20:42:33 -0400 Subject: [PATCH 22/96] =?UTF-8?q?added=20appropriate=20annotations=20and?= =?UTF-8?q?=20downgraded=20binary=20extension=20to=20the=20=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../include/eosio.msig/eosio.msig.hpp | 261 ++---------------- contracts/eosio.msig/src/eosio.msig.cpp | 6 +- 2 files changed, 33 insertions(+), 234 deletions(-) diff --git a/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp b/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp index cc6809cf..d33b0412 100644 --- a/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp +++ b/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp @@ -6,204 +6,6 @@ #include namespace eosio { - /** - * Clone of `eosio::binary_extension` that includes `operator=` to avoid - * bumping the `eosio.cdt` dependency version of the v1.8.x patch release of - * `eosio.contracts`. - */ - template - class eosio_msig_binary_extension { - public: - using value_type = T; - - constexpr eosio_msig_binary_extension() {} - constexpr eosio_msig_binary_extension( const T& ext ) - :_has_value(true) - { - ::new (&_data) T(ext); - } - constexpr eosio_msig_binary_extension( T&& ext ) - :_has_value(true) - { - ::new (&_data) T(std::move(ext)); - } - /** construct contained type in place */ - template - constexpr eosio_msig_binary_extension( std::in_place_t, Args&&... args ) - :_has_value(true) - { - ::new (&_data) T(std::forward(args)...); - } - - constexpr eosio_msig_binary_extension( const eosio_msig_binary_extension& other ) - :_has_value(other._has_value) - { - if( other._has_value ) ::new (&_data) T( *other ); - } - - constexpr eosio_msig_binary_extension( eosio_msig_binary_extension&& other ) - :_has_value(other._has_value) - { - if( other._has_value ) { - ::new (&_data) T( *std::move(other) ); - other._has_value = false; - } - } - - /// @cond INTERNAL - ~eosio_msig_binary_extension() { reset(); } - - /// @cond INTERNAL - constexpr eosio_msig_binary_extension& operator= (const eosio_msig_binary_extension& other) { - if (has_value()) - reset(); - - if (other.has_value()) { - ::new (&_data) T(*other); - _has_value = true; - } - return *this; - } - - /// @cond INTERNAL - constexpr eosio_msig_binary_extension& operator= (eosio_msig_binary_extension&& other) { - if (has_value()) - reset(); - - if (other.has_value()) { - ::new (&_data) T(*other); - _has_value = true; - other._has_value = false; - } - return *this; - } - /** test if container is holding a value */ - constexpr explicit operator bool()const { return _has_value; } - /** test if container is holding a value */ - constexpr bool has_value()const { return _has_value; } - - /** get the contained value */ - constexpr T& value()& { - if (!_has_value) { - check(false, "cannot get value of empty eosio_msig_binary_extension"); - } - return _get(); - } - - /// @cond INTERNAL - - /** get the contained value */ - constexpr const T& value()const & { - if (!_has_value) { - check(false, "cannot get value of empty eosio_msig_binary_extension"); - } - return _get(); - } - - /** get the contained value or a user specified default - * @pre def should be convertible to type T - * */ - template - constexpr auto value_or( U&& def ) -> std::enable_if_t::value, T&>& { - if (_has_value) - return _get(); - return def; - } - - constexpr T value_or() const { return (_has_value) ? _get() : T{}; } - - constexpr T* operator->() { - return &_get(); - } - constexpr const T* operator->()const { - return &_get(); - } - - constexpr T& operator*()& { - return _get(); - } - constexpr const T& operator*()const& { - return _get(); - } - constexpr const T&& operator*()const&& { - return std::move(_get()); - } - constexpr T&& operator*()&& { - return std::move(_get()); - } - - template - T& emplace(Args&& ... args)& { - if (_has_value) { - reset(); - } - - ::new (&_data) T( std::forward(args)... ); - _has_value = true; - - return _get(); - } - - void reset() { - if( _has_value ) { - _get().~value_type(); - _has_value = false; - } - } - - /// @endcond - - private: - bool _has_value = false; - typename std::aligned_storage::type _data; - - constexpr T& _get() { - return *reinterpret_cast(&_data); - } - - constexpr const T& _get()const { - return *reinterpret_cast(&_data); - } - }; - - /// @cond IMPLEMENTATIONS - - /** - * Serialize a eosio_msig_binary_extension into a stream - * - * @ingroup eosio_msig_binary_extension - * @brief Serialize a eosio_msig_binary_extension - * @param ds - The stream to write - * @param opt - The value to serialize - * @tparam DataStream - Type of datastream buffer - * @return DataStream& - Reference to the datastream - */ - template - inline DataStream& operator<<(DataStream& ds, const eosio::eosio_msig_binary_extension& be) { - ds << be.value_or(); - return ds; - } - - /** - * Deserialize a eosio_msig_binary_extension from a stream - * - * @ingroup eosio_msig_binary_extension - * @brief Deserialize a eosio_msig_binary_extension - * @param ds - The stream to read - * @param opt - The destination for deserialized value - * @tparam DataStream - Type of datastream buffer - * @return DataStream& - Reference to the datastream - */ - template - inline DataStream& operator>>(DataStream& ds, eosio::eosio_msig_binary_extension& be) { - if( ds.remaining() ) { - T val; - ds >> val; - be.emplace(val); - } - return ds; - } - /** * The `eosio.msig` system contract allows for creation of proposed transactions which require authorization from a list of accounts, approval of the proposed transactions by those accounts required to approve it, and finally, it also allows the execution of the approved transactions on the blockchain. * @@ -310,43 +112,40 @@ namespace eosio { using exec_action = eosio::action_wrapper<"exec"_n, &multisig::exec>; using invalidate_action = eosio::action_wrapper<"invalidate"_n, &multisig::invalidate>; - struct [[eosio::table]] proposal { - name proposal_name; - std::vector packed_transaction; - eosio::eosio_msig_binary_extension< std::optional > earliest_exec_time; - - uint64_t primary_key()const { return proposal_name.value; } - }; - typedef eosio::multi_index< "proposal"_n, proposal > proposals; - - struct [[eosio::table]] old_approvals_info { - name proposal_name; - std::vector requested_approvals; - std::vector provided_approvals; - - uint64_t primary_key()const { return proposal_name.value; } - }; - typedef eosio::multi_index< "approvals"_n, old_approvals_info > old_approvals; + struct [[eosio::table, eosio::contract("eosio.msig")]] proposal { + name proposal_name; + std::vector packed_transaction; + eosio::binary_extension< std::optional > earliest_exec_time; - struct approval { - permission_level level; - time_point time; - }; + uint64_t primary_key()const { return proposal_name.value; } + }; + typedef eosio::multi_index< "proposal"_n, proposal > proposals; - struct [[eosio::table]] approvals_info { - uint8_t version = 1; - name proposal_name; - //requested approval doesn't need to contain time, but we want requested approval - //to be of exactly the same size as provided approval, in this case approve/unapprove - //doesn't change serialized data size. So, we use the same type. - std::vector requested_approvals; - std::vector provided_approvals; + struct [[eosio::table, eosio::contract("eosio.msig")]] old_approvals_info { + name proposal_name; + std::vector requested_approvals; + std::vector provided_approvals; + uint64_t primary_key()const { return proposal_name.value; } + }; + typedef eosio::multi_index< "approvals"_n, old_approvals_info > old_approvals; + struct approval { + permission_level level; + time_point time; + }; - uint64_t primary_key()const { return proposal_name.value; } - }; - typedef eosio::multi_index< "approvals2"_n, approvals_info > approvals; + struct [[eosio::table, eosio::contract("eosio.msig")]] approvals_info { + uint8_t version = 1; + name proposal_name; + //requested approval doesn't need to contain time, but we want requested approval + //to be of exactly the same size as provided approval, in this case approve/unapprove + //doesn't change serialized data size. So, we use the same type. + std::vector requested_approvals; + std::vector provided_approvals; + uint64_t primary_key()const { return proposal_name.value; } + }; + typedef eosio::multi_index< "approvals2"_n, approvals_info > approvals; - struct [[eosio::table]] invalidation { + struct [[eosio::table, eosio::contract("eosio.msig")]] invalidation { name account; time_point last_invalidation_time; diff --git a/contracts/eosio.msig/src/eosio.msig.cpp b/contracts/eosio.msig/src/eosio.msig.cpp index e24e9688..854814bb 100644 --- a/contracts/eosio.msig/src/eosio.msig.cpp +++ b/contracts/eosio.msig/src/eosio.msig.cpp @@ -76,7 +76,7 @@ void multisig::propose( name proposer, proptable.emplace( proposer, [&]( auto& prop ) { prop.proposal_name = proposal_name; prop.packed_transaction = pkd_trans; - prop.earliest_exec_time = std::optional{}; + prop.earliest_exec_time.emplace(); }); approvals apptable( get_self(), proposer.value ); @@ -131,7 +131,7 @@ void multisig::approve( name proposer, name proposal_name, permission_level leve auto table_op = [](auto&&, auto&&){}; if( trx_is_authorized(get_approvals_and_adjust_table(get_self(), proposer, proposal_name, table_op), prop.packed_transaction) ) { proptable.modify( prop, proposer, [&]( auto& p ) { - p.earliest_exec_time = std::optional{ current_time_point() + eosio::seconds(trx_header.delay_sec.value)}; + p.earliest_exec_time.emplace(time_point{ current_time_point() + eosio::seconds(trx_header.delay_sec.value)}); }); } } @@ -171,7 +171,7 @@ void multisig::unapprove( name proposer, name proposal_name, permission_level le auto table_op = [](auto&&, auto&&){}; if( !trx_is_authorized(get_approvals_and_adjust_table(get_self(), proposer, proposal_name, table_op), prop.packed_transaction) ) { proptable.modify( prop, proposer, [&]( auto& p ) { - p.earliest_exec_time = std::optional{}; + p.earliest_exec_time.emplace(); }); } } From 98d943a435ecd39d2efa5e7a9b3148b048cdf0f9 Mon Sep 17 00:00:00 2001 From: Dmytro Sydorchenko Date: Mon, 17 Oct 2022 13:25:05 -0400 Subject: [PATCH 23/96] msig test fixes + debug output --- contracts/eosio.wrap/src/eosio.wrap.cpp | 14 +- contracts/test_contracts/CMakeLists.txt | 1 + .../test_contracts/sendinline/CMakeLists.txt | 6 + .../sendinline/src/sendinline.cpp | 0 tests/contracts.hpp.in | 13 +- tests/eosio.msig_tests.cpp | 161 ++++++++++++++++-- tests/eosio.wrap_tests.cpp | 65 ++++--- .../test_contracts/sendinline/CMakeLists.txt | 4 - 8 files changed, 213 insertions(+), 51 deletions(-) create mode 100644 contracts/test_contracts/sendinline/CMakeLists.txt rename {tests => contracts}/test_contracts/sendinline/src/sendinline.cpp (100%) delete mode 100644 tests/test_contracts/sendinline/CMakeLists.txt diff --git a/contracts/eosio.wrap/src/eosio.wrap.cpp b/contracts/eosio.wrap/src/eosio.wrap.cpp index 12056bf1..abbdf90a 100644 --- a/contracts/eosio.wrap/src/eosio.wrap.cpp +++ b/contracts/eosio.wrap/src/eosio.wrap.cpp @@ -10,7 +10,19 @@ void wrap::exec( ignore, ignore ) { require_auth( executer ); - send_deferred( (uint128_t(executer.value) << 64) | (uint64_t)current_time_point().time_since_epoch().count(), executer, _ds.pos(), _ds.remaining() ); + //send_deferred( (uint128_t(executer.value) << 64) | (uint64_t)current_time_point().time_since_epoch().count(), executer, _ds.pos(), _ds.remaining() ); + transaction_header trx_header; + std::vector context_free_actions; + std::vector actions; + _ds >> trx_header; + //check( trx_header.expiration >= eosio::time_point_sec(current_time_point()), "transaction expired" ); + _ds >> context_free_actions; + check( context_free_actions.empty(), "not allowed to `exec` a transaction with context-free actions" ); + _ds >> actions; + + for (const auto& act : actions) { + act.send(); + } } } /// namespace eosio diff --git a/contracts/test_contracts/CMakeLists.txt b/contracts/test_contracts/CMakeLists.txt index 38e00885..e145e9ea 100644 --- a/contracts/test_contracts/CMakeLists.txt +++ b/contracts/test_contracts/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(blockinfo_tester) +add_subdirectory(sendinline) \ No newline at end of file diff --git a/contracts/test_contracts/sendinline/CMakeLists.txt b/contracts/test_contracts/sendinline/CMakeLists.txt new file mode 100644 index 00000000..2e1f3429 --- /dev/null +++ b/contracts/test_contracts/sendinline/CMakeLists.txt @@ -0,0 +1,6 @@ +add_contract(sendinline sendinline ${CMAKE_CURRENT_SOURCE_DIR}/src/sendinline.cpp) + +target_include_directories(sendinline PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include + "$") + +set_target_properties(sendinline PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") \ No newline at end of file diff --git a/tests/test_contracts/sendinline/src/sendinline.cpp b/contracts/test_contracts/sendinline/src/sendinline.cpp similarity index 100% rename from tests/test_contracts/sendinline/src/sendinline.cpp rename to contracts/test_contracts/sendinline/src/sendinline.cpp diff --git a/tests/contracts.hpp.in b/tests/contracts.hpp.in index 27fddd5b..ba33a662 100644 --- a/tests/contracts.hpp.in +++ b/tests/contracts.hpp.in @@ -24,8 +24,6 @@ struct contracts { static std::vector system_abi_old() { return read_abi("${CMAKE_CURRENT_SOURCE_DIR}/test_contracts/old_versions/v1.2.1/eosio.system/eosio.system.abi"); } static std::vector msig_wasm_old() { return read_wasm("${CMAKE_CURRENT_SOURCE_DIR}/test_contracts/old_versions/v1.2.1/eosio.msig/eosio.msig.wasm"); } static std::vector msig_abi_old() { return read_abi("${CMAKE_CURRENT_SOURCE_DIR}/test_contracts/old_versions/v1.2.1/eosio.msig/eosio.msig.abi"); } - static std::vector sendinline_wasm() {return read_wasm("${CMAKE_CURRENT_SOURCE_DIR}/test_contracts/old_versions/v1.8.3/sendinline/sendinline.wasm"); } - static std::vector sendinline_abi() {return read_abi("${CMAKE_CURRENT_SOURCE_DIR}/test_contracts/old_versions/v1.8.3/sendinline/sendinline.abi"); } }; }; @@ -38,5 +36,16 @@ static std::vector blockinfo_tester_wasm() return eosio::testing::read_wasm( "${CMAKE_BINARY_DIR}/contracts/test_contracts/blockinfo_tester/blockinfo_tester.wasm"); } +static std::vector sendinline_wasm() +{ + return eosio::testing::read_wasm( + "${CMAKE_BINARY_DIR}/contracts/test_contracts/sendinline/sendinline.wasm"); +} +static std::vector sendinline_abi() +{ + return eosio::testing::read_abi( + "${CMAKE_BINARY_DIR}/contracts/test_contracts/sendinline/sendinline.abi"); +} + } // namespace system_contracts::testing::test_contracts \ No newline at end of file diff --git a/tests/eosio.msig_tests.cpp b/tests/eosio.msig_tests.cpp index d612b8fd..385c35fa 100644 --- a/tests/eosio.msig_tests.cpp +++ b/tests/eosio.msig_tests.cpp @@ -3,6 +3,9 @@ #include #include #include +#include +#include + #include @@ -512,7 +515,8 @@ BOOST_FIXTURE_TEST_CASE( update_system_contract_all_approve, eosio_msig_tester ) transaction_trace_ptr trx_trace; control->applied_transaction.connect( [&]( std::tuple p ) { - trx_trace = std::get<0>(p); + if (!trx_trace) + trx_trace = std::get<0>(p); } ); push_action( "alice"_n, "exec"_n, mvo() @@ -528,12 +532,12 @@ BOOST_FIXTURE_TEST_CASE( update_system_contract_all_approve, eosio_msig_tester ) BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(0).action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).creator_action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).closest_unnotified_ancestor_action_ordinal ); - // EOSIO 1.8 N() macro returns a uint64_t rather than a struct name + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, action_name{trx_trace->action_traces.at(0).receiver} ); BOOST_REQUIRE_EQUAL( "eosio.msig"_n, name{trx_trace->action_traces.at(0).act.account} ); BOOST_REQUIRE_EQUAL( "exec"_n, name{trx_trace->action_traces.at(0).act.name} ); BOOST_REQUIRE_EQUAL( "alice"_n, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( "ctive"_n, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); + BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(1).action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).creator_action_ordinal ); @@ -667,7 +671,8 @@ BOOST_FIXTURE_TEST_CASE( update_system_contract_major_approve, eosio_msig_tester transaction_trace_ptr trx_trace; control->applied_transaction.connect( [&]( std::tuple p ) { - trx_trace = std::get<0>(p); + if (!trx_trace) + trx_trace = std::get<0>(p); } ); // execute by another producer different from proposer @@ -684,7 +689,7 @@ BOOST_FIXTURE_TEST_CASE( update_system_contract_major_approve, eosio_msig_tester BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(0).action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).creator_action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).closest_unnotified_ancestor_action_ordinal ); - // EOSIO 1.8 N() macro returns a uint64_t rather than a struct name + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, action_name{trx_trace->action_traces.at(0).receiver} ); BOOST_REQUIRE_EQUAL( "eosio.msig"_n, name{trx_trace->action_traces.at(0).act.account} ); BOOST_REQUIRE_EQUAL( "exec"_n, name{trx_trace->action_traces.at(0).act.name} ); @@ -1039,14 +1044,69 @@ BOOST_FIXTURE_TEST_CASE( switch_proposal_and_fail_approve_with_hash, eosio_msig_ BOOST_FIXTURE_TEST_CASE( sendinline, eosio_msig_tester ) try { create_accounts( {"sendinline"_n} ); - set_code( "sendinline"_n, contracts::util::sendinline_wasm() ); - set_abi( "sendinline"_n, contracts::util::sendinline_abi().data() ); + set_code( "sendinline"_n, system_contracts::testing::test_contracts::sendinline_wasm() ); + set_abi( "sendinline"_n, system_contracts::testing::test_contracts::sendinline_abi().data() ); create_accounts( {"wrongcon"_n} ); - set_code( "wrongcon"_n, contracts::util::sendinline_wasm() ); - set_abi( "wrongcon"_n, contracts::util::sendinline_abi().data() ); + set_code( "wrongcon"_n, system_contracts::testing::test_contracts::sendinline_wasm() ); + set_abi( "wrongcon"_n, system_contracts::testing::test_contracts::sendinline_abi().data() ); produce_blocks(); + // TODO: debug output, remove + struct linked_action { + name account; + std::optional action; + }; + + auto get_linked_action_map = [&](account_name acc_name){ + const auto& links = control->db().get_index(); + auto iter = links.lower_bound( boost::make_tuple( acc_name ) ); + + std::multimap result; + while (iter != links.end() && iter->account == acc_name ) { + auto action = iter->message_type.empty() ? std::optional() : std::optional(iter->message_type); + result.emplace(std::make_pair(iter->required_permission, linked_action{iter->code, std::move(action)})); + ++iter; + } + + return result; + }; + auto get_linked_actions = [&](chain::name acc_name, chain::name perm_name) { + auto link_bounds = get_linked_action_map(acc_name).equal_range(perm_name); + auto linked_actions = std::vector(); + linked_actions.reserve(get_linked_action_map(acc_name).count(perm_name)); + for (auto link = link_bounds.first; link != link_bounds.second; ++link) { + linked_actions.push_back(link->second); + } + return linked_actions; + }; + + { + const auto& permissions = control->db().get_index(); + auto perm = permissions.lower_bound( boost::make_tuple( "sendinline"_n ) ); + while( perm != permissions.end() && perm->owner == "sendinline"_n ) { + /// TODO: lookup perm->parent name + name parent; + + // Don't lookup parent if null + if( perm->parent._id ) { + const auto* p = control->db().find( perm->parent ); + if( p ) { + parent = p->name; + } + } + + auto linked_actions = get_linked_actions("sendinline"_n, perm->name); + + auto auth = perm->auth.to_authority(); + BOOST_TEST_MESSAGE("sendinline permissions: " << perm->name.to_string() + << ", parent: " << parent.to_string() + << ", auth: {threshold: " << auth.threshold << ", accounts_size: " << auth.accounts.size() << ", accounts[0]: {" << auth.accounts[0].weight << ", {" << auth.accounts[0].permission.actor.to_string() << ", " << auth.accounts[0].permission.permission.to_string() << "}}" + << ", linked actions size: " << linked_actions.size() ); + ++perm; + } + } + action act = get_action( config::system_account_name, "reqauth"_n, {}, mvo()("from", "alice")); BOOST_REQUIRE_EXCEPTION( base_tester::push_action( "sendinline"_n, "send"_n, "bob"_n, mvo() @@ -1058,6 +1118,32 @@ BOOST_FIXTURE_TEST_CASE( sendinline, eosio_msig_tester ) try { unsatisfied_authorization, fc_exception_message_starts_with("transaction declares authority") ); + // TODO: debug output, remove + { + const auto& permissions = control->db().get_index(); + auto perm = permissions.lower_bound( boost::make_tuple( "alice"_n ) ); + while( perm != permissions.end() && perm->owner == "alice"_n ) { + /// TODO: lookup perm->parent name + name parent; + + // Don't lookup parent if null + if( perm->parent._id ) { + const auto* p = control->db().find( perm->parent ); + if( p ) { + parent = p->name; + } + } + + auto linked_actions = get_linked_actions("alice"_n, perm->name); + + auto auth = perm->auth.to_authority(); + BOOST_TEST_MESSAGE("alice permissions: " << perm->name.to_string() + << ", parent: " << parent.to_string() + << ", auth: {threshold: " << auth.threshold << ", accounts_size: " << auth.accounts.size() << ", accounts[0]: {" << auth.accounts[0].weight << ", {" << auth.accounts[0].permission.actor.to_string() << ", " << auth.accounts[0].permission.permission.to_string() << "}}" + << ", linked actions size: " << linked_actions.size() ); + ++perm; + } + } base_tester::push_action(config::system_account_name, "updateauth"_n, "alice"_n, mvo() ("account", "alice") @@ -1066,6 +1152,32 @@ BOOST_FIXTURE_TEST_CASE( sendinline, eosio_msig_tester ) try { ("auth", authority{ 1, {}, {permission_level_weight{ {"sendinline"_n, config::active_name}, 1}}, {} }) ); produce_blocks(); + // TODO: debug output, remove + { + const auto& permissions = control->db().get_index(); + auto perm = permissions.lower_bound( boost::make_tuple( "alice"_n ) ); + while( perm != permissions.end() && perm->owner == "alice"_n ) { + /// TODO: lookup perm->parent name + name parent; + + // Don't lookup parent if null + if( perm->parent._id ) { + const auto* p = control->db().find( perm->parent ); + if( p ) { + parent = p->name; + } + } + + auto linked_actions = get_linked_actions("alice"_n, perm->name); + + auto auth = perm->auth.to_authority(); + BOOST_TEST_MESSAGE("alice permissions: " << perm->name.to_string() + << ", parent: " << parent.to_string() + << ", auth: {threshold: " << auth.threshold << ", accounts_size: " << auth.accounts.size() << ", accounts[0]: {" << auth.accounts[0].weight << ", {" << auth.accounts[0].permission.actor.to_string() << ", " << auth.accounts[0].permission.permission.to_string() << "}}" + << ", linked actions size: " << linked_actions.size() ); + ++perm; + } + } base_tester::push_action( config::system_account_name, "linkauth"_n, "alice"_n, mvo() ("account", "alice") @@ -1131,10 +1243,37 @@ BOOST_FIXTURE_TEST_CASE( sendinline, eosio_msig_tester ) try { ("proposer", "bob") ("proposal_name", "first") ("trx", trx) - ("requested", std::vector{{ "sendinline"_n, "eosio.code"_n }}) + ("requested", std::vector{{ "sendinline"_n, config::active_name }}) ); produce_blocks(); - + + // TODO: debug output, remove + { + const auto& permissions = control->db().get_index(); + auto perm = permissions.lower_bound( boost::make_tuple( "sendinline"_n ) ); + while( perm != permissions.end() && perm->owner == "sendinline"_n ) { + /// TODO: lookup perm->parent name + name parent; + + // Don't lookup parent if null + if( perm->parent._id ) { + const auto* p = control->db().find( perm->parent ); + if( p ) { + parent = p->name; + } + } + + auto linked_actions = get_linked_actions("sendinline"_n, perm->name); + + auto auth = perm->auth.to_authority(); + BOOST_TEST_MESSAGE("sendinline permissions: " << perm->name.to_string() + << ", parent: " << parent.to_string() + << ", auth: {threshold: " << auth.threshold << ", accounts_size: " << auth.accounts.size() << ", accounts[0]: {" << auth.accounts[0].weight << ", {" << auth.accounts[0].permission.actor.to_string() << ", " << auth.accounts[0].permission.permission.to_string() << "}}" + << ", linked actions size: " << linked_actions.size() ); + ++perm; + } + } + base_tester::push_action( "sendinline"_n, "send"_n, "bob"_n, mvo() ("contract", "eosio.msig") ("action_name", "approve") diff --git a/tests/eosio.wrap_tests.cpp b/tests/eosio.wrap_tests.cpp index 6910f724..f6a01be8 100644 --- a/tests/eosio.wrap_tests.cpp +++ b/tests/eosio.wrap_tests.cpp @@ -168,8 +168,9 @@ BOOST_FIXTURE_TEST_CASE( wrap_exec_direct, eosio_wrap_tester ) try { transaction_trace_ptr trace; control->applied_transaction.connect( [&]( std::tuple p ) { - const auto& t = std::get<0>(p); - if( t->scheduled ) { trace = t; } + //the second will be onblock, we need only wrap transaction + if (!trace) + trace = std::get<0>(p); } ); { @@ -193,9 +194,11 @@ BOOST_FIXTURE_TEST_CASE( wrap_exec_direct, eosio_wrap_tester ) try { produce_block(); BOOST_REQUIRE( bool(trace) ); - BOOST_REQUIRE_EQUAL( 1, trace->action_traces.size() ); - BOOST_REQUIRE_EQUAL( config::system_account_name, name{trace->action_traces[0].act.account} ); - BOOST_REQUIRE_EQUAL( "reqauth"_n, name{trace->action_traces[0].act.name} ); + BOOST_REQUIRE_EQUAL( 2, trace->action_traces.size() ); + BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, name{trace->action_traces[0].act.account} ); + BOOST_REQUIRE_EQUAL( "exec"_n, name{trace->action_traces[0].act.name} ); + BOOST_REQUIRE_EQUAL( config::system_account_name, name{trace->action_traces[1].act.account} ); + BOOST_REQUIRE_EQUAL( "reqauth"_n, name{trace->action_traces[1].act.name} ); BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); } FC_LOG_AND_RETHROW() @@ -233,21 +236,9 @@ BOOST_FIXTURE_TEST_CASE( wrap_with_msig, eosio_wrap_tester ) try { produce_block(); - BOOST_REQUIRE_EQUAL( 2, traces.size() ); - - BOOST_REQUIRE_EQUAL( 1, traces[0]->action_traces.size() ); - BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, name{traces[0]->action_traces[0].act.account} ); - BOOST_REQUIRE_EQUAL( "exec"_n, name{traces[0]->action_traces[0].act.name} ); - BOOST_REQUIRE_EQUAL( transaction_receipt::executed, traces[0]->receipt->status ); - - BOOST_REQUIRE_EQUAL( 1, traces[1]->action_traces.size() ); - BOOST_REQUIRE_EQUAL( config::system_account_name, name{traces[1]->action_traces[0].act.account} ); - BOOST_REQUIRE_EQUAL( "reqauth"_n, name{traces[1]->action_traces[0].act.name} ); - BOOST_REQUIRE_EQUAL( transaction_receipt::executed, traces[1]->receipt->status ); - BOOST_REQUIRE( bool(trx_trace) ); BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); - BOOST_REQUIRE_EQUAL( 2, trx_trace->action_traces.size() ); + BOOST_REQUIRE_EQUAL( 3, trx_trace->action_traces.size() ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(0).action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).creator_action_ordinal ); @@ -270,6 +261,16 @@ BOOST_FIXTURE_TEST_CASE( wrap_with_msig, eosio_wrap_tester ) try { BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, name{trx_trace->action_traces.at(1).act.authorization[1].actor} ); BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(1).act.authorization[1].permission} ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{3}, trx_trace->action_traces.at(2).action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(2).creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(2).closest_unnotified_ancestor_action_ordinal ); + BOOST_REQUIRE_EQUAL( config::system_account_name, action_name{trx_trace->action_traces.at(2).receiver} ); + BOOST_REQUIRE_EQUAL( config::system_account_name, name{trx_trace->action_traces.at(2).act.account} ); + BOOST_REQUIRE_EQUAL( "reqauth"_n, name{trx_trace->action_traces.at(2).act.name} ); + BOOST_REQUIRE_EQUAL( 1, trx_trace->action_traces.at(2).act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "bob"_n, name{trx_trace->action_traces.at(2).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(2).act.authorization[0].permission} ); + } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( wrap_with_msig_unapprove, eosio_wrap_tester ) try { @@ -365,28 +366,16 @@ BOOST_FIXTURE_TEST_CASE( wrap_with_msig_producers_change, eosio_wrap_tester ) tr // Now the proposal should be ready to execute transaction_trace_ptr trx_trace; trx_trace = push_action( "eosio.msig"_n, "exec"_n, "alice"_n, mvo() - ("proposer", "carol") ("proposal_name", "first") + ("proposer", "carol") ("executer", "alice") ); produce_block(); - - BOOST_REQUIRE_EQUAL( 2, traces.size() ); - - BOOST_REQUIRE_EQUAL( 1, traces[0]->action_traces.size() ); - BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, name{traces[0]->action_traces[0].act.account} ); - BOOST_REQUIRE_EQUAL( "exec"_n, name{traces[0]->action_traces[0].act.name} ); - BOOST_REQUIRE_EQUAL( transaction_receipt::executed, traces[0]->receipt->status ); - - BOOST_REQUIRE_EQUAL( 1, traces[1]->action_traces.size() ); - BOOST_REQUIRE_EQUAL( config::system_account_name, name{traces[1]->action_traces[0].act.account} ); - BOOST_REQUIRE_EQUAL( "reqauth"_n, name{traces[1]->action_traces[0].act.name} ); - BOOST_REQUIRE_EQUAL( transaction_receipt::executed, traces[1]->receipt->status ); - + BOOST_REQUIRE( bool(trx_trace) ); BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); - BOOST_REQUIRE_EQUAL( 2, trx_trace->action_traces.size() ); + BOOST_REQUIRE_EQUAL( 3, trx_trace->action_traces.size() ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(0).action_ordinal ); BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).creator_action_ordinal ); @@ -409,6 +398,16 @@ BOOST_FIXTURE_TEST_CASE( wrap_with_msig_producers_change, eosio_wrap_tester ) tr BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, name{trx_trace->action_traces.at(1).act.authorization[1].actor} ); BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(1).act.authorization[1].permission} ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{3}, trx_trace->action_traces.at(2).action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(2).creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(2).closest_unnotified_ancestor_action_ordinal ); + BOOST_REQUIRE_EQUAL( config::system_account_name, action_name{trx_trace->action_traces.at(2).receiver} ); + BOOST_REQUIRE_EQUAL( config::system_account_name, name{trx_trace->action_traces.at(2).act.account} ); + BOOST_REQUIRE_EQUAL( "reqauth"_n, name{trx_trace->action_traces.at(2).act.name} ); + BOOST_REQUIRE_EQUAL( 1, trx_trace->action_traces.at(2).act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "bob"_n, name{trx_trace->action_traces.at(2).act.authorization[0].actor} ); + BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(2).act.authorization[0].permission} ); + } FC_LOG_AND_RETHROW() BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/test_contracts/sendinline/CMakeLists.txt b/tests/test_contracts/sendinline/CMakeLists.txt deleted file mode 100644 index 9c03a8d7..00000000 --- a/tests/test_contracts/sendinline/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -find_package(eosio.cdt) -add_contract(sendinline sendinline ${CMAKE_CURRENT_SOURCE_DIR}/src/sendinline.cpp) -target_include_directories(sendinline.wasm PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) -set_target_properties(sendinline.wasm PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") \ No newline at end of file From e716a384e5f7fef6101a8153a1667e094f85442c Mon Sep 17 00:00:00 2001 From: Dmytro Sydorchenko Date: Mon, 17 Oct 2022 18:00:42 -0400 Subject: [PATCH 24/96] tests fixed, debug code removed --- tests/eosio.msig_tests.cpp | 148 +---------------------------------- tests/eosio.system_tests.cpp | 3 +- 2 files changed, 3 insertions(+), 148 deletions(-) diff --git a/tests/eosio.msig_tests.cpp b/tests/eosio.msig_tests.cpp index 385c35fa..7146a91d 100644 --- a/tests/eosio.msig_tests.cpp +++ b/tests/eosio.msig_tests.cpp @@ -1052,61 +1052,6 @@ BOOST_FIXTURE_TEST_CASE( sendinline, eosio_msig_tester ) try { set_abi( "wrongcon"_n, system_contracts::testing::test_contracts::sendinline_abi().data() ); produce_blocks(); - // TODO: debug output, remove - struct linked_action { - name account; - std::optional action; - }; - - auto get_linked_action_map = [&](account_name acc_name){ - const auto& links = control->db().get_index(); - auto iter = links.lower_bound( boost::make_tuple( acc_name ) ); - - std::multimap result; - while (iter != links.end() && iter->account == acc_name ) { - auto action = iter->message_type.empty() ? std::optional() : std::optional(iter->message_type); - result.emplace(std::make_pair(iter->required_permission, linked_action{iter->code, std::move(action)})); - ++iter; - } - - return result; - }; - auto get_linked_actions = [&](chain::name acc_name, chain::name perm_name) { - auto link_bounds = get_linked_action_map(acc_name).equal_range(perm_name); - auto linked_actions = std::vector(); - linked_actions.reserve(get_linked_action_map(acc_name).count(perm_name)); - for (auto link = link_bounds.first; link != link_bounds.second; ++link) { - linked_actions.push_back(link->second); - } - return linked_actions; - }; - - { - const auto& permissions = control->db().get_index(); - auto perm = permissions.lower_bound( boost::make_tuple( "sendinline"_n ) ); - while( perm != permissions.end() && perm->owner == "sendinline"_n ) { - /// TODO: lookup perm->parent name - name parent; - - // Don't lookup parent if null - if( perm->parent._id ) { - const auto* p = control->db().find( perm->parent ); - if( p ) { - parent = p->name; - } - } - - auto linked_actions = get_linked_actions("sendinline"_n, perm->name); - - auto auth = perm->auth.to_authority(); - BOOST_TEST_MESSAGE("sendinline permissions: " << perm->name.to_string() - << ", parent: " << parent.to_string() - << ", auth: {threshold: " << auth.threshold << ", accounts_size: " << auth.accounts.size() << ", accounts[0]: {" << auth.accounts[0].weight << ", {" << auth.accounts[0].permission.actor.to_string() << ", " << auth.accounts[0].permission.permission.to_string() << "}}" - << ", linked actions size: " << linked_actions.size() ); - ++perm; - } - } - action act = get_action( config::system_account_name, "reqauth"_n, {}, mvo()("from", "alice")); BOOST_REQUIRE_EXCEPTION( base_tester::push_action( "sendinline"_n, "send"_n, "bob"_n, mvo() @@ -1118,32 +1063,6 @@ BOOST_FIXTURE_TEST_CASE( sendinline, eosio_msig_tester ) try { unsatisfied_authorization, fc_exception_message_starts_with("transaction declares authority") ); - // TODO: debug output, remove - { - const auto& permissions = control->db().get_index(); - auto perm = permissions.lower_bound( boost::make_tuple( "alice"_n ) ); - while( perm != permissions.end() && perm->owner == "alice"_n ) { - /// TODO: lookup perm->parent name - name parent; - - // Don't lookup parent if null - if( perm->parent._id ) { - const auto* p = control->db().find( perm->parent ); - if( p ) { - parent = p->name; - } - } - - auto linked_actions = get_linked_actions("alice"_n, perm->name); - - auto auth = perm->auth.to_authority(); - BOOST_TEST_MESSAGE("alice permissions: " << perm->name.to_string() - << ", parent: " << parent.to_string() - << ", auth: {threshold: " << auth.threshold << ", accounts_size: " << auth.accounts.size() << ", accounts[0]: {" << auth.accounts[0].weight << ", {" << auth.accounts[0].permission.actor.to_string() << ", " << auth.accounts[0].permission.permission.to_string() << "}}" - << ", linked actions size: " << linked_actions.size() ); - ++perm; - } - } base_tester::push_action(config::system_account_name, "updateauth"_n, "alice"_n, mvo() ("account", "alice") @@ -1152,32 +1071,6 @@ BOOST_FIXTURE_TEST_CASE( sendinline, eosio_msig_tester ) try { ("auth", authority{ 1, {}, {permission_level_weight{ {"sendinline"_n, config::active_name}, 1}}, {} }) ); produce_blocks(); - // TODO: debug output, remove - { - const auto& permissions = control->db().get_index(); - auto perm = permissions.lower_bound( boost::make_tuple( "alice"_n ) ); - while( perm != permissions.end() && perm->owner == "alice"_n ) { - /// TODO: lookup perm->parent name - name parent; - - // Don't lookup parent if null - if( perm->parent._id ) { - const auto* p = control->db().find( perm->parent ); - if( p ) { - parent = p->name; - } - } - - auto linked_actions = get_linked_actions("alice"_n, perm->name); - - auto auth = perm->auth.to_authority(); - BOOST_TEST_MESSAGE("alice permissions: " << perm->name.to_string() - << ", parent: " << parent.to_string() - << ", auth: {threshold: " << auth.threshold << ", accounts_size: " << auth.accounts.size() << ", accounts[0]: {" << auth.accounts[0].weight << ", {" << auth.accounts[0].permission.actor.to_string() << ", " << auth.accounts[0].permission.permission.to_string() << "}}" - << ", linked actions size: " << linked_actions.size() ); - ++perm; - } - } base_tester::push_action( config::system_account_name, "linkauth"_n, "alice"_n, mvo() ("account", "alice") @@ -1219,22 +1112,12 @@ BOOST_FIXTURE_TEST_CASE( sendinline, eosio_msig_tester ) try { BOOST_REQUIRE_EQUAL( "alice"_n, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); BOOST_REQUIRE_EQUAL( "perm"_n, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); - - base_tester::push_action(config::system_account_name, updateauth::get_name(), "sendinline"_n, mvo() - ("account", "sendinline") - ("permission", name(config::active_name)) - ("parent", name(config::owner_name)) - ("auth", authority(1, {key_weight{get_public_key("sendinline"_n, "active"), 1}}, { - permission_level_weight{{"sendinline"_n, config::eosio_code_name}, 1} - } - )) - ); produce_blocks(); action approve_act = get_action("eosio.msig"_n, "approve"_n, {}, mvo() ("proposer", "bob") ("proposal_name", "first") - ("level", permission_level{"sendinline"_n, "eosio.code"_n}) + ("level", permission_level{"sendinline"_n, config::active_name}) ); transaction trx = reqauth( "alice"_n, {permission_level{"alice"_n, "perm"_n}}, abi_serializer_max_time ); @@ -1243,37 +1126,10 @@ BOOST_FIXTURE_TEST_CASE( sendinline, eosio_msig_tester ) try { ("proposer", "bob") ("proposal_name", "first") ("trx", trx) - ("requested", std::vector{{ "sendinline"_n, config::active_name }}) + ("requested", std::vector{{ "sendinline"_n, config::active_name}}) ); produce_blocks(); - // TODO: debug output, remove - { - const auto& permissions = control->db().get_index(); - auto perm = permissions.lower_bound( boost::make_tuple( "sendinline"_n ) ); - while( perm != permissions.end() && perm->owner == "sendinline"_n ) { - /// TODO: lookup perm->parent name - name parent; - - // Don't lookup parent if null - if( perm->parent._id ) { - const auto* p = control->db().find( perm->parent ); - if( p ) { - parent = p->name; - } - } - - auto linked_actions = get_linked_actions("sendinline"_n, perm->name); - - auto auth = perm->auth.to_authority(); - BOOST_TEST_MESSAGE("sendinline permissions: " << perm->name.to_string() - << ", parent: " << parent.to_string() - << ", auth: {threshold: " << auth.threshold << ", accounts_size: " << auth.accounts.size() << ", accounts[0]: {" << auth.accounts[0].weight << ", {" << auth.accounts[0].permission.actor.to_string() << ", " << auth.accounts[0].permission.permission.to_string() << "}}" - << ", linked actions size: " << linked_actions.size() ); - ++perm; - } - } - base_tester::push_action( "sendinline"_n, "send"_n, "bob"_n, mvo() ("contract", "eosio.msig") ("action_name", "approve") diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 1c476c03..f4db7ee4 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -3675,8 +3675,7 @@ BOOST_FIXTURE_TEST_CASE( wasmcfg, eosio_system_tester ) try { transaction_trace_ptr trace; control->applied_transaction.connect( [&]( std::tuple p ) { - const auto& t = std::get<0>(p); - if( t->scheduled ) { trace = t; } + trace = std::get<0>(p); } ); BOOST_REQUIRE_EQUAL(success(), push_action_msig( "alice1111111"_n, "exec"_n, mvo() From fbb6ee26e251a67e85cc1b41094f644dbf919063 Mon Sep 17 00:00:00 2001 From: Dmytro Sydorchenko Date: Mon, 17 Oct 2022 22:34:44 -0400 Subject: [PATCH 25/96] remove applied_transaction from msig and wrap tests --- tests/eosio.msig_tests.cpp | 340 ++++++++++++++++++++++--------------- tests/eosio.wrap_tests.cpp | 206 +++++++++++----------- 2 files changed, 301 insertions(+), 245 deletions(-) diff --git a/tests/eosio.msig_tests.cpp b/tests/eosio.msig_tests.cpp index 7146a91d..11271be0 100644 --- a/tests/eosio.msig_tests.cpp +++ b/tests/eosio.msig_tests.cpp @@ -211,20 +211,31 @@ BOOST_FIXTURE_TEST_CASE( propose_approve_execute, eosio_msig_tester ) try { ("level", permission_level{ "alice"_n, config::active_name }) ); - transaction_trace_ptr trace; - control->applied_transaction.connect( - [&]( std::tuple p ) { - trace = std::get<0>(p); - } ); - push_action( "alice"_n, "exec"_n, mvo() - ("proposer", "alice") - ("proposal_name", "first") - ("executer", "alice") + transaction_trace_ptr trace = push_action( "alice"_n, "exec"_n, mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("executer", "alice") ); BOOST_REQUIRE( bool(trace) ); - BOOST_REQUIRE_EQUAL( 1, trace->action_traces.size() ); BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); + BOOST_REQUIRE_EQUAL( 2, trace->action_traces.size() ); + + auto exec_trace = trace->action_traces.at(0); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.act.account ); + BOOST_REQUIRE_EQUAL( "exec"_n, exec_trace.act.name ); + BOOST_REQUIRE_EQUAL( 1, exec_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "alice"_n, exec_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, exec_trace.act.authorization.at(0).permission ); + + auto reqauth_trace = trace->action_traces.at(1); + BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.act.account ); + BOOST_REQUIRE_EQUAL( "reqauth"_n, reqauth_trace.act.name ); + BOOST_REQUIRE_EQUAL( 1, reqauth_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "alice"_n, reqauth_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, reqauth_trace.act.authorization.at(0).permission ); } FC_LOG_AND_RETHROW() @@ -296,21 +307,33 @@ BOOST_FIXTURE_TEST_CASE( propose_approve_by_two, eosio_msig_tester ) try { ("level", permission_level{ "bob"_n, config::active_name }) ); - transaction_trace_ptr trace; - control->applied_transaction.connect( - [&]( std::tuple p ) { - trace = std::get<0>(p); - } ); - - push_action( "alice"_n, "exec"_n, mvo() - ("proposer", "alice") - ("proposal_name", "first") - ("executer", "alice") + transaction_trace_ptr trace = push_action( "alice"_n, "exec"_n, mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("executer", "alice") ); BOOST_REQUIRE( bool(trace) ); - BOOST_REQUIRE_EQUAL( 1, trace->action_traces.size() ); BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); + BOOST_REQUIRE_EQUAL( 2, trace->action_traces.size() ); + + auto exec_trace = trace->action_traces.at(0); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.act.account ); + BOOST_REQUIRE_EQUAL( "exec"_n, exec_trace.act.name ); + BOOST_REQUIRE_EQUAL( 1, exec_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "alice"_n, exec_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, exec_trace.act.authorization.at(0).permission ); + + auto reqauth_trace = trace->action_traces.at(1); + BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.act.account ); + BOOST_REQUIRE_EQUAL( "reqauth"_n, reqauth_trace.act.name ); + BOOST_REQUIRE_EQUAL( 2, reqauth_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "alice"_n, reqauth_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, reqauth_trace.act.authorization.at(0).permission ); + BOOST_REQUIRE_EQUAL( "bob"_n, reqauth_trace.act.authorization.at(1).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, reqauth_trace.act.authorization.at(1).permission ); } FC_LOG_AND_RETHROW() @@ -386,21 +409,33 @@ BOOST_FIXTURE_TEST_CASE( big_transaction, eosio_msig_tester ) try { ("level", permission_level{ "bob"_n, config::active_name }) ); - transaction_trace_ptr trace; - control->applied_transaction.connect( - [&]( std::tuple p ) { - trace = std::get<0>(p); - } ); - - push_action( "alice"_n, "exec"_n, mvo() - ("proposer", "alice") - ("proposal_name", "first") - ("executer", "alice") + transaction_trace_ptr trace = push_action( "alice"_n, "exec"_n, mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("executer", "alice") ); BOOST_REQUIRE( bool(trace) ); - BOOST_REQUIRE_EQUAL( 1, trace->action_traces.size() ); BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); + BOOST_REQUIRE_EQUAL( 2, trace->action_traces.size() ); + + auto exec_trace = trace->action_traces.at(0); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.act.account ); + BOOST_REQUIRE_EQUAL( "exec"_n, exec_trace.act.name ); + BOOST_REQUIRE_EQUAL( 1, exec_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "alice"_n, exec_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, exec_trace.act.authorization.at(0).permission ); + + auto setcode_trace = trace->action_traces.at(1); + BOOST_REQUIRE_EQUAL( "eosio"_n, setcode_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio"_n, setcode_trace.act.account ); + BOOST_REQUIRE_EQUAL( "setcode"_n, setcode_trace.act.name ); + BOOST_REQUIRE_EQUAL( 2, setcode_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "alice"_n, setcode_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, setcode_trace.act.authorization.at(0).permission ); + BOOST_REQUIRE_EQUAL( "bob"_n, setcode_trace.act.authorization.at(1).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, setcode_trace.act.authorization.at(1).permission ); } FC_LOG_AND_RETHROW() @@ -511,42 +546,40 @@ BOOST_FIXTURE_TEST_CASE( update_system_contract_all_approve, eosio_msig_tester ) ("proposal_name", "first") ("level", permission_level{ "carol"_n, config::active_name }) ); - // execute by alice to replace the eosio system contract - transaction_trace_ptr trx_trace; - control->applied_transaction.connect( - [&]( std::tuple p ) { - if (!trx_trace) - trx_trace = std::get<0>(p); - } ); - push_action( "alice"_n, "exec"_n, mvo() - ("proposer", "alice") - ("proposal_name", "first") - ("executer", "alice") + // execute by alice to replace the eosio system contract + transaction_trace_ptr trx_trace = push_action( "alice"_n, "exec"_n, mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("executer", "alice") ); BOOST_REQUIRE( bool(trx_trace) ); BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); BOOST_REQUIRE_EQUAL( 2, trx_trace->action_traces.size() ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(0).action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).closest_unnotified_ancestor_action_ordinal ); + auto exec_trace = trx_trace->action_traces.at(0); + BOOST_REQUIRE_EQUAL( 1, exec_trace.action_ordinal ); + BOOST_REQUIRE_EQUAL( 0, exec_trace.creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( 0, exec_trace.closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, action_name{trx_trace->action_traces.at(0).receiver} ); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, name{trx_trace->action_traces.at(0).act.account} ); - BOOST_REQUIRE_EQUAL( "exec"_n, name{trx_trace->action_traces.at(0).act.name} ); - BOOST_REQUIRE_EQUAL( "alice"_n, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); - - BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(1).action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( "eosio"_n, action_name{trx_trace->action_traces.at(1).receiver} ); - BOOST_REQUIRE_EQUAL( "eosio"_n, name{trx_trace->action_traces.at(1).act.account} ); - BOOST_REQUIRE_EQUAL( "setcode"_n, name{trx_trace->action_traces.at(1).act.name} ); - BOOST_REQUIRE_EQUAL( "eosio"_n, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.act.account ); + BOOST_REQUIRE_EQUAL( "exec"_n, exec_trace.act.name ); + BOOST_REQUIRE_EQUAL( 1, exec_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "alice"_n, exec_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, exec_trace.act.authorization.at(0).permission ); + + auto setcode_trace = trx_trace->action_traces.at(1); + BOOST_REQUIRE_EQUAL( 2, setcode_trace.action_ordinal ); + BOOST_REQUIRE_EQUAL( 1, setcode_trace.creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( 1, setcode_trace.closest_unnotified_ancestor_action_ordinal ); + BOOST_REQUIRE_EQUAL( "eosio"_n, setcode_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio"_n, setcode_trace.act.account ); + BOOST_REQUIRE_EQUAL( "setcode"_n, setcode_trace.act.name ); + BOOST_REQUIRE_EQUAL( 1, setcode_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "eosio"_n, setcode_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, setcode_trace.act.authorization.at(0).permission ); // can't create account because system contract was replaced by the reject_all contract @@ -667,43 +700,39 @@ BOOST_FIXTURE_TEST_CASE( update_system_contract_major_approve, eosio_msig_tester ("proposal_name", "first") ("level", permission_level{ "apple"_n, config::active_name }) ); - // execute by alice to replace the eosio system contract - transaction_trace_ptr trx_trace; - control->applied_transaction.connect( - [&]( std::tuple p ) { - if (!trx_trace) - trx_trace = std::get<0>(p); - } ); - // execute by another producer different from proposer - push_action( "apple"_n, "exec"_n, mvo() - ("proposer", "alice") - ("proposal_name", "first") - ("executer", "apple") + transaction_trace_ptr trx_trace = push_action( "apple"_n, "exec"_n, mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("executer", "apple") ); BOOST_REQUIRE( bool(trx_trace) ); BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); BOOST_REQUIRE_EQUAL( 2, trx_trace->action_traces.size() ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(0).action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).closest_unnotified_ancestor_action_ordinal ); + auto exec_trace = trx_trace->action_traces.at(0); + BOOST_REQUIRE_EQUAL( 1, exec_trace.action_ordinal ); + BOOST_REQUIRE_EQUAL( 0, exec_trace.creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( 0, exec_trace.closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, action_name{trx_trace->action_traces.at(0).receiver} ); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, name{trx_trace->action_traces.at(0).act.account} ); - BOOST_REQUIRE_EQUAL( "exec"_n, name{trx_trace->action_traces.at(0).act.name} ); - BOOST_REQUIRE_EQUAL( "apple"_n, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); - - BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(1).action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( "eosio"_n, action_name{trx_trace->action_traces.at(1).receiver} ); - BOOST_REQUIRE_EQUAL( "eosio"_n, name{trx_trace->action_traces.at(1).act.account} ); - BOOST_REQUIRE_EQUAL( "setcode"_n, name{trx_trace->action_traces.at(1).act.name} ); - BOOST_REQUIRE_EQUAL( "eosio"_n, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.act.account ); + BOOST_REQUIRE_EQUAL( "exec"_n, exec_trace.act.name ); + BOOST_REQUIRE_EQUAL( 1, exec_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "apple"_n, exec_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, exec_trace.act.authorization.at(0).permission ); + + auto setcode_trace = trx_trace->action_traces.at(1); + BOOST_REQUIRE_EQUAL( 2, setcode_trace.action_ordinal ); + BOOST_REQUIRE_EQUAL( 1, setcode_trace.creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( 1, setcode_trace.closest_unnotified_ancestor_action_ordinal ); + BOOST_REQUIRE_EQUAL( "eosio"_n, setcode_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio"_n, setcode_trace.act.account ); + BOOST_REQUIRE_EQUAL( "setcode"_n, setcode_trace.act.name ); + BOOST_REQUIRE_EQUAL( 1, setcode_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "eosio"_n, setcode_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, setcode_trace.act.authorization.at(0).permission ); // can't create account because system contract was replaced by the reject_all contract @@ -788,22 +817,31 @@ BOOST_FIXTURE_TEST_CASE( propose_invalidate_approve, eosio_msig_tester ) try { ("level", permission_level{ "alice"_n, config::active_name }) ); - //successfully execute - transaction_trace_ptr trace; - control->applied_transaction.connect( - [&]( std::tuple p ) { - trace = std::get<0>(p); - } ); - - push_action( "bob"_n, "exec"_n, mvo() - ("proposer", "alice") - ("proposal_name", "first") - ("executer", "bob") + transaction_trace_ptr trace = push_action( "bob"_n, "exec"_n, mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("executer", "bob") ); BOOST_REQUIRE( bool(trace) ); - BOOST_REQUIRE_EQUAL( 1, trace->action_traces.size() ); BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); + BOOST_REQUIRE_EQUAL( 2, trace->action_traces.size() ); + + auto exec_trace = trace->action_traces.at(0); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.act.account ); + BOOST_REQUIRE_EQUAL( "exec"_n, exec_trace.act.name ); + BOOST_REQUIRE_EQUAL( 1, exec_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "bob"_n, exec_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, exec_trace.act.authorization.at(0).permission ); + + auto reqauth_trace = trace->action_traces.at(1); + BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.act.account ); + BOOST_REQUIRE_EQUAL( "reqauth"_n, reqauth_trace.act.name ); + BOOST_REQUIRE_EQUAL( 1, reqauth_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "alice"_n, reqauth_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, reqauth_trace.act.authorization.at(0).permission ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( approve_execute_old, eosio_msig_tester ) try { @@ -831,21 +869,31 @@ BOOST_FIXTURE_TEST_CASE( approve_execute_old, eosio_msig_tester ) try { ("level", permission_level{ "alice"_n, config::active_name }) ); - transaction_trace_ptr trace; - control->applied_transaction.connect( - [&]( std::tuple p ) { - trace = std::get<0>(p); - } ); - - push_action( "alice"_n, "exec"_n, mvo() - ("proposer", "alice") - ("proposal_name", "first") - ("executer", "alice") + transaction_trace_ptr trace = push_action( "alice"_n, "exec"_n, mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("executer", "alice") ); BOOST_REQUIRE( bool(trace) ); - BOOST_REQUIRE_EQUAL( 1, trace->action_traces.size() ); BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); + BOOST_REQUIRE_EQUAL( 2, trace->action_traces.size() ); + + auto exec_trace = trace->action_traces.at(0); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.act.account ); + BOOST_REQUIRE_EQUAL( "exec"_n, exec_trace.act.name ); + BOOST_REQUIRE_EQUAL( 1, exec_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "alice"_n, exec_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, exec_trace.act.authorization.at(0).permission ); + + auto reqauth_trace = trace->action_traces.at(1); + BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.act.account ); + BOOST_REQUIRE_EQUAL( "reqauth"_n, reqauth_trace.act.name ); + BOOST_REQUIRE_EQUAL( 1, reqauth_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "alice"_n, reqauth_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, reqauth_trace.act.authorization.at(0).permission ); } FC_LOG_AND_RETHROW() @@ -934,21 +982,33 @@ BOOST_FIXTURE_TEST_CASE( approve_by_two_old, eosio_msig_tester ) try { ("level", permission_level{ "bob"_n, config::active_name }) ); - transaction_trace_ptr trace; - control->applied_transaction.connect( - [&]( std::tuple p ) { - trace = std::get<0>(p); - } ); - - push_action( "alice"_n, "exec"_n, mvo() - ("proposer", "alice") - ("proposal_name", "first") - ("executer", "alice") + transaction_trace_ptr trace = push_action( "alice"_n, "exec"_n, mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("executer", "alice") ); BOOST_REQUIRE( bool(trace) ); - BOOST_REQUIRE_EQUAL( 1, trace->action_traces.size() ); BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); + BOOST_REQUIRE_EQUAL( 2, trace->action_traces.size() ); + + auto exec_trace = trace->action_traces.at(0); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.act.account ); + BOOST_REQUIRE_EQUAL( "exec"_n, exec_trace.act.name ); + BOOST_REQUIRE_EQUAL( 1, exec_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "alice"_n, exec_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, exec_trace.act.authorization.at(0).permission ); + + auto reqauth_trace = trace->action_traces.at(1); + BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.act.account ); + BOOST_REQUIRE_EQUAL( "reqauth"_n, reqauth_trace.act.name ); + BOOST_REQUIRE_EQUAL( 2, reqauth_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "alice"_n, reqauth_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, reqauth_trace.act.authorization.at(0).permission ); + BOOST_REQUIRE_EQUAL( "bob"_n, reqauth_trace.act.authorization.at(1).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, reqauth_trace.act.authorization.at(1).permission ); } FC_LOG_AND_RETHROW() @@ -982,22 +1042,32 @@ BOOST_FIXTURE_TEST_CASE( approve_with_hash, eosio_msig_tester ) try { ("level", permission_level{ "alice"_n, config::active_name }) ("proposal_hash", trx_hash) ); - - transaction_trace_ptr trace; - control->applied_transaction.connect( - [&]( std::tuple p ) { - trace = std::get<0>(p); - } ); - - push_action( "alice"_n, "exec"_n, mvo() - ("proposer", "alice") - ("proposal_name", "first") - ("executer", "alice") + + transaction_trace_ptr trace = push_action( "alice"_n, "exec"_n, mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("executer", "alice") ); BOOST_REQUIRE( bool(trace) ); - BOOST_REQUIRE_EQUAL( 1, trace->action_traces.size() ); BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); + BOOST_REQUIRE_EQUAL( 2, trace->action_traces.size() ); + + auto exec_trace = trace->action_traces.at(0); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.act.account ); + BOOST_REQUIRE_EQUAL( "exec"_n, exec_trace.act.name ); + BOOST_REQUIRE_EQUAL( 1, exec_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "alice"_n, exec_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, exec_trace.act.authorization.at(0).permission ); + + auto reqauth_trace = trace->action_traces.at(1); + BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.act.account ); + BOOST_REQUIRE_EQUAL( "reqauth"_n, reqauth_trace.act.name ); + BOOST_REQUIRE_EQUAL( 1, reqauth_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "alice"_n, reqauth_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, reqauth_trace.act.authorization.at(0).permission ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( switch_proposal_and_fail_approve_with_hash, eosio_msig_tester ) try { diff --git a/tests/eosio.wrap_tests.cpp b/tests/eosio.wrap_tests.cpp index f6a01be8..2ba0a637 100644 --- a/tests/eosio.wrap_tests.cpp +++ b/tests/eosio.wrap_tests.cpp @@ -165,41 +165,34 @@ BOOST_AUTO_TEST_SUITE(eosio_wrap_tests) BOOST_FIXTURE_TEST_CASE( wrap_exec_direct, eosio_wrap_tester ) try { auto trx = reqauth( "bob"_n, {permission_level{"bob"_n, config::active_name}} ); - transaction_trace_ptr trace; - control->applied_transaction.connect( - [&]( std::tuple p ) { - //the second will be onblock, we need only wrap transaction - if (!trace) - trace = std::get<0>(p); - } ); - - { - signed_transaction wrap_trx( wrap_exec( "alice"_n, trx ), {}, {} ); - /* - set_transaction_headers( wrap_trx ); - wrap_trx.actions.emplace_back( get_action( "eosio.wrap"_n, "exec"_n, - {{"alice"_n, config::active_name}, {"eosio.wrap"_n, config::active_name}}, - mvo() - ("executer", "alice") - ("trx", trx) - ) ); - */ - wrap_trx.sign( get_private_key( "alice"_n, "active" ), control->get_chain_id() ); - for( const auto& actor : {"prod1"_n, "prod2"_n, "prod3"_n, "prod4"_n} ) { - wrap_trx.sign( get_private_key( actor, "active" ), control->get_chain_id() ); - } - push_transaction( wrap_trx ); + signed_transaction wrap_trx( wrap_exec( "alice"_n, trx ), {}, {} ); + wrap_trx.sign( get_private_key( "alice"_n, "active" ), control->get_chain_id() ); + for( const auto& actor : {"prod1"_n, "prod2"_n, "prod3"_n, "prod4"_n} ) { + wrap_trx.sign( get_private_key( actor, "active" ), control->get_chain_id() ); } - - produce_block(); + transaction_trace_ptr trace = push_transaction( wrap_trx ); BOOST_REQUIRE( bool(trace) ); - BOOST_REQUIRE_EQUAL( 2, trace->action_traces.size() ); - BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, name{trace->action_traces[0].act.account} ); - BOOST_REQUIRE_EQUAL( "exec"_n, name{trace->action_traces[0].act.name} ); - BOOST_REQUIRE_EQUAL( config::system_account_name, name{trace->action_traces[1].act.account} ); - BOOST_REQUIRE_EQUAL( "reqauth"_n, name{trace->action_traces[1].act.name} ); BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); + BOOST_REQUIRE_EQUAL( 2, trace->action_traces.size() ); + + auto exec_trace = trace->action_traces.at(0); + BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, exec_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, exec_trace.act.account ); + BOOST_REQUIRE_EQUAL( "exec"_n, exec_trace.act.name ); + BOOST_REQUIRE_EQUAL( 2, exec_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "alice"_n, exec_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, exec_trace.act.authorization.at(0).permission ); + BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, exec_trace.act.authorization.at(1).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, exec_trace.act.authorization.at(1).permission ); + + auto reqauth_trace = trace->action_traces.at(1); + BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.act.account ); + BOOST_REQUIRE_EQUAL( "reqauth"_n, reqauth_trace.act.name ); + BOOST_REQUIRE_EQUAL( 1, reqauth_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "bob"_n, reqauth_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, reqauth_trace.act.authorization.at(0).permission ); } FC_LOG_AND_RETHROW() @@ -220,18 +213,11 @@ BOOST_FIXTURE_TEST_CASE( wrap_with_msig, eosio_wrap_tester ) try { approve( "carol"_n, "first"_n, "prod3"_n ); approve( "carol"_n, "first"_n, "prod4"_n ); - vector traces; - control->applied_transaction.connect( - [&]( std::tuple p ) { - traces.push_back( std::get<0>(p) ); - } ); - // Now the proposal should be ready to execute - transaction_trace_ptr trx_trace; - trx_trace = push_action( "eosio.msig"_n, "exec"_n, "alice"_n, mvo() - ("proposer", "carol") - ("proposal_name", "first") - ("executer", "alice") + transaction_trace_ptr trx_trace = push_action( "eosio.msig"_n, "exec"_n, "alice"_n, mvo() + ("proposer", "carol") + ("proposal_name", "first") + ("executer", "alice") ); produce_block(); @@ -240,36 +226,40 @@ BOOST_FIXTURE_TEST_CASE( wrap_with_msig, eosio_wrap_tester ) try { BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); BOOST_REQUIRE_EQUAL( 3, trx_trace->action_traces.size() ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(0).action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).closest_unnotified_ancestor_action_ordinal ); - // EOSIO 1.8 N() macro returns a uint64_t rather than a struct name - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, action_name{trx_trace->action_traces.at(0).receiver} ); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, name{trx_trace->action_traces.at(0).act.account} ); - BOOST_REQUIRE_EQUAL( "exec"_n, name{trx_trace->action_traces.at(0).act.name} ); - BOOST_REQUIRE_EQUAL( "alice"_n, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); - - BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(1).action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, action_name{trx_trace->action_traces.at(1).receiver} ); - BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, name{trx_trace->action_traces.at(1).act.account} ); - BOOST_REQUIRE_EQUAL( "exec"_n, name{trx_trace->action_traces.at(1).act.name} ); - BOOST_REQUIRE_EQUAL( "alice"_n, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); - BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, name{trx_trace->action_traces.at(1).act.authorization[1].actor} ); - BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(1).act.authorization[1].permission} ); - - BOOST_REQUIRE_EQUAL( fc::unsigned_int{3}, trx_trace->action_traces.at(2).action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(2).creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(2).closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( config::system_account_name, action_name{trx_trace->action_traces.at(2).receiver} ); - BOOST_REQUIRE_EQUAL( config::system_account_name, name{trx_trace->action_traces.at(2).act.account} ); - BOOST_REQUIRE_EQUAL( "reqauth"_n, name{trx_trace->action_traces.at(2).act.name} ); - BOOST_REQUIRE_EQUAL( 1, trx_trace->action_traces.at(2).act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "bob"_n, name{trx_trace->action_traces.at(2).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(2).act.authorization[0].permission} ); + auto msig_exec_trace = trx_trace->action_traces.at(0); + BOOST_REQUIRE_EQUAL( 1, msig_exec_trace.action_ordinal ); + BOOST_REQUIRE_EQUAL( 0, msig_exec_trace.creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( 0, msig_exec_trace.closest_unnotified_ancestor_action_ordinal ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, msig_exec_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, msig_exec_trace.act.account ); + BOOST_REQUIRE_EQUAL( "exec"_n, msig_exec_trace.act.name ); + BOOST_REQUIRE_EQUAL( 1, msig_exec_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "alice"_n, msig_exec_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, msig_exec_trace.act.authorization.at(0).permission ); + + auto wrap_exec_trace = trx_trace->action_traces.at(1); + BOOST_REQUIRE_EQUAL( 2, wrap_exec_trace.action_ordinal ); + BOOST_REQUIRE_EQUAL( 1, wrap_exec_trace.creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( 1, wrap_exec_trace.closest_unnotified_ancestor_action_ordinal ); + BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, wrap_exec_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, wrap_exec_trace.act.account ); + BOOST_REQUIRE_EQUAL( "exec"_n, wrap_exec_trace.act.name ); + BOOST_REQUIRE_EQUAL( 2, wrap_exec_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "alice"_n, wrap_exec_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, wrap_exec_trace.act.authorization.at(0).permission ); + BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, wrap_exec_trace.act.authorization.at(1).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, wrap_exec_trace.act.authorization.at(1).permission ); + + auto reqauth_trace = trx_trace->action_traces.at(2); + BOOST_REQUIRE_EQUAL( 3, reqauth_trace.action_ordinal ); + BOOST_REQUIRE_EQUAL( 2, reqauth_trace.creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( 2, reqauth_trace.closest_unnotified_ancestor_action_ordinal ); + BOOST_REQUIRE_EQUAL( config::system_account_name, reqauth_trace.receiver ); + BOOST_REQUIRE_EQUAL( config::system_account_name, reqauth_trace.act.account ); + BOOST_REQUIRE_EQUAL( "reqauth"_n, reqauth_trace.act.name ); + BOOST_REQUIRE_EQUAL( 1, reqauth_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "bob"_n, reqauth_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, reqauth_trace.act.authorization.at(0).permission ); } FC_LOG_AND_RETHROW() @@ -357,12 +347,6 @@ BOOST_FIXTURE_TEST_CASE( wrap_with_msig_producers_change, eosio_wrap_tester ) tr // But prod5 still can provide the fifth approval necessary to satisfy the 2/3+1 threshold of the new producer set approve( "carol"_n, "first"_n, "prod5"_n ); - vector traces; - control->applied_transaction.connect( - [&]( std::tuple p ) { - traces.push_back( std::get<0>(p) ); - } ); - // Now the proposal should be ready to execute transaction_trace_ptr trx_trace; trx_trace = push_action( "eosio.msig"_n, "exec"_n, "alice"_n, mvo() @@ -370,43 +354,45 @@ BOOST_FIXTURE_TEST_CASE( wrap_with_msig_producers_change, eosio_wrap_tester ) tr ("proposer", "carol") ("executer", "alice") ); - - produce_block(); BOOST_REQUIRE( bool(trx_trace) ); BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); BOOST_REQUIRE_EQUAL( 3, trx_trace->action_traces.size() ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(0).action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).closest_unnotified_ancestor_action_ordinal ); - // EOSIO 1.8 N() macro returns a uint64_t rather than a struct name - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, action_name{trx_trace->action_traces.at(0).receiver} ); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, name{trx_trace->action_traces.at(0).act.account} ); - BOOST_REQUIRE_EQUAL( "exec"_n, name{trx_trace->action_traces.at(0).act.name} ); - BOOST_REQUIRE_EQUAL( "alice"_n, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); - - BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(1).action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, action_name{trx_trace->action_traces.at(1).receiver} ); - BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, name{trx_trace->action_traces.at(1).act.account} ); - BOOST_REQUIRE_EQUAL( "exec"_n, name{trx_trace->action_traces.at(1).act.name} ); - BOOST_REQUIRE_EQUAL( "alice"_n, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); - BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, name{trx_trace->action_traces.at(1).act.authorization[1].actor} ); - BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(1).act.authorization[1].permission} ); - - BOOST_REQUIRE_EQUAL( fc::unsigned_int{3}, trx_trace->action_traces.at(2).action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(2).creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(2).closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( config::system_account_name, action_name{trx_trace->action_traces.at(2).receiver} ); - BOOST_REQUIRE_EQUAL( config::system_account_name, name{trx_trace->action_traces.at(2).act.account} ); - BOOST_REQUIRE_EQUAL( "reqauth"_n, name{trx_trace->action_traces.at(2).act.name} ); - BOOST_REQUIRE_EQUAL( 1, trx_trace->action_traces.at(2).act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "bob"_n, name{trx_trace->action_traces.at(2).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(2).act.authorization[0].permission} ); + auto msig_exec_trace = trx_trace->action_traces.at(0); + BOOST_REQUIRE_EQUAL( 1, msig_exec_trace.action_ordinal ); + BOOST_REQUIRE_EQUAL( 0, msig_exec_trace.creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( 0, msig_exec_trace.closest_unnotified_ancestor_action_ordinal ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, msig_exec_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio.msig"_n, msig_exec_trace.act.account ); + BOOST_REQUIRE_EQUAL( "exec"_n, msig_exec_trace.act.name ); + BOOST_REQUIRE_EQUAL( 1, msig_exec_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "alice"_n, msig_exec_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, msig_exec_trace.act.authorization.at(0).permission ); + + auto wrap_exec_trace = trx_trace->action_traces.at(1); + BOOST_REQUIRE_EQUAL( 2, wrap_exec_trace.action_ordinal ); + BOOST_REQUIRE_EQUAL( 1, wrap_exec_trace.creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( 1, wrap_exec_trace.closest_unnotified_ancestor_action_ordinal ); + BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, wrap_exec_trace.receiver ); + BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, wrap_exec_trace.act.account ); + BOOST_REQUIRE_EQUAL( "exec"_n, wrap_exec_trace.act.name ); + BOOST_REQUIRE_EQUAL( 2, wrap_exec_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "alice"_n, wrap_exec_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, wrap_exec_trace.act.authorization.at(0).permission ); + BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, wrap_exec_trace.act.authorization.at(1).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, wrap_exec_trace.act.authorization.at(1).permission ); + + auto reqauth_trace = trx_trace->action_traces.at(2); + BOOST_REQUIRE_EQUAL( 3, reqauth_trace.action_ordinal ); + BOOST_REQUIRE_EQUAL( 2, reqauth_trace.creator_action_ordinal ); + BOOST_REQUIRE_EQUAL( 2, reqauth_trace.closest_unnotified_ancestor_action_ordinal ); + BOOST_REQUIRE_EQUAL( config::system_account_name, reqauth_trace.receiver ); + BOOST_REQUIRE_EQUAL( config::system_account_name, reqauth_trace.act.account ); + BOOST_REQUIRE_EQUAL( "reqauth"_n, reqauth_trace.act.name ); + BOOST_REQUIRE_EQUAL( 1, reqauth_trace.act.authorization.size() ); + BOOST_REQUIRE_EQUAL( "bob"_n, reqauth_trace.act.authorization.at(0).actor ); + BOOST_REQUIRE_EQUAL( "active"_n, reqauth_trace.act.authorization.at(0).permission ); } FC_LOG_AND_RETHROW() From a7ad82f39befae90e67167ba9b8a56f8699b5f84 Mon Sep 17 00:00:00 2001 From: Dmytro Sydorchenko Date: Tue, 18 Oct 2022 15:16:48 -0400 Subject: [PATCH 26/96] add expiration check to wrap contract --- contracts/eosio.wrap/src/eosio.wrap.cpp | 5 ++--- tests/eosio.wrap_tests.cpp | 13 +++---------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/contracts/eosio.wrap/src/eosio.wrap.cpp b/contracts/eosio.wrap/src/eosio.wrap.cpp index abbdf90a..a1a9f198 100644 --- a/contracts/eosio.wrap/src/eosio.wrap.cpp +++ b/contracts/eosio.wrap/src/eosio.wrap.cpp @@ -10,16 +10,15 @@ void wrap::exec( ignore, ignore ) { require_auth( executer ); - //send_deferred( (uint128_t(executer.value) << 64) | (uint64_t)current_time_point().time_since_epoch().count(), executer, _ds.pos(), _ds.remaining() ); transaction_header trx_header; std::vector context_free_actions; std::vector actions; _ds >> trx_header; - //check( trx_header.expiration >= eosio::time_point_sec(current_time_point()), "transaction expired" ); + check( trx_header.expiration >= current_time_point(), "transaction expired" ); _ds >> context_free_actions; check( context_free_actions.empty(), "not allowed to `exec` a transaction with context-free actions" ); _ds >> actions; - + for (const auto& act : actions) { act.send(); } diff --git a/tests/eosio.wrap_tests.cpp b/tests/eosio.wrap_tests.cpp index 2ba0a637..143dddf5 100644 --- a/tests/eosio.wrap_tests.cpp +++ b/tests/eosio.wrap_tests.cpp @@ -73,12 +73,7 @@ class eosio_wrap_tester : public tester { set_producers( {"prod1"_n, "prod2"_n, "prod3"_n, "prod4"_n, "prod5"_n} ); produce_blocks(); - - const auto& accnt = control->db().get( "eosio.wrap"_n ); - abi_def abi; - BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true); - abi_ser.set_abi(abi, abi_serializer::create_yield_function(abi_serializer_max_time)); - + while( control->pending_block_producer().to_string() == "eosio" ) { produce_block(); } @@ -112,8 +107,6 @@ class eosio_wrap_tester : public tester { transaction wrap_exec( account_name executer, const transaction& trx, uint32_t expiration = base_tester::DEFAULT_EXPIRATION_DELTA ); transaction reqauth( account_name from, const vector& auths, uint32_t expiration = base_tester::DEFAULT_EXPIRATION_DELTA ); - - abi_serializer abi_ser; }; transaction eosio_wrap_tester::wrap_exec( account_name executer, const transaction& trx, uint32_t expiration ) { @@ -301,7 +294,7 @@ BOOST_FIXTURE_TEST_CASE( wrap_with_msig_unapprove, eosio_wrap_tester ) try { BOOST_FIXTURE_TEST_CASE( wrap_with_msig_producers_change, eosio_wrap_tester ) try { create_accounts( { "newprod1"_n } ); - auto trx = reqauth( "bob"_n, {permission_level{"bob"_n, config::active_name}} ); + auto trx = reqauth( "bob"_n, {permission_level{"bob"_n, config::active_name}}, 120 ); auto wrap_trx = wrap_exec( "alice"_n, trx, 36000 ); propose( "carol"_n, "first"_n, @@ -354,7 +347,7 @@ BOOST_FIXTURE_TEST_CASE( wrap_with_msig_producers_change, eosio_wrap_tester ) tr ("proposer", "carol") ("executer", "alice") ); - + BOOST_REQUIRE( bool(trx_trace) ); BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); BOOST_REQUIRE_EQUAL( 3, trx_trace->action_traces.size() ); From 8e88e18cdf4c88212023df652f4a43c583c49290 Mon Sep 17 00:00:00 2001 From: Dmytro Sydorchenko Date: Mon, 24 Oct 2022 13:49:42 -0400 Subject: [PATCH 27/96] #11 review concerns addressed --- contracts/eosio.wrap/src/eosio.wrap.cpp | 1 - tests/eosio.msig_tests.cpp | 335 ++++++------------------ tests/eosio.wrap_tests.cpp | 141 +++------- 3 files changed, 109 insertions(+), 368 deletions(-) diff --git a/contracts/eosio.wrap/src/eosio.wrap.cpp b/contracts/eosio.wrap/src/eosio.wrap.cpp index a1a9f198..472ed4a5 100644 --- a/contracts/eosio.wrap/src/eosio.wrap.cpp +++ b/contracts/eosio.wrap/src/eosio.wrap.cpp @@ -14,7 +14,6 @@ void wrap::exec( ignore, ignore ) { std::vector context_free_actions; std::vector actions; _ds >> trx_header; - check( trx_header.expiration >= current_time_point(), "transaction expired" ); _ds >> context_free_actions; check( context_free_actions.empty(), "not allowed to `exec` a transaction with context-free actions" ); _ds >> actions; diff --git a/tests/eosio.msig_tests.cpp b/tests/eosio.msig_tests.cpp index 11271be0..f3a9f968 100644 --- a/tests/eosio.msig_tests.cpp +++ b/tests/eosio.msig_tests.cpp @@ -3,9 +3,6 @@ #include #include #include -#include -#include - #include @@ -151,6 +148,8 @@ class eosio_msig_tester : public tester { transaction reqauth( account_name from, const vector& auths, const fc::microseconds& max_serialization_time ); + void check_traces(transaction_trace_ptr trace, std::vector> res); + abi_serializer abi_ser; }; @@ -182,6 +181,19 @@ transaction eosio_msig_tester::reqauth( account_name from, const vector> res) { + + BOOST_REQUIRE( bool(trace) ); + BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); + BOOST_REQUIRE_EQUAL( res.size(), trace->action_traces.size() ); + + for (size_t i = 0; i < res.size(); i++) { + auto cur_action = trace->action_traces.at(i); + BOOST_REQUIRE_EQUAL( res[i]["receiver"], cur_action.receiver ); + BOOST_REQUIRE_EQUAL( res[i]["act_name"], cur_action.act.name ); + } +} + BOOST_AUTO_TEST_SUITE(eosio_msig_tests) BOOST_FIXTURE_TEST_CASE( propose_approve_execute, eosio_msig_tester ) try { @@ -217,25 +229,10 @@ BOOST_FIXTURE_TEST_CASE( propose_approve_execute, eosio_msig_tester ) try { ("executer", "alice") ); - BOOST_REQUIRE( bool(trace) ); - BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); - BOOST_REQUIRE_EQUAL( 2, trace->action_traces.size() ); - - auto exec_trace = trace->action_traces.at(0); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.act.account ); - BOOST_REQUIRE_EQUAL( "exec"_n, exec_trace.act.name ); - BOOST_REQUIRE_EQUAL( 1, exec_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "alice"_n, exec_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, exec_trace.act.authorization.at(0).permission ); - - auto reqauth_trace = trace->action_traces.at(1); - BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.act.account ); - BOOST_REQUIRE_EQUAL( "reqauth"_n, reqauth_trace.act.name ); - BOOST_REQUIRE_EQUAL( 1, reqauth_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "alice"_n, reqauth_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, reqauth_trace.act.authorization.at(0).permission ); + check_traces( trace, { + {{"receiver", "eosio.msig"_n}, {"act_name", "exec"_n}}, + {{"receiver", config::system_account_name}, {"act_name", "reqauth"_n}} + } ); } FC_LOG_AND_RETHROW() @@ -313,27 +310,10 @@ BOOST_FIXTURE_TEST_CASE( propose_approve_by_two, eosio_msig_tester ) try { ("executer", "alice") ); - BOOST_REQUIRE( bool(trace) ); - BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); - BOOST_REQUIRE_EQUAL( 2, trace->action_traces.size() ); - - auto exec_trace = trace->action_traces.at(0); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.act.account ); - BOOST_REQUIRE_EQUAL( "exec"_n, exec_trace.act.name ); - BOOST_REQUIRE_EQUAL( 1, exec_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "alice"_n, exec_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, exec_trace.act.authorization.at(0).permission ); - - auto reqauth_trace = trace->action_traces.at(1); - BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.act.account ); - BOOST_REQUIRE_EQUAL( "reqauth"_n, reqauth_trace.act.name ); - BOOST_REQUIRE_EQUAL( 2, reqauth_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "alice"_n, reqauth_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, reqauth_trace.act.authorization.at(0).permission ); - BOOST_REQUIRE_EQUAL( "bob"_n, reqauth_trace.act.authorization.at(1).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, reqauth_trace.act.authorization.at(1).permission ); + check_traces( trace, { + {{"receiver", "eosio.msig"_n}, {"act_name", "exec"_n}}, + {{"receiver", config::system_account_name}, {"act_name", "reqauth"_n}} + } ); } FC_LOG_AND_RETHROW() @@ -415,27 +395,10 @@ BOOST_FIXTURE_TEST_CASE( big_transaction, eosio_msig_tester ) try { ("executer", "alice") ); - BOOST_REQUIRE( bool(trace) ); - BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); - BOOST_REQUIRE_EQUAL( 2, trace->action_traces.size() ); - - auto exec_trace = trace->action_traces.at(0); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.act.account ); - BOOST_REQUIRE_EQUAL( "exec"_n, exec_trace.act.name ); - BOOST_REQUIRE_EQUAL( 1, exec_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "alice"_n, exec_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, exec_trace.act.authorization.at(0).permission ); - - auto setcode_trace = trace->action_traces.at(1); - BOOST_REQUIRE_EQUAL( "eosio"_n, setcode_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio"_n, setcode_trace.act.account ); - BOOST_REQUIRE_EQUAL( "setcode"_n, setcode_trace.act.name ); - BOOST_REQUIRE_EQUAL( 2, setcode_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "alice"_n, setcode_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, setcode_trace.act.authorization.at(0).permission ); - BOOST_REQUIRE_EQUAL( "bob"_n, setcode_trace.act.authorization.at(1).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, setcode_trace.act.authorization.at(1).permission ); + check_traces( trace, { + {{"receiver", "eosio.msig"_n}, {"act_name", "exec"_n}}, + {{"receiver", config::system_account_name}, {"act_name", "setcode"_n}} + } ); } FC_LOG_AND_RETHROW() @@ -548,41 +511,18 @@ BOOST_FIXTURE_TEST_CASE( update_system_contract_all_approve, eosio_msig_tester ) ); // execute by alice to replace the eosio system contract - transaction_trace_ptr trx_trace = push_action( "alice"_n, "exec"_n, mvo() - ("proposer", "alice") - ("proposal_name", "first") - ("executer", "alice") + transaction_trace_ptr trace = push_action( "alice"_n, "exec"_n, mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("executer", "alice") ); - BOOST_REQUIRE( bool(trx_trace) ); - BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); - BOOST_REQUIRE_EQUAL( 2, trx_trace->action_traces.size() ); - - auto exec_trace = trx_trace->action_traces.at(0); - BOOST_REQUIRE_EQUAL( 1, exec_trace.action_ordinal ); - BOOST_REQUIRE_EQUAL( 0, exec_trace.creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( 0, exec_trace.closest_unnotified_ancestor_action_ordinal ); + check_traces( trace, { + {{"receiver", "eosio.msig"_n}, {"act_name", "exec"_n}}, + {{"receiver", config::system_account_name}, {"act_name", "setcode"_n}} + } ); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.act.account ); - BOOST_REQUIRE_EQUAL( "exec"_n, exec_trace.act.name ); - BOOST_REQUIRE_EQUAL( 1, exec_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "alice"_n, exec_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, exec_trace.act.authorization.at(0).permission ); - - auto setcode_trace = trx_trace->action_traces.at(1); - BOOST_REQUIRE_EQUAL( 2, setcode_trace.action_ordinal ); - BOOST_REQUIRE_EQUAL( 1, setcode_trace.creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( 1, setcode_trace.closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( "eosio"_n, setcode_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio"_n, setcode_trace.act.account ); - BOOST_REQUIRE_EQUAL( "setcode"_n, setcode_trace.act.name ); - BOOST_REQUIRE_EQUAL( 1, setcode_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "eosio"_n, setcode_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, setcode_trace.act.authorization.at(0).permission ); - // can't create account because system contract was replaced by the reject_all contract - BOOST_REQUIRE_EXCEPTION( create_account_with_resources( "alice1111112"_n, "eosio"_n, core_sym::from_string("1.0000"), false ), eosio_assert_message_exception, eosio_assert_message_is("rejecting all actions") @@ -701,41 +641,18 @@ BOOST_FIXTURE_TEST_CASE( update_system_contract_major_approve, eosio_msig_tester ("level", permission_level{ "apple"_n, config::active_name }) ); // execute by another producer different from proposer - transaction_trace_ptr trx_trace = push_action( "apple"_n, "exec"_n, mvo() - ("proposer", "alice") - ("proposal_name", "first") - ("executer", "apple") + transaction_trace_ptr trace = push_action( "apple"_n, "exec"_n, mvo() + ("proposer", "alice") + ("proposal_name", "first") + ("executer", "apple") ); - BOOST_REQUIRE( bool(trx_trace) ); - BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); - BOOST_REQUIRE_EQUAL( 2, trx_trace->action_traces.size() ); - - auto exec_trace = trx_trace->action_traces.at(0); - BOOST_REQUIRE_EQUAL( 1, exec_trace.action_ordinal ); - BOOST_REQUIRE_EQUAL( 0, exec_trace.creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( 0, exec_trace.closest_unnotified_ancestor_action_ordinal ); + check_traces( trace, { + {{"receiver", "eosio.msig"_n}, {"act_name", "exec"_n}}, + {{"receiver", config::system_account_name}, {"act_name", "setcode"_n}} + } ); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.act.account ); - BOOST_REQUIRE_EQUAL( "exec"_n, exec_trace.act.name ); - BOOST_REQUIRE_EQUAL( 1, exec_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "apple"_n, exec_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, exec_trace.act.authorization.at(0).permission ); - - auto setcode_trace = trx_trace->action_traces.at(1); - BOOST_REQUIRE_EQUAL( 2, setcode_trace.action_ordinal ); - BOOST_REQUIRE_EQUAL( 1, setcode_trace.creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( 1, setcode_trace.closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( "eosio"_n, setcode_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio"_n, setcode_trace.act.account ); - BOOST_REQUIRE_EQUAL( "setcode"_n, setcode_trace.act.name ); - BOOST_REQUIRE_EQUAL( 1, setcode_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "eosio"_n, setcode_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, setcode_trace.act.authorization.at(0).permission ); - // can't create account because system contract was replaced by the reject_all contract - BOOST_REQUIRE_EXCEPTION( create_account_with_resources( "alice1111112"_n, "eosio"_n, core_sym::from_string("1.0000"), false ), eosio_assert_message_exception, eosio_assert_message_is("rejecting all actions") @@ -823,25 +740,10 @@ BOOST_FIXTURE_TEST_CASE( propose_invalidate_approve, eosio_msig_tester ) try { ("executer", "bob") ); - BOOST_REQUIRE( bool(trace) ); - BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); - BOOST_REQUIRE_EQUAL( 2, trace->action_traces.size() ); - - auto exec_trace = trace->action_traces.at(0); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.act.account ); - BOOST_REQUIRE_EQUAL( "exec"_n, exec_trace.act.name ); - BOOST_REQUIRE_EQUAL( 1, exec_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "bob"_n, exec_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, exec_trace.act.authorization.at(0).permission ); - - auto reqauth_trace = trace->action_traces.at(1); - BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.act.account ); - BOOST_REQUIRE_EQUAL( "reqauth"_n, reqauth_trace.act.name ); - BOOST_REQUIRE_EQUAL( 1, reqauth_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "alice"_n, reqauth_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, reqauth_trace.act.authorization.at(0).permission ); + check_traces( trace, { + {{"receiver", "eosio.msig"_n}, {"act_name", "exec"_n}}, + {{"receiver", config::system_account_name}, {"act_name", "reqauth"_n}} + } ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( approve_execute_old, eosio_msig_tester ) try { @@ -874,27 +776,10 @@ BOOST_FIXTURE_TEST_CASE( approve_execute_old, eosio_msig_tester ) try { ("proposal_name", "first") ("executer", "alice") ); - - BOOST_REQUIRE( bool(trace) ); - BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); - BOOST_REQUIRE_EQUAL( 2, trace->action_traces.size() ); - - auto exec_trace = trace->action_traces.at(0); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.act.account ); - BOOST_REQUIRE_EQUAL( "exec"_n, exec_trace.act.name ); - BOOST_REQUIRE_EQUAL( 1, exec_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "alice"_n, exec_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, exec_trace.act.authorization.at(0).permission ); - - auto reqauth_trace = trace->action_traces.at(1); - BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.act.account ); - BOOST_REQUIRE_EQUAL( "reqauth"_n, reqauth_trace.act.name ); - BOOST_REQUIRE_EQUAL( 1, reqauth_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "alice"_n, reqauth_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, reqauth_trace.act.authorization.at(0).permission ); - + check_traces( trace, { + {{"receiver", "eosio.msig"_n}, {"act_name", "exec"_n}}, + {{"receiver", config::system_account_name}, {"act_name", "reqauth"_n}} + } ); } FC_LOG_AND_RETHROW() @@ -987,28 +872,10 @@ BOOST_FIXTURE_TEST_CASE( approve_by_two_old, eosio_msig_tester ) try { ("proposal_name", "first") ("executer", "alice") ); - - BOOST_REQUIRE( bool(trace) ); - BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); - BOOST_REQUIRE_EQUAL( 2, trace->action_traces.size() ); - - auto exec_trace = trace->action_traces.at(0); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.act.account ); - BOOST_REQUIRE_EQUAL( "exec"_n, exec_trace.act.name ); - BOOST_REQUIRE_EQUAL( 1, exec_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "alice"_n, exec_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, exec_trace.act.authorization.at(0).permission ); - - auto reqauth_trace = trace->action_traces.at(1); - BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.act.account ); - BOOST_REQUIRE_EQUAL( "reqauth"_n, reqauth_trace.act.name ); - BOOST_REQUIRE_EQUAL( 2, reqauth_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "alice"_n, reqauth_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, reqauth_trace.act.authorization.at(0).permission ); - BOOST_REQUIRE_EQUAL( "bob"_n, reqauth_trace.act.authorization.at(1).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, reqauth_trace.act.authorization.at(1).permission ); + check_traces( trace, { + {{"receiver", "eosio.msig"_n}, {"act_name", "exec"_n}}, + {{"receiver", config::system_account_name}, {"act_name", "reqauth"_n}} + } ); } FC_LOG_AND_RETHROW() @@ -1048,26 +915,10 @@ BOOST_FIXTURE_TEST_CASE( approve_with_hash, eosio_msig_tester ) try { ("proposal_name", "first") ("executer", "alice") ); - - BOOST_REQUIRE( bool(trace) ); - BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); - BOOST_REQUIRE_EQUAL( 2, trace->action_traces.size() ); - - auto exec_trace = trace->action_traces.at(0); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, exec_trace.act.account ); - BOOST_REQUIRE_EQUAL( "exec"_n, exec_trace.act.name ); - BOOST_REQUIRE_EQUAL( 1, exec_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "alice"_n, exec_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, exec_trace.act.authorization.at(0).permission ); - - auto reqauth_trace = trace->action_traces.at(1); - BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.act.account ); - BOOST_REQUIRE_EQUAL( "reqauth"_n, reqauth_trace.act.name ); - BOOST_REQUIRE_EQUAL( 1, reqauth_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "alice"_n, reqauth_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, reqauth_trace.act.authorization.at(0).permission ); + check_traces( trace, { + {{"receiver", "eosio.msig"_n}, {"act_name", "exec"_n}}, + {{"receiver", config::system_account_name}, {"act_name", "reqauth"_n}} + } ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( switch_proposal_and_fail_approve_with_hash, eosio_msig_tester ) try { @@ -1150,37 +1001,16 @@ BOOST_FIXTURE_TEST_CASE( sendinline, eosio_msig_tester ) try { ); produce_blocks(); - transaction_trace_ptr trx_trace; - trx_trace = base_tester::push_action( "sendinline"_n, "send"_n, "bob"_n, mvo() - ("contract", "eosio") - ("action_name", "reqauth") - ("auths", std::vector{ {"alice"_n, "perm"_n} }) - ("payload", act.data) + transaction_trace_ptr trace = base_tester::push_action( "sendinline"_n, "send"_n, "bob"_n, mvo() + ("contract", "eosio") + ("action_name", "reqauth") + ("auths", std::vector{ {"alice"_n, "perm"_n} }) + ("payload", act.data) ); - produce_blocks(); - - BOOST_REQUIRE( bool(trx_trace) ); - BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); - BOOST_REQUIRE_EQUAL( 2, trx_trace->action_traces.size() ); - - BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(0).action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).closest_unnotified_ancestor_action_ordinal ); - // EOSIO 1.8 N() macro returns a uint64_t rather than a struct name - BOOST_REQUIRE_EQUAL( "sendinline"_n, action_name{trx_trace->action_traces.at(0).receiver} ); - BOOST_REQUIRE_EQUAL( "sendinline"_n, name{trx_trace->action_traces.at(0).act.account} ); - BOOST_REQUIRE_EQUAL( "send"_n, name{trx_trace->action_traces.at(0).act.name} ); - BOOST_REQUIRE_EQUAL( "bob"_n, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); - - BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(1).action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( "eosio"_n, action_name{trx_trace->action_traces.at(1).receiver} ); - BOOST_REQUIRE_EQUAL( "eosio"_n, name{trx_trace->action_traces.at(1).act.account} ); - BOOST_REQUIRE_EQUAL( "reqauth"_n, name{trx_trace->action_traces.at(1).act.name} ); - BOOST_REQUIRE_EQUAL( "alice"_n, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( "perm"_n, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); + check_traces( trace, { + {{"receiver", "sendinline"_n}, {"act_name", "send"_n}}, + {{"receiver", config::system_account_name}, {"act_name", "reqauth"_n}} + } ); produce_blocks(); @@ -1208,34 +1038,17 @@ BOOST_FIXTURE_TEST_CASE( sendinline, eosio_msig_tester ) try { ); produce_blocks(); - trx_trace = base_tester::push_action( "eosio.msig"_n, "exec"_n, "bob"_n, mvo() + trace = base_tester::push_action( "eosio.msig"_n, "exec"_n, "bob"_n, mvo() ("proposer", "bob") ("proposal_name", "first") ("executer", "bob") ); - BOOST_REQUIRE( bool(trx_trace) ); - BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); - BOOST_REQUIRE_EQUAL( 2, trx_trace->action_traces.size() ); - - BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(0).action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{0}, trx_trace->action_traces.at(0).closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, action_name{trx_trace->action_traces.at(0).receiver} ); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, name{trx_trace->action_traces.at(0).act.account} ); - BOOST_REQUIRE_EQUAL( "exec"_n, name{trx_trace->action_traces.at(0).act.name} ); - BOOST_REQUIRE_EQUAL( "bob"_n, name{trx_trace->action_traces.at(0).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( "active"_n, name{trx_trace->action_traces.at(0).act.authorization[0].permission} ); - - BOOST_REQUIRE_EQUAL( fc::unsigned_int{2}, trx_trace->action_traces.at(1).action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( fc::unsigned_int{1}, trx_trace->action_traces.at(1).closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( "eosio"_n, action_name{trx_trace->action_traces.at(1).receiver} ); - BOOST_REQUIRE_EQUAL( "eosio"_n, name{trx_trace->action_traces.at(1).act.account} ); - BOOST_REQUIRE_EQUAL( "reqauth"_n, name{trx_trace->action_traces.at(1).act.name} ); - BOOST_REQUIRE_EQUAL( "alice"_n, name{trx_trace->action_traces.at(1).act.authorization[0].actor} ); - BOOST_REQUIRE_EQUAL( "perm"_n, name{trx_trace->action_traces.at(1).act.authorization[0].permission} ); - + check_traces( trace, { + {{"receiver", "eosio.msig"_n}, {"act_name", "exec"_n}}, + {{"receiver", config::system_account_name}, {"act_name", "reqauth"_n}} + } ); + } FC_LOG_AND_RETHROW() BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/eosio.wrap_tests.cpp b/tests/eosio.wrap_tests.cpp index 143dddf5..8f694c8f 100644 --- a/tests/eosio.wrap_tests.cpp +++ b/tests/eosio.wrap_tests.cpp @@ -107,6 +107,8 @@ class eosio_wrap_tester : public tester { transaction wrap_exec( account_name executer, const transaction& trx, uint32_t expiration = base_tester::DEFAULT_EXPIRATION_DELTA ); transaction reqauth( account_name from, const vector& auths, uint32_t expiration = base_tester::DEFAULT_EXPIRATION_DELTA ); + + void check_traces(transaction_trace_ptr trace, std::vector> res); }; transaction eosio_wrap_tester::wrap_exec( account_name executer, const transaction& trx, uint32_t expiration ) { @@ -153,6 +155,19 @@ transaction eosio_wrap_tester::reqauth( account_name from, const vector> res) { + + BOOST_REQUIRE( bool(trace) ); + BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); + BOOST_REQUIRE_EQUAL( res.size(), trace->action_traces.size() ); + + for (size_t i = 0; i < res.size(); i++) { + auto cur_action = trace->action_traces.at(i); + BOOST_REQUIRE_EQUAL( res[i]["receiver"], cur_action.receiver ); + BOOST_REQUIRE_EQUAL( res[i]["act_name"], cur_action.act.name ); + } +} + BOOST_AUTO_TEST_SUITE(eosio_wrap_tests) BOOST_FIXTURE_TEST_CASE( wrap_exec_direct, eosio_wrap_tester ) try { @@ -165,28 +180,10 @@ BOOST_FIXTURE_TEST_CASE( wrap_exec_direct, eosio_wrap_tester ) try { } transaction_trace_ptr trace = push_transaction( wrap_trx ); - BOOST_REQUIRE( bool(trace) ); - BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trace->receipt->status ); - BOOST_REQUIRE_EQUAL( 2, trace->action_traces.size() ); - - auto exec_trace = trace->action_traces.at(0); - BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, exec_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, exec_trace.act.account ); - BOOST_REQUIRE_EQUAL( "exec"_n, exec_trace.act.name ); - BOOST_REQUIRE_EQUAL( 2, exec_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "alice"_n, exec_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, exec_trace.act.authorization.at(0).permission ); - BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, exec_trace.act.authorization.at(1).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, exec_trace.act.authorization.at(1).permission ); - - auto reqauth_trace = trace->action_traces.at(1); - BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio"_n, reqauth_trace.act.account ); - BOOST_REQUIRE_EQUAL( "reqauth"_n, reqauth_trace.act.name ); - BOOST_REQUIRE_EQUAL( 1, reqauth_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "bob"_n, reqauth_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, reqauth_trace.act.authorization.at(0).permission ); - + check_traces( trace, { + {{"receiver", "eosio.wrap"_n}, {"act_name", "exec"_n}}, + {{"receiver", config::system_account_name}, {"act_name", "reqauth"_n}} + } ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( wrap_with_msig, eosio_wrap_tester ) try { @@ -207,52 +204,17 @@ BOOST_FIXTURE_TEST_CASE( wrap_with_msig, eosio_wrap_tester ) try { approve( "carol"_n, "first"_n, "prod4"_n ); // Now the proposal should be ready to execute - transaction_trace_ptr trx_trace = push_action( "eosio.msig"_n, "exec"_n, "alice"_n, mvo() + transaction_trace_ptr trace = push_action( "eosio.msig"_n, "exec"_n, "alice"_n, mvo() ("proposer", "carol") ("proposal_name", "first") ("executer", "alice") ); - produce_block(); - - BOOST_REQUIRE( bool(trx_trace) ); - BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); - BOOST_REQUIRE_EQUAL( 3, trx_trace->action_traces.size() ); - - auto msig_exec_trace = trx_trace->action_traces.at(0); - BOOST_REQUIRE_EQUAL( 1, msig_exec_trace.action_ordinal ); - BOOST_REQUIRE_EQUAL( 0, msig_exec_trace.creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( 0, msig_exec_trace.closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, msig_exec_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, msig_exec_trace.act.account ); - BOOST_REQUIRE_EQUAL( "exec"_n, msig_exec_trace.act.name ); - BOOST_REQUIRE_EQUAL( 1, msig_exec_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "alice"_n, msig_exec_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, msig_exec_trace.act.authorization.at(0).permission ); - - auto wrap_exec_trace = trx_trace->action_traces.at(1); - BOOST_REQUIRE_EQUAL( 2, wrap_exec_trace.action_ordinal ); - BOOST_REQUIRE_EQUAL( 1, wrap_exec_trace.creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( 1, wrap_exec_trace.closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, wrap_exec_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, wrap_exec_trace.act.account ); - BOOST_REQUIRE_EQUAL( "exec"_n, wrap_exec_trace.act.name ); - BOOST_REQUIRE_EQUAL( 2, wrap_exec_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "alice"_n, wrap_exec_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, wrap_exec_trace.act.authorization.at(0).permission ); - BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, wrap_exec_trace.act.authorization.at(1).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, wrap_exec_trace.act.authorization.at(1).permission ); - - auto reqauth_trace = trx_trace->action_traces.at(2); - BOOST_REQUIRE_EQUAL( 3, reqauth_trace.action_ordinal ); - BOOST_REQUIRE_EQUAL( 2, reqauth_trace.creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( 2, reqauth_trace.closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( config::system_account_name, reqauth_trace.receiver ); - BOOST_REQUIRE_EQUAL( config::system_account_name, reqauth_trace.act.account ); - BOOST_REQUIRE_EQUAL( "reqauth"_n, reqauth_trace.act.name ); - BOOST_REQUIRE_EQUAL( 1, reqauth_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "bob"_n, reqauth_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, reqauth_trace.act.authorization.at(0).permission ); + check_traces( trace, { + {{"receiver", "eosio.msig"_n}, {"act_name", "exec"_n}}, + {{"receiver", "eosio.wrap"_n}, {"act_name", "exec"_n}}, + {{"receiver", config::system_account_name}, {"act_name", "reqauth"_n}} + } ); } FC_LOG_AND_RETHROW() @@ -341,51 +303,18 @@ BOOST_FIXTURE_TEST_CASE( wrap_with_msig_producers_change, eosio_wrap_tester ) tr approve( "carol"_n, "first"_n, "prod5"_n ); // Now the proposal should be ready to execute - transaction_trace_ptr trx_trace; - trx_trace = push_action( "eosio.msig"_n, "exec"_n, "alice"_n, mvo() - ("proposal_name", "first") - ("proposer", "carol") - ("executer", "alice") + transaction_trace_ptr trace = push_action( "eosio.msig"_n, "exec"_n, "alice"_n, mvo() + ("proposal_name", "first") + ("proposer", "carol") + ("executer", "alice") ); - BOOST_REQUIRE( bool(trx_trace) ); - BOOST_REQUIRE_EQUAL( transaction_receipt::executed, trx_trace->receipt->status ); - BOOST_REQUIRE_EQUAL( 3, trx_trace->action_traces.size() ); - - auto msig_exec_trace = trx_trace->action_traces.at(0); - BOOST_REQUIRE_EQUAL( 1, msig_exec_trace.action_ordinal ); - BOOST_REQUIRE_EQUAL( 0, msig_exec_trace.creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( 0, msig_exec_trace.closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, msig_exec_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio.msig"_n, msig_exec_trace.act.account ); - BOOST_REQUIRE_EQUAL( "exec"_n, msig_exec_trace.act.name ); - BOOST_REQUIRE_EQUAL( 1, msig_exec_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "alice"_n, msig_exec_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, msig_exec_trace.act.authorization.at(0).permission ); - - auto wrap_exec_trace = trx_trace->action_traces.at(1); - BOOST_REQUIRE_EQUAL( 2, wrap_exec_trace.action_ordinal ); - BOOST_REQUIRE_EQUAL( 1, wrap_exec_trace.creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( 1, wrap_exec_trace.closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, wrap_exec_trace.receiver ); - BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, wrap_exec_trace.act.account ); - BOOST_REQUIRE_EQUAL( "exec"_n, wrap_exec_trace.act.name ); - BOOST_REQUIRE_EQUAL( 2, wrap_exec_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "alice"_n, wrap_exec_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, wrap_exec_trace.act.authorization.at(0).permission ); - BOOST_REQUIRE_EQUAL( "eosio.wrap"_n, wrap_exec_trace.act.authorization.at(1).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, wrap_exec_trace.act.authorization.at(1).permission ); - - auto reqauth_trace = trx_trace->action_traces.at(2); - BOOST_REQUIRE_EQUAL( 3, reqauth_trace.action_ordinal ); - BOOST_REQUIRE_EQUAL( 2, reqauth_trace.creator_action_ordinal ); - BOOST_REQUIRE_EQUAL( 2, reqauth_trace.closest_unnotified_ancestor_action_ordinal ); - BOOST_REQUIRE_EQUAL( config::system_account_name, reqauth_trace.receiver ); - BOOST_REQUIRE_EQUAL( config::system_account_name, reqauth_trace.act.account ); - BOOST_REQUIRE_EQUAL( "reqauth"_n, reqauth_trace.act.name ); - BOOST_REQUIRE_EQUAL( 1, reqauth_trace.act.authorization.size() ); - BOOST_REQUIRE_EQUAL( "bob"_n, reqauth_trace.act.authorization.at(0).actor ); - BOOST_REQUIRE_EQUAL( "active"_n, reqauth_trace.act.authorization.at(0).permission ); + + check_traces( trace, { + {{"receiver", "eosio.msig"_n}, {"act_name", "exec"_n}}, + {{"receiver", "eosio.wrap"_n}, {"act_name", "exec"_n}}, + {{"receiver", config::system_account_name}, {"act_name", "reqauth"_n}} + } ); } FC_LOG_AND_RETHROW() From 9be27351c6742653a73f2e32d87c760fbb05f170 Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Fri, 28 Oct 2022 16:26:53 -0400 Subject: [PATCH 28/96] triage new issues by adding label & assigning to project --- .github/workflows/label_new_issues.yaml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/workflows/label_new_issues.yaml diff --git a/.github/workflows/label_new_issues.yaml b/.github/workflows/label_new_issues.yaml new file mode 100644 index 00000000..88f0f03a --- /dev/null +++ b/.github/workflows/label_new_issues.yaml @@ -0,0 +1,18 @@ +name: Label New Issue + +on: + issues: + types: opened + +jobs: + label_new_issue: + uses: AntelopeIO/issue-project-labeler-workflow/.github/workflows/issue-project-labeler.yaml@v1 + with: + issue-id: ${{github.event.issue.node_id}} + label: triage + org-project: 'ENF Engineering' + project-field: Status=Todo + skip-if-existing-project: true + secrets: + token: ${{secrets.ENFCIBOT_REPO_AND_PROJECTS}} + From bf885d09b3def48fdbe04cb687c8354c1fe7dcc9 Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Fri, 28 Oct 2022 17:16:38 -0400 Subject: [PATCH 29/96] adjust leap-dev package regex to support both 3.1 & 3.2+ --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 79ad1f2c..5564cd70 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -52,7 +52,7 @@ jobs: with: owner: AntelopeIO repo: leap - file: 'leap-dev.*x86_64.deb' + file: 'leap-dev.*(x86_64|amd64).deb' ref: '${{steps.versions.outputs.leap-dev-ref}}' prereleases: true artifact-name: leap-dev-ubuntu20-amd64 From c42da5dc04b04f889af5297bab635711e6f5e6af Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Fri, 28 Oct 2022 18:19:26 -0400 Subject: [PATCH 30/96] place default targets in .json file --- .cicd/defaults.json | 10 +++++++ .github/workflows/build.yaml | 56 +++++++++++++++++++++++++----------- 2 files changed, 50 insertions(+), 16 deletions(-) create mode 100644 .cicd/defaults.json diff --git a/.cicd/defaults.json b/.cicd/defaults.json new file mode 100644 index 00000000..4759e709 --- /dev/null +++ b/.cicd/defaults.json @@ -0,0 +1,10 @@ +{ + "leap-dev":{ + "target":"*", + "prerelease":true + }, + "cdt":{ + "target":"*", + "prerelease":true + } +} diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 5564cd70..cbd502a6 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -9,11 +9,25 @@ on: workflow_dispatch: inputs: override-leap-dev: - description: 'Override leap-dev ref' + description: Override leap-dev target type: string + override-leap-dev-prerelease: + type: choice + description: Override leap-dev prelease + options: + - default + - true + - false override-cdt: - description: 'Override cdt ref' + description: 'Override cdt target' type: string + override-cdt-prerelease: + type: choice + description: Override cdt prelease + options: + - default + - true + - false defaults: run: @@ -26,35 +40,45 @@ jobs: steps: - name: Setup leap-dev & cdt versions id: versions + env: + GH_TOKEN: ${{secrets.GITHUB_TOKEN}} run: | - if [[ "${{inputs.override-leap-dev}}" == "" ]]; then - echo "::set-output name=leap-dev-ref::*" #default leap-dev ref - else - echo "::set-output name=leap-dev-ref::${{inputs.override-leap-dev}}" + DEFAULTS_JSON=$(curl -s -f $(gh api https://api.github.com/repos/${{github.repository}}/contents/.cicd/defaults.json?ref=${{github.sha}} --jq .download_url)) + echo leap-dev-target=$(echo "$DEFAULTS_JSON" | jq -r '."leap-dev".target') >> $GITHUB_OUTPUT + echo leap-dev-prerelease=$(echo "$DEFAULTS_JSON" | jq -r '."leap-dev".prerelease') >> $GITHUB_OUTPUT + echo cdt-target=$(echo "$DEFAULTS_JSON" | jq -r '.cdt.target') >> $GITHUB_OUTPUT + echo cdt-prerelease=$(echo "$DEFAULTS_JSON" | jq -r '.cdt.prerelease') >> $GITHUB_OUTPUT + + if [[ "${{inputs.override-leap-dev}}" != "" ]]; then + echo leap-dev-target=${{inputs.override-leap-dev}} >> $GITHUB_OUTPUT + fi + if [[ "${{inputs.override-leap-dev-prerelease}}" == +(true|false) ]]; then + echo leap-dev-prerelease=${{inputs.override-leap-dev-prerelease}} >> $GITHUB_OUTPUT + fi + if [[ "${{inputs.override-cdt}}" != "" ]]; then + echo cdt-target=${{inputs.override-cdt}} >> $GITHUB_OUTPUT fi - if [[ "${{inputs.override-cdt}}" == "" ]]; then - echo "::set-output name=cdt-ref::*" #defect cdt ref - else - echo "::set-output name=cdt-ref::${{inputs.override-cdt}}" + if [[ "${{inputs.override-cdt-prerelease}}" == +(true|false) ]]; then + echo cdt-prerelease=${{inputs.override-cdt-prerelease}} >> $GITHUB_OUTPUT fi - name: Download cdt - uses: AntelopeIO/asset-artifact-download-action@v1 + uses: AntelopeIO/asset-artifact-download-action@v2 with: owner: AntelopeIO repo: cdt file: 'cdt_.*amd64.deb' - ref: '${{steps.versions.outputs.cdt-ref}}' - prereleases: true + target: '${{steps.versions.outputs.cdt-target}}' + prereleases: ${{fromJSON(steps.versions.outputs.cdt-prerelease)}} artifact-name: cdt_ubuntu_package_amd64 token: ${{github.token}} - name: Download leap-dev - uses: AntelopeIO/asset-artifact-download-action@v1 + uses: AntelopeIO/asset-artifact-download-action@v2 with: owner: AntelopeIO repo: leap file: 'leap-dev.*(x86_64|amd64).deb' - ref: '${{steps.versions.outputs.leap-dev-ref}}' - prereleases: true + target: '${{steps.versions.outputs.leap-dev-target}}' + prereleases: ${{fromJSON(steps.versions.outputs.leap-dev-prerelease)}} artifact-name: leap-dev-ubuntu20-amd64 container-package: experimental-binaries token: ${{github.token}} From 8fb8c7045b91514adae197b8c164014064cb8ae7 Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Thu, 3 Nov 2022 10:55:24 -0400 Subject: [PATCH 31/96] add -S & -L to curl usage --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index cbd502a6..4148645e 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -43,7 +43,7 @@ jobs: env: GH_TOKEN: ${{secrets.GITHUB_TOKEN}} run: | - DEFAULTS_JSON=$(curl -s -f $(gh api https://api.github.com/repos/${{github.repository}}/contents/.cicd/defaults.json?ref=${{github.sha}} --jq .download_url)) + DEFAULTS_JSON=$(curl -sSfL $(gh api https://api.github.com/repos/${{github.repository}}/contents/.cicd/defaults.json?ref=${{github.sha}} --jq .download_url)) echo leap-dev-target=$(echo "$DEFAULTS_JSON" | jq -r '."leap-dev".target') >> $GITHUB_OUTPUT echo leap-dev-prerelease=$(echo "$DEFAULTS_JSON" | jq -r '."leap-dev".prerelease') >> $GITHUB_OUTPUT echo cdt-target=$(echo "$DEFAULTS_JSON" | jq -r '.cdt.target') >> $GITHUB_OUTPUT From 5448563ab9a2d4c3d004050ac59a066589465fef Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Thu, 3 Nov 2022 10:56:13 -0400 Subject: [PATCH 32/96] no need to cd to build/tests dir first --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 4148645e..1b211e8a 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -95,7 +95,7 @@ jobs: cmake -S src -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=On cmake --build build -- -j $(nproc) tar zcf build.tar.gz build - cd build/tests; ctest --output-on-failure -j $(nproc) + ctest --test-dir build/tests --output-on-failure -j $(nproc) - name: Upload builddir uses: actions/upload-artifact@v3 with: From 90c07a88ef188f004a545a9d4599d2317e1be460 Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Fri, 4 Nov 2022 17:43:44 -0400 Subject: [PATCH 33/96] use 3.x versions of leap & cdt --- .cicd/defaults.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.cicd/defaults.json b/.cicd/defaults.json index 4759e709..ff3a3dbc 100644 --- a/.cicd/defaults.json +++ b/.cicd/defaults.json @@ -1,10 +1,10 @@ { "leap-dev":{ - "target":"*", - "prerelease":true + "target":"3", + "prerelease":false }, "cdt":{ - "target":"*", - "prerelease":true + "target":"3", + "prerelease":false } } From 40a2cfc9d4cc4de09ae792b444b259a2caa08baf Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Wed, 23 Nov 2022 13:16:29 -0500 Subject: [PATCH 34/96] remove some duplicate cmake --- CMakeLists.txt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b0bb4207..a6a9f5b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,13 +46,6 @@ elseif(UNIX) endif() set(SECP256K1_ROOT "/usr/local") -if(APPLE) - set(OPENSSL_ROOT "/usr/local/opt/openssl") -elseif(UNIX) - set(OPENSSL_ROOT "/usr/include/openssl") -endif() -set(SECP256K1_ROOT "/usr/local") - option(BUILD_TESTS "Build unit tests" OFF) if(BUILD_TESTS) From c3c77913edea5485c1945d0ecf46d77dd7f9401e Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Wed, 23 Nov 2022 13:18:19 -0500 Subject: [PATCH 35/96] add cmake option to enable/disable Leap eosiotester version check --- CMakeLists.txt | 3 +++ tests/CMakeLists.txt | 36 +++++++++++++++++++----------------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a6a9f5b9..bd5c9d4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,9 @@ option(SYSTEM_CONFIGURABLE_WASM_LIMITS option(SYSTEM_BLOCKCHAIN_PARAMETERS "Enables use of the host functions activated by the BLOCKCHAIN_PARAMETERS protocol feature" ON) +option(SYSTEM_ENABLE_LEAP_VERSION_CHECK + "Enables a configure-time check that the version of Leap's tester library is compatible with this project's unit tests" ON) + ExternalProject_Add( contracts_project SOURCE_DIR ${CMAKE_SOURCE_DIR}/contracts diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index aa8e3e04..f21e9118 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -4,25 +4,27 @@ set(EOSIO_VERSION_MIN "3.1") set(EOSIO_VERSION_SOFT_MAX "3.1") # set(EOSIO_VERSION_HARD_MAX "") -find_package(leap) +find_package(leap REQUIRED) # Check the version of Leap -set(VERSION_MATCH_ERROR_MSG "") -eosio_check_version(VERSION_OUTPUT "${EOSIO_VERSION}" "${EOSIO_VERSION_MIN}" "${EOSIO_VERSION_SOFT_MAX}" - "${EOSIO_VERSION_HARD_MAX}" VERSION_MATCH_ERROR_MSG) -if(VERSION_OUTPUT STREQUAL "MATCH") - message(STATUS "Using Leap version ${EOSIO_VERSION}") -elseif(VERSION_OUTPUT STREQUAL "WARN") - message( - WARNING - "Using Leap version ${EOSIO_VERSION} even though it exceeds the maximum supported version of ${EOSIO_VERSION_SOFT_MAX}; continuing with configuration, however build may fail.\nIt is recommended to use Leap version ${EOSIO_VERSION_SOFT_MAX}.x" - ) -else() # INVALID OR MISMATCH - message( - FATAL_ERROR - "Found Leap version ${EOSIO_VERSION} but it does not satisfy version requirements: ${VERSION_MATCH_ERROR_MSG}\nPlease use Leap version ${EOSIO_VERSION_SOFT_MAX}.x" - ) -endif(VERSION_OUTPUT STREQUAL "MATCH") +if(SYSTEM_ENABLE_LEAP_VERSION_CHECK) + set(VERSION_MATCH_ERROR_MSG "") + eosio_check_version(VERSION_OUTPUT "${EOSIO_VERSION}" "${EOSIO_VERSION_MIN}" "${EOSIO_VERSION_SOFT_MAX}" + "${EOSIO_VERSION_HARD_MAX}" VERSION_MATCH_ERROR_MSG) + if(VERSION_OUTPUT STREQUAL "MATCH") + message(STATUS "Using Leap version ${EOSIO_VERSION}") + elseif(VERSION_OUTPUT STREQUAL "WARN") + message( + WARNING + "Using Leap version ${EOSIO_VERSION} even though it exceeds the maximum supported version of ${EOSIO_VERSION_SOFT_MAX}; continuing with configuration, however build may fail.\nIt is recommended to use Leap version ${EOSIO_VERSION_SOFT_MAX}.x" + ) + else() # INVALID OR MISMATCH + message( + FATAL_ERROR + "Found Leap version ${EOSIO_VERSION} but it does not satisfy version requirements: ${VERSION_MATCH_ERROR_MSG}\nPlease use Leap version ${EOSIO_VERSION_SOFT_MAX}.x" + ) + endif() +endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/contracts.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/contracts.hpp) From 45d3a7ae5ca4b4d1a32f75046c588366d4a1c850 Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Wed, 23 Nov 2022 13:19:07 -0500 Subject: [PATCH 36/96] set SYSTEM_ENABLE_LEAP_VERSION_CHECK off in CI --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 1b211e8a..8e12bada 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -92,7 +92,7 @@ jobs: path: src - name: Build & Test run: | - cmake -S src -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=On + cmake -S src -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=On -DSYSTEM_ENABLE_LEAP_VERSION_CHECK=Off cmake --build build -- -j $(nproc) tar zcf build.tar.gz build ctest --test-dir build/tests --output-on-failure -j $(nproc) From b3b7340f419e39e46628199c3ab854c8fbc460b7 Mon Sep 17 00:00:00 2001 From: Luis Date: Wed, 23 Nov 2022 14:06:25 -0500 Subject: [PATCH 37/96] replace eosio.contracts with eos-system-contracts :doc --- CMakeLists.txt | 2 +- CONTRIBUTING.md | 22 +++++++++---------- docs.json | 2 +- docs/01_key-concepts/01_system.md | 2 +- docs/04_guides/02_how-to-buy-ram.md | 2 +- docs/04_guides/03_how-to-stake.md | 2 +- docs/04_guides/04_how-to-vote.md | 2 +- ...ow-to-create-issue-and-transfer-a-token.md | 4 ++-- docs/index.md | 2 +- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 81f6f130..288cfa1e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ else() set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") endif() -message(STATUS "Building eosio.contracts v${VERSION_FULL}") +message(STATUS "Building eos-system-contracts v${VERSION_FULL}") include(ExternalProject) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b3413262..fcfe1526 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,4 @@ -# Contributing to eosio.contracts +# Contributing to eos-system-contracts Interested in contributing? That's awesome! Here are some guidelines to get started quickly and easily: @@ -6,7 +6,7 @@ Interested in contributing? That's awesome! Here are some guidelines to get star - [Bug Reports](#bug-reports) - [Feature Requests](#feature-requests) - [Change Requests](#change-requests) -- [Working on eosio.contracts](#working-on-eosiocontracts) +- [Working on eos-system-contracts](#working-on-eos-system-contracts) - [Feature Branches](#feature-branches) - [Submitting Pull Requests](#submitting-pull-requests) - [Testing and Quality Assurance](#testing-and-quality-assurance) @@ -16,7 +16,7 @@ Interested in contributing? That's awesome! Here are some guidelines to get star ## Reporting An Issue -If you're about to raise an issue because you think you've found a problem with eosio.contracts, or you'd like to make a request for a new feature in the codebase, or any other reason… please read this first. +If you're about to raise an issue because you think you've found a problem with eos-system-contracts, or you'd like to make a request for a new feature in the codebase, or any other reason… please read this first. The GitHub issue tracker is the preferred channel for [bug reports](#bug-reports), [feature requests](#feature-requests), and [submitting pull requests](#submitting-pull-requests), but please respect the following restrictions: @@ -34,12 +34,12 @@ Guidelines for bug reports: reported. 1. **Check if the issue has been fixed** — look for [closed issues in the - current milestone](https://github.com/EOSIO/eosio.contracts/issues?q=is%3Aissue+is%3Aclosed) or try to reproduce it + current milestone](https://github.com/eosnetworkfoundation/eos-system-contracts/issues?q=is%3Aissue+is%3Aclosed) or try to reproduce it using the latest `develop` branch. A good bug report shouldn't leave others needing to chase you up for more information. Be sure to include the details of your environment and relevant tests that demonstrate the failure. -[Report a bug](https://github.com/EOSIO/eosio.contracts/issues/new?title=Bug%3A) +[Report a bug](https://github.com/eosnetworkfoundation/eos-system-contracts/issues/new?title=Bug%3A) ### Feature Requests @@ -51,15 +51,15 @@ Feature requests are welcome. Before you submit one be sure to have: ### Change Requests -Change requests cover both architectural and functional changes to how eosio.contracts works. If you have an idea for a new or different dependency, a refactor, or an improvement to a feature, etc - please be sure to: +Change requests cover both architectural and functional changes to how eos-system-contracts works. If you have an idea for a new or different dependency, a refactor, or an improvement to a feature, etc - please be sure to: 1. **Use the GitHub search** and check someone else didn't get there first 1. Take a moment to think about the best way to make a case for, and explain what you're thinking. Are you sure this shouldn't really be a [bug report](#bug-reports) or a [feature request](#feature-requests)? Is it really one idea or is it many? What's the context? What problem are you solving? Why is what you are suggesting better than what's already there? -## Working on eosio.contracts +## Working on eos-system-contracts -Code contributions are welcome and encouraged! If you are looking for a good place to start, check out the [good first issue](https://github.com/EOSIO/eosio.contracts/labels/good%20first%20issue) label in GitHub issues. +Code contributions are welcome and encouraged! If you are looking for a good place to start, check out the [good first issue](https://github.com/eosnetworkfoundation/eos-system-contracts/labels/good%20first%20issue) label in GitHub issues. Also, please follow these guidelines when submitting code: @@ -67,8 +67,8 @@ Also, please follow these guidelines when submitting code: To get it out of the way: -- **[develop](https://github.com/EOSIO/eosio.contracts/tree/develop)** is the development branch. All work on the next release happens here so you should generally branch off `develop`. Do **NOT** use this branch for a production site. -- **[master](https://github.com/EOSIO/eosio.contracts/tree/master)** contains the latest release of eosio.contracts. This branch may be used in production. Do **NOT** use this branch to work on eosio.contracts's source. +- **[develop](https://github.com/eosnetworkfoundation/eos-system-contracts/tree/develop)** is the development branch. All work on the next release happens here so you should generally branch off `develop`. Do **NOT** use this branch for a production site. +- **[master](https://github.com/eosnetworkfoundation/eos-system-contracts/tree/master)** contains the latest release of eos-system-contracts. This branch may be used in production. Do **NOT** use this branch to work on eos-system-contracts's source. ### Submitting Pull Requests @@ -78,7 +78,7 @@ Pull requests are awesome. If you're looking to raise a PR for something which d Never underestimate just how useful quality assurance is. If you're looking to get involved with the code base and don't know where to start, checking out and testing a pull request is one of the most useful things you could do. -Essentially, [check out the latest develop branch](#working-on-eosio.contracts), take it for a spin, and if you find anything odd, please follow the [bug report guidelines](#bug-reports) and let us know! +Essentially, [check out the latest develop branch](#working-on-eos-system-contracts), take it for a spin, and if you find anything odd, please follow the [bug report guidelines](#bug-reports) and let us know! ## Conduct diff --git a/docs.json b/docs.json index 2d4e43af..9f4e4940 100644 --- a/docs.json +++ b/docs.json @@ -1,5 +1,5 @@ { - "name": "eosio.contracts", + "name": "eos-system-contracts", "generators": [ { "name": "collate_markdown", diff --git a/docs/01_key-concepts/01_system.md b/docs/01_key-concepts/01_system.md index fb8352ac..35a3caa4 100644 --- a/docs/01_key-concepts/01_system.md +++ b/docs/01_key-concepts/01_system.md @@ -2,7 +2,7 @@ content_title: System contracts, system accounts, privileged accounts --- -At the genesis of an Antelope-based blockchain, there is only one account present, `eosio` account, which is the main `system account`. There are other `system account`s, created by `eosio` account, which control specific actions of the `system contract`s [mentioned in previous section](/index.md#system-contracts-defined-in-eosio.contracts). __Note__ the terms `system contract` and `system account`. `Privileged accounts` are accounts which can execute a transaction while skipping the standard authorization check. To ensure that this is not a security hole, the permission authority over these accounts is granted to `eosio.prods` system account. +At the genesis of an Antelope-based blockchain, there is only one account present, `eosio` account, which is the main `system account`. There are other `system account`s, created by `eosio` account, which control specific actions of the `system contract`s [mentioned in previous section](/index.md#system-contracts-defined-in-eos-system-contracts). __Note__ the terms `system contract` and `system account`. `Privileged accounts` are accounts which can execute a transaction while skipping the standard authorization check. To ensure that this is not a security hole, the permission authority over these accounts is granted to `eosio.prods` system account. As you just learned the relation between a `system account` and a `system contract`, it is also important to remember that not all system accounts contain a system contract, but each system account has important roles in the blockchain functionality, as follows: diff --git a/docs/04_guides/02_how-to-buy-ram.md b/docs/04_guides/02_how-to-buy-ram.md index dee6776e..257e9fe9 100644 --- a/docs/04_guides/02_how-to-buy-ram.md +++ b/docs/04_guides/02_how-to-buy-ram.md @@ -11,7 +11,7 @@ Setup an account that require multiple signatures for signing a transaction * You have an account -* Ensure the reference system contracts from `eosio.contracts` repository is deployed and used to manage system resources +* Ensure the reference system contracts from `eos-system-contracts` repository is deployed and used to manage system resources * You have sufficient token allocated to your account diff --git a/docs/04_guides/03_how-to-stake.md b/docs/04_guides/03_how-to-stake.md index 0413a01a..f5e207cf 100644 --- a/docs/04_guides/03_how-to-stake.md +++ b/docs/04_guides/03_how-to-stake.md @@ -11,7 +11,7 @@ Stake resource for your account * Install the currently supported version of cleos -* Ensure the reference system contracts from `eosio.contracts` repository is deployed and used to manage system resources +* Ensure the reference system contracts from `eos-system-contracts` repository is deployed and used to manage system resources * Understand the following: * What is an account diff --git a/docs/04_guides/04_how-to-vote.md b/docs/04_guides/04_how-to-vote.md index ee9e1f96..31f5a6a6 100644 --- a/docs/04_guides/04_how-to-vote.md +++ b/docs/04_guides/04_how-to-vote.md @@ -11,7 +11,7 @@ Vote for a block producer * Install the current supported version of cleos -* Ensure the reference system contracts from `eosio.contracts` repository is deployed and used to manage system resources +* Ensure the reference system contracts from `eos-system-contracts` repository is deployed and used to manage system resources * Understand the following: * What is a block producer diff --git a/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md b/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md index 7ced242f..c228b23b 100644 --- a/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md +++ b/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md @@ -17,7 +17,7 @@ git clone https://github.com/eosnetworkfoundation/eos-system-contracts --branch ``` ```sh -cd eosio.contracts/contracts/eosio.token +cd eos-system-contracts/contracts/eosio.token ``` ## Step 2: Create Account for Contract @@ -37,7 +37,7 @@ eosio-cpp -I include -o eosio.token.wasm src/eosio.token.cpp --abigen ## Step 4: Deploy the Token Contract ```shell -cleos set contract eosio.token CONTRACTS_DIR/eosio.contracts/contracts/eosio.token --abi eosio.token.abi -p eosio.token@active +cleos set contract eosio.token CONTRACTS_DIR/eos-system-contracts/contracts/eosio.token --abi eosio.token.abi -p eosio.token@active ``` Result should look similar to the one below: diff --git a/docs/index.md b/docs/index.md index 60875409..45e580e7 100644 --- a/docs/index.md +++ b/docs/index.md @@ -4,7 +4,7 @@ content_title: About System Contracts The Antelope blockchain framework is unique in that the features and characteristics of the blockchain built on it are flexible, that is, they can be changed, or modified completely to suit each business case requirement. Core blockchain features such as consensus, fee schedules, account creation and modification, token economics, block producer registration, voting, multi-sig, etc., are implemented inside smart contracts which are deployed on the blockchain built on the Antelope framework. -## System contracts defined in eosio.contracts +## System contracts defined in eos-system-contracts The `eos-system-contracts` repository contains the system contracts encapsulating the base functionality for the EOS blockchain. From e1ee9327b088f2e85a2f56cbeb075dda21633471 Mon Sep 17 00:00:00 2001 From: Luis Date: Wed, 23 Nov 2022 14:11:12 -0500 Subject: [PATCH 38/96] clean up and curate contributing.md file :doc --- CONTRIBUTING.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fcfe1526..252f1015 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -35,7 +35,7 @@ Guidelines for bug reports: 1. **Check if the issue has been fixed** — look for [closed issues in the current milestone](https://github.com/eosnetworkfoundation/eos-system-contracts/issues?q=is%3Aissue+is%3Aclosed) or try to reproduce it - using the latest `develop` branch. + using the latest `main` branch. A good bug report shouldn't leave others needing to chase you up for more information. Be sure to include the details of your environment and relevant tests that demonstrate the failure. @@ -67,8 +67,8 @@ Also, please follow these guidelines when submitting code: To get it out of the way: -- **[develop](https://github.com/eosnetworkfoundation/eos-system-contracts/tree/develop)** is the development branch. All work on the next release happens here so you should generally branch off `develop`. Do **NOT** use this branch for a production site. -- **[master](https://github.com/eosnetworkfoundation/eos-system-contracts/tree/master)** contains the latest release of eos-system-contracts. This branch may be used in production. Do **NOT** use this branch to work on eos-system-contracts's source. +- **[main](https://github.com/eosnetworkfoundation/eos-system-contracts/tree/main)** is the development branch. All work on the next release happens here so you should generally branch off `main`. Do **NOT** use this branch for a production site. +- **release/** branches contain stable releases of eos-system-contracts. Some of these branches may be obsolete, a prerelease (release candidate), or designated as stable and ready for use in production. Generally do **NOT** use these branches to work on eos-system-contracts' source unless you are working on a defect or change that would apply to a current stable release or release candidate. If in doubt, branch off of `main` and an eos-system-contracts maintainer will chime in if you should switch to a release branch. ### Submitting Pull Requests @@ -78,7 +78,7 @@ Pull requests are awesome. If you're looking to raise a PR for something which d Never underestimate just how useful quality assurance is. If you're looking to get involved with the code base and don't know where to start, checking out and testing a pull request is one of the most useful things you could do. -Essentially, [check out the latest develop branch](#working-on-eos-system-contracts), take it for a spin, and if you find anything odd, please follow the [bug report guidelines](#bug-reports) and let us know! +Essentially, [check out the main branch](#working-on-eos-system-contracts), take it for a spin, and if you find anything odd, please follow the [bug report guidelines](#bug-reports) and let us know! ## Conduct From 47099915d01ed1028e9e3d4edde38fd882449002 Mon Sep 17 00:00:00 2001 From: Luis Date: Wed, 23 Nov 2022 14:13:19 -0500 Subject: [PATCH 39/96] remove unused docs.json file :doc --- docs.json | 40 ---------------------------------------- 1 file changed, 40 deletions(-) delete mode 100644 docs.json diff --git a/docs.json b/docs.json deleted file mode 100644 index 9f4e4940..00000000 --- a/docs.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "name": "eos-system-contracts", - "generators": [ - { - "name": "collate_markdown", - "options": { - "docs_dir": "docs" - } - }, - { - "name": "mdjavadoc", - "options": { - "source_dirs": [ - "contracts/eosio.token/include/eosio.token/", - "contracts/eosio.wrap/include/eosio.wrap/", - "contracts/eosio.bios/include/eosio.bios/", - "contracts/eosio.system/include/eosio.system/", - "contracts/eosio.msig/include/eosio.msig/" - ], - "output_dir": "action-reference" - } - } - ], - "skip_default_filters": true, - "filters": [ - { - "name": "sanitize", - "options": { - "exclude": ["action-reference"] - } - }, - { - "name": "capitalize", - "options": { - "mode": "all", - "exclude": ["action-reference"] - } - } - ] -} From 4556fc119f8f54abb430c6aff202d5b26061d50a Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Fri, 2 Dec 2022 16:38:52 -0500 Subject: [PATCH 40/96] some very minor eosio.token test cleanups --- tests/eosio.token_tests.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/eosio.token_tests.cpp b/tests/eosio.token_tests.cpp index 68e7d554..6db45ac4 100644 --- a/tests/eosio.token_tests.cpp +++ b/tests/eosio.token_tests.cpp @@ -114,7 +114,7 @@ class eosio_token_tester : public tester { const string& symbolname ) { return push_action( owner, "close"_n, mvo() ( "owner", owner ) - ( "symbol", "0,CERO" ) + ( "symbol", symbolname ) ); } @@ -324,15 +324,11 @@ BOOST_FIXTURE_TEST_CASE( transfer_tests, eosio_token_tester ) try { alice_balance = get_account("alice"_n, "0,CERO"); REQUIRE_MATCHING_OBJECT( alice_balance, mvo() ("balance", "700 CERO") - ("frozen", 0) - ("whitelist", 1) ); auto bob_balance = get_account("bob"_n, "0,CERO"); REQUIRE_MATCHING_OBJECT( bob_balance, mvo() ("balance", "300 CERO") - ("frozen", 0) - ("whitelist", 1) ); BOOST_REQUIRE_EQUAL( wasm_assert_msg( "overdrawn balance" ), From ae7666f3707b9f1f29bdda7b4aad761bed278ef4 Mon Sep 17 00:00:00 2001 From: iamveritas Date: Sun, 29 Jan 2023 00:24:20 +0200 Subject: [PATCH 41/96] get rid of the staking of CPU and NET concept, introduce PowerUp --- docs/01_key-concepts/01_system.md | 2 +- docs/01_key-concepts/03_cpu.md | 6 +- docs/01_key-concepts/04_net.md | 6 +- docs/01_key-concepts/05_stake.md | 49 ---------------- .../05_system_resource_allocation.md | 28 +++++++++ docs/01_key-concepts/06_vote.md | 6 +- docs/01_key-concepts/07_powerup_model.md | 7 +++ docs/04_guides/02_how-to-buy-ram.md | 12 ++-- docs/04_guides/03_how-to-stake.md | 20 +++---- docs/04_guides/04_how-to-vote.md | 12 ++-- ...08_configure-use-powerup-resource-model.md | 58 ++++++++++++------- docs/index.md | 5 +- 12 files changed, 107 insertions(+), 104 deletions(-) delete mode 100644 docs/01_key-concepts/05_stake.md create mode 100644 docs/01_key-concepts/05_system_resource_allocation.md create mode 100644 docs/01_key-concepts/07_powerup_model.md diff --git a/docs/01_key-concepts/01_system.md b/docs/01_key-concepts/01_system.md index 35a3caa4..30a9f1f3 100644 --- a/docs/01_key-concepts/01_system.md +++ b/docs/01_key-concepts/01_system.md @@ -18,6 +18,6 @@ As you just learned the relation between a `system account` and a `system contra |eosio.ram|No|No|The account that keeps track of the SYS balances based on users actions of buying or selling RAM.| |eosio.ramfee|No|No|The account that keeps track of the fees collected from users RAM trading actions: 0.5% from the value of each trade goes into this account.| |eosio.saving|No|No|The account which holds the 4% of network inflation.| -|eosio.stake|No|No|The account that keeps track of all SYS tokens which have been staked for NET or CPU bandwidth.| +|eosio.stake|No|No|The account that keeps track of all SYS tokens which have been staked for voting.| |eosio.vpay|No|No|The account that pays the block producers accordingly with the votes won. It assigns 0.75% of inflation based on the amount of votes a block producer won in the last 24 hours.| |eosio.rex|No|No|The account that keeps track of fees and balances resulted from REX related actions execution.| diff --git a/docs/01_key-concepts/03_cpu.md b/docs/01_key-concepts/03_cpu.md index f094beb7..add4b149 100644 --- a/docs/01_key-concepts/03_cpu.md +++ b/docs/01_key-concepts/03_cpu.md @@ -2,8 +2,6 @@ content_title: CPU as system resource --- -The system resource CPU provides processing power to blockchain accounts. The amount of CPU an account has is measured in microseconds and it is referred to as `cpu bandwidth` on the `cleos get account` command output. The `cpu bandwidth` represents the amount of processing time an account has at its disposal when actions sent to its contract are executed by the blockchain. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient CPU must be staked in order for transactions to complete. +The system resource CPU provides processing power to blockchain accounts. The amount of CPU an account has is measured in microseconds and it is referred to as `cpu bandwidth` on the `dune -- cleos get account` command output. The `cpu bandwidth` represents the amount of processing time an account has at its disposal when actions sent to its contract are executed by the blockchain. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient CPU must be allocated to the account in order for transactions to complete. -For more details about staking on Antelope-based blockchains refer to the following: -* [Staking Mechanism](https://developers.eos.io/docs/latest/overview/technical_features#staking-mechanism). -* [Staking on Antelope-based blockchains](05_stake.md) +For more details about resource allocation on the EOS blockchain refer to the [Resource Allocation](./05_system_resource_allocation.md) documentation. diff --git a/docs/01_key-concepts/04_net.md b/docs/01_key-concepts/04_net.md index c7a6e79d..5ab148ed 100644 --- a/docs/01_key-concepts/04_net.md +++ b/docs/01_key-concepts/04_net.md @@ -2,8 +2,6 @@ content_title: NET as system resource --- -NET, as CPU and RAM, is a very important system resource in Antelope-based blockchains. NET is measured by the byte size of the transactions saved in the blockchain database and it is referred to as `net bandwidth` on the cleos get account command result. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient NET must be staked in order for transactions to complete. +NET, as CPU and RAM, is a very important system resource in the EOS blockchain. NET is measured by the byte size of the transactions saved in the blockchain database and it is referred to as `net bandwidth` on the `dune -- cleos get account` command output. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient NET must be allocated to the account in order for transactions to complete. -For more details about staking on Antelope-based blockchains refer to the following: -* [Staking Mechanism](https://developers.eos.io/docs/latest/overview/technical_features#staking-mechanism). -* [Staking on Antelope-based blockchains](05_stake.md) +For more details about resource allocation on the EOS blockchain refer to the [Resource Allocation](./05_system_resource_allocation.md) documentation. diff --git a/docs/01_key-concepts/05_stake.md b/docs/01_key-concepts/05_stake.md deleted file mode 100644 index c7bffe21..00000000 --- a/docs/01_key-concepts/05_stake.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -content_title: Staking on Antelope-based blockchains ---- - -## System Resources - -Antelope-based blockchains work with three system resources: - -* [RAM](02_ram.md) -* [CPU](03_cpu.md) -* [NET](04_net.md) - -## How To Allocate System Resources - -Antelope-based blockchain accounts need sufficient system resources, RAM, CPU and NET, to interact with the smart contracts deployed on the blockchain. - -### Stake NET and CPU - -The CPU and NET system resources are allocated by the account owner via the staking mechanism. Refer to the [cleos manual](https://docs.eosnetwork.com/leap/latest/cleos/how-to-guides/how-to-stake-resource) on how to do it via the command line interface. - -You will also find that staking/unstaking is at times referred to as delegating/undelegating. The economics of staking is also to provably commit to a promise that you will hold the staked tokens, either for NET or CPU, for a pre-established period of time, in spite of inflation caused by minting new tokens in order to reward BPs for their services every 24 hours. - -When you stake tokens for CPU and NET, you gain access to system resources proportional to the total amount of tokens staked by all other users for the same system resource at the same time. This means you can execute transactions at no cost but in the limits of the staked tokens. The staked tokens guarantee the proportional amount of resources regardless of any variations in the free market. - -If an account consumes all its allocated CPU and NET resources, it has two options: - -* It can wait for the blockchain to replenish the consumed resources. You can read more details below about the [system resources replenish algorithm].(05_stake.md#System-Resources-Replenish-Algorithm). -* It can allocate more resources through the staking mechanism. - -When an account uses the allocated resources, the amount that can be used in one transaction is limited by predefine [maximum CPU](https://docs.eosnetwork.com/cdt/latest/reference/Classes/structeosio_1_1blockchain__parameters#variable-max-transaction-cpu-usage), [minimum CPU](https://docs.eosnetwork.com/cdt/latest/reference/Classes/structeosio_1_1blockchain__parameters#variable-min-transaction-cpu-usage), and [maximum NET](https://docs.eosnetwork.com/cdt/latest/reference/Classes/structeosio_1_1blockchain__parameters#variable-max-transaction-net-usage) limits. Transactions executed by the blockchain contain one or more actions, and each transaction must consume an amount of CPU and NET which is in the limits defined by the aforementioned blockchain settings. - -#### System Resources Replenish Algorithm - -Antelope-based blockchains replenish automatically the consumed CPU and NET system resources. Before a transaction is executed, by the blockchain, it first calculates how many resources the account executing the transaction can consume. The calculation uses an exponential moving average with linear extrapolation when data is missing, and it multiplies the currently accumulated average by `(number of blocks in the window - number of blocks since last update) / (number of blocks in the window)`. The window is set as 24 hours window. - -This formula has the following outcomes: - -* If an account waited `number of blocks in the window` without executing any transaction it resets to zero usage. - -* If an account issues a transaction with every block it would always be `(number of blocks in the window - 1) / (number of blocks in the window)`, a very small value, very close to zero. Mathematically it _never_ reaches zero but the EOS implementation truncates off the tiny numbers to zero. - -* The accounts that execute transactions more often than the ones that execute less transactions, replenish their resources slower than the later. In other words, the more transactions an account executes the slower the replenish of resources. - -[[info]] -| The blockchain calculates and updates the remaining resources, for the accounts which execute transactions, with each block, before each transaction is executed. As time passes, as explained above, the consumed system resources are gradually replenished, and the available system resources increase, or decrease, depending on how many transactions an account executes. After waiting for some time, if you check the available resources balance and expect to see it increased, because your account did not executed any transactions, you will not see it updated. That is because it gets updated only before a transaction is executed. Therefore in order to see the available resources you have to execute a transaction. This is counter intuitive and the next versions will improve this aspect. - -### Buy RAM - -The RAM resource must be bought using the system token. Refer to the [cleos manual](https://docs.eosnetwork.com/leap/latest/cleos/how-to-guides/how-to-buy-ram) to learn how to do it via the command line interface. When an account consumes all its allocated RAM can not store any additional information on the blockchain database until it frees some of the occupied RAM or more RAM is allocated to the account through the RAM buying process. diff --git a/docs/01_key-concepts/05_system_resource_allocation.md b/docs/01_key-concepts/05_system_resource_allocation.md new file mode 100644 index 00000000..1a07b350 --- /dev/null +++ b/docs/01_key-concepts/05_system_resource_allocation.md @@ -0,0 +1,28 @@ +--- +content_title: System Resource Allocation +--- + +## System Resources + +Antelope-based blockchains work with three system resources: + +* [RAM](02_ram.md) +* [CPU](03_cpu.md) +* [NET](04_net.md) + +## How To Allocate System Resources + +The EOS accounts need sufficient system resources, RAM, CPU and NET, to interact with the smart contracts deployed on the blockchain. + +### Rent NET and CPU + +The CPU and NET system resources are rented by the account owner through the [PowerUp model](./07_powerup_model.md). + +When an account uses the rented resources, the amount that can be used in one transaction is limited by predefine [maximum CPU](https://docs.eosnetwork.com/cdt/latest/reference/Classes/structeosio_1_1blockchain__parameters#variable-max-transaction-cpu-usage), [minimum CPU](https://docs.eosnetwork.com/cdt/latest/reference/Classes/structeosio_1_1blockchain__parameters#variable-min-transaction-cpu-usage), and [maximum NET](https://docs.eosnetwork.com/cdt/latest/reference/Classes/structeosio_1_1blockchain__parameters#variable-max-transaction-net-usage) limits. Transactions executed by the blockchain contain one or more actions, and each transaction must consume an amount of CPU and NET which is in the limits defined by the aforementioned blockchain settings. + +[[info]] +| The blockchain calculates and updates the remaining resources, for the accounts which execute transactions, with each block, before each transaction is executed. + +### Buy RAM + +The RAM resource must be bought using the system token. Refer to the [cleos manual](https://docs.eosnetwork.com/leap/latest/cleos/how-to-guides/how-to-buy-ram) to learn how to do it via the command line interface. When an account consumes all its allocated RAM can not store any additional information on the blockchain database until it frees some of the occupied RAM or more RAM is allocated to the account through the RAM buying process. diff --git a/docs/01_key-concepts/06_vote.md b/docs/01_key-concepts/06_vote.md index c2344c3c..aa271e38 100644 --- a/docs/01_key-concepts/06_vote.md +++ b/docs/01_key-concepts/06_vote.md @@ -1,5 +1,7 @@ --- -content_title: Voting on Antelope-based blockchains +content_title: Voting on EOS blockchain --- -In an Antelope-based network the blockchain is kept alive by nodes which are interconnected between each other, communicating with each other via peer to peer protocols. Some of these nodes are elected, via a voting process, by the token holders to be producer nodes. They produce blocks, validate them and reach consensus on what transactions are allowed in each block, their order, and what blocks are finalized and stored forever in the blockchain. This way the governance, the mechanism by which collective decisions are made, of the blockchain is achieved through the 21 active block producers which are appointed by token holders' votes. It's the 21 active block producers which continuously create the blockchain by creating blocks, and securing them by validating them, and reaching consensus. Consensus is reached when 2/3+1 active block producers agree on validity of a block, that is all transactions contained in it and their order. The 21 producers is the default value however it can be configured to be higher or smaller to meet each business case requirements. +The EOS blockchain is kept alive by nodes which are interconnected between each other, communicating with each other via peer to peer protocols. Some of these nodes are elected, via a voting process, by the token holders to be producer nodes. They produce blocks, validate them and reach consensus on what transactions are allowed in each block, their order, and what blocks are finalized and stored forever in the blockchain state. This way the governance, the mechanism by which collective decisions are made, of the blockchain is achieved through the 21 active block producers which are appointed by token holders' votes. It is the 21 active block producers which continuously advancing the blockchain by creating blocks, and securing them by validating them, and reaching consensus. Consensus is reached when 2/3+1 active block producers agree on validity of a block, that is all transactions contained in it and their order. The 21 producers is the default value however it can be configured to be higher or smaller to meet each business case requirements. + +The 21 block producers are elected through the voting process. Each EOS token holder that wants to vote for one or up to 30 block producers must stake their tokens. The more tokens are stake the more voting power. The voting power of one account is proportional with the amount of tokens staked by that account versus the total amount of tokens staked by whole accounts that stake their tokens. \ No newline at end of file diff --git a/docs/01_key-concepts/07_powerup_model.md b/docs/01_key-concepts/07_powerup_model.md new file mode 100644 index 00000000..36f3b895 --- /dev/null +++ b/docs/01_key-concepts/07_powerup_model.md @@ -0,0 +1,7 @@ +--- +content_title: PowerUp Model +--- + +## What Is PowerUp Model + +## How To Use The PowerUp Model diff --git a/docs/04_guides/02_how-to-buy-ram.md b/docs/04_guides/02_how-to-buy-ram.md index 257e9fe9..02267e89 100644 --- a/docs/04_guides/02_how-to-buy-ram.md +++ b/docs/04_guides/02_how-to-buy-ram.md @@ -3,11 +3,11 @@ content_title: How to buy RAM link_text: How to buy RAM --- -# Goal +## Goal Setup an account that require multiple signatures for signing a transaction -# Before you begin +## Before you begin * You have an account @@ -15,14 +15,14 @@ Setup an account that require multiple signatures for signing a transaction * You have sufficient token allocated to your account -* Install the currently supported version of cleos +* Install the currently supported version of dune * Unlock your wallet -# Steps +## Steps -Buys RAM in value of 0.1 SYS tokens for account `alice`: +Buys RAM in value of 10 SYS tokens for account `alice`: ```shell -cleos system buyram alice alice "0.1 SYS" -p alice@active +dune -- cleos system buyram alice alice "10 SYS" -p alice@active ``` \ No newline at end of file diff --git a/docs/04_guides/03_how-to-stake.md b/docs/04_guides/03_how-to-stake.md index f5e207cf..1d19b800 100644 --- a/docs/04_guides/03_how-to-stake.md +++ b/docs/04_guides/03_how-to-stake.md @@ -3,13 +3,13 @@ content_title: How to stake link_text: How to stake --- -# Goal +## Goal -Stake resource for your account +Stake resources for your account to participate in the on-chain voting and governance. -# Before you begin +## Before you begin -* Install the currently supported version of cleos +* Install the currently supported version of dune * Ensure the reference system contracts from `eos-system-contracts` repository is deployed and used to manage system resources @@ -18,16 +18,16 @@ Stake resource for your account * What is network bandwidth * What is CPU bandwidth -# Steps +## Steps -Stake 0.01 SYS network bandwidth for `alice` +Stake 10 SYS network bandwidth for `alice` ```shell -cleos system delegatebw alice alice "0 SYS" "0.01 SYS" +dune -- cleos system delegatebw alice alice "0 SYS" "10 SYS" ``` -Stake 0.01 SYS CPU bandwidth for `alice`: +Stake 10 SYS CPU bandwidth for `alice`: ```shell -cleos system delegatebw alice alice "0.01 SYS" "0 SYS" -``` \ No newline at end of file +dune -- cleos system delegatebw alice alice "10 SYS" "0 SYS" +``` diff --git a/docs/04_guides/04_how-to-vote.md b/docs/04_guides/04_how-to-vote.md index 31f5a6a6..4a34e38e 100644 --- a/docs/04_guides/04_how-to-vote.md +++ b/docs/04_guides/04_how-to-vote.md @@ -3,13 +3,13 @@ content_title: How to vote link_text: How to vote --- -# Goal +## Goal Vote for a block producer -# Before you begin +## Before you begin -* Install the current supported version of cleos +* Install the current supported version of dune * Ensure the reference system contracts from `eos-system-contracts` repository is deployed and used to manage system resources @@ -19,12 +19,12 @@ Vote for a block producer * Unlock your wallet -# Steps +## Steps Assume you are going to vote for blockproducer1 and blockproducer2 from an account called `eosiotestts2`, execute the following: ```bash -cleos system voteproducer prods eosiotestts2 blockproducer1 blockproducer2 +dune -- cleos system voteproducer prods eosiotestts2 blockproducer1 blockproducer2 ``` You should see something like below: @@ -32,4 +32,4 @@ You should see something like below: ```console executed transaction: 2d8b58f7387aef52a1746d7a22d304bbbe0304481d7751fc4a50b619df62676d 128 bytes 374 us # eosio <= eosio::voteproducer {"voter":"eosiotestts2","proxy":"","producers":["blockproducer1","blockproducer2"]} -``` \ No newline at end of file +``` diff --git a/docs/04_guides/08_configure-use-powerup-resource-model.md b/docs/04_guides/08_configure-use-powerup-resource-model.md index 835b4355..4b981c6e 100644 --- a/docs/04_guides/08_configure-use-powerup-resource-model.md +++ b/docs/04_guides/08_configure-use-powerup-resource-model.md @@ -2,9 +2,11 @@ content_title: How to configure PowerUp resource model link_text: How to configure PowerUp resource model --- -# Configure and Use the PowerUp Resource Model -## Overview +## Configure and Use the PowerUp Resource Model + +### Overview + This new system will create a new optional NET and CPU marketplace which displaces (over time) the existing staking system and REX market. Under the old model, system token holders own NET and CPU and may choose to use it themselves, delegate it to others, or make @@ -13,11 +15,12 @@ owns almost all NET and CPU resources and the only way to access these resources through the new `powerup` action. It channels fees to the REX pool to enable token holders to profit off the new market. -## Configuration +### Configuration + +#### Definitions -### Definitions +##### Configuration -#### Configuration ```c++ // configure the `powerup` market. The market becomes available the first time this action is invoked void cfgpowerup( powerup_config& args ); @@ -66,6 +69,7 @@ struct powerup_config { // existing setting (no default exists). }; ``` + #### State Definitions useful to help understand the configuration, including defaults: @@ -122,18 +126,21 @@ struct powerup_state { }; ``` -### Preparation for Upgrade +#### Preparation for Upgrade + 1. Build [eos-system-contracts](https://github.com/eosnetworkfoundation/eos-system-contracts) with `powerup` code. 2. Deploy eosio.system contract to `eosio`. 3. Create account `eosio.reserv` and ensure the account has enough RAM, at least 4 KiB. 4. Deploy `powup.results.abi` to `eosio.reserv` account using `setabi`. The ABI can be found in the `build/contracts/eosio.system/.powerup/` directory. 5. Enable the REX system (if not enabled). -### Configuring PowerUp +#### Configure PowerUp + +##### Config file + +**config.json** -#### Config file ```json -# config.json { "net": { "assumed_stake_weight": 944076307, @@ -160,16 +167,19 @@ struct powerup_state { } ``` -#### cfgpowerup Action Call +##### cfgpowerup Action Call + ```sh # call to `cfgpowerup` -cleos push action eosio cfgpowerup "[`cat ./config.json`]" -p eosio +dune -- cleos push action eosio cfgpowerup "[`cat ./config.json`]" -p eosio ``` -#### Check state +##### Check state + ```sh -cleos get table eosio 0 powup.state +dune -- cleos get table eosio 0 powup.state ``` + ```json { "rows": [{ @@ -217,14 +227,17 @@ cleos get table eosio 0 powup.state } ``` -### Using PowerUp +#### Using PowerUp + +##### Execute An Order -#### Executing an order The action to power up an account is `powerup`. It takes a `payer` of the fee and a `receiver` of the resources. The `days` must always match `state.powerup_days`. `net_frac` and `cpu_frac` are the percentage of the resources that you need. The easiest way to caclulate the percentage is to multiple 10^15 (100%) by the desired percentage. For example: 10^15 * 0.01 = 10^13. + ```sh -cleos push action eosio powerup '[user, user, 1, 10000000000000, 10000000000000, "1000.0000 TST"]' -p user -``` +dune -- cleos push action eosio powerup '[user, user, 1, 10000000000000, 10000000000000, "1000.0000 TST"]' -p user ``` + +```console executed transaction: 82b7124601612b371b812e3bf65cf63bb44616802d3cd33a2c0422b58399f54f 144 bytes 521 us # eosio <= eosio::powerup {"payer":"user","receiver":"user","days":1,"net_frac":"10000000000000","cpu_frac":"10000000000000","... # eosio.token <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 TST","memo":"transfer from user to eosio.rex"} @@ -232,17 +245,21 @@ executed transaction: 82b7124601612b371b812e3bf65cf63bb44616802d3cd33a2c0422b583 # user <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 TST","memo":"transfer from user to eosio.rex"} # eosio.rex <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 TST","memo":"transfer from user to eosio.rex"} ``` + You can see how much NET and CPU weight was received as well as the fee by looking at the `eosio.reserv::powupresult` informational action. *It is worth mentioning that the network being used for the example has not fully transitioned so the available resources are minimal therefore 1% of the resources are quite expensive. As the system continues the transition more resources are available to the `PowerUp` resource model and will become more affordable.* -#### Processing Expired Orders +##### Process Expired Orders + The resources in loans that expire do not automatically get reclaimed by the system. The expired loans sit in a queue that must be processed. Anyone calling the `powerup` action will help with processing this queue (limited to processing at most two expired loans at a time) so that normally the expired loans will be automatically processed in a timely manner. However, in some cases it may be necessary to manual process expired loans in the queue to make resources available to the system again and thus make prices cheaper. In such a scenario, any account may process up to an arbitrary number of expired loans by calling the `powerupexec` action. The orders table `powup.order` can be viewed by calling: + ```sh -cleos get table eosio 0 powup.order +dune -- cleos get table eosio 0 powup.order ``` + ```json { "rows": [{ @@ -262,8 +279,9 @@ cleos get table eosio 0 powup.order Example `powerupexec` call: ```sh -cleos push action eosio powerupexec '[user, 2]' -p user +dune -- cleos push action eosio powerupexec '[user, 2]' -p user ``` + ```console executed transaction: 93ab4ac900a7902e4e59e5e925e8b54622715328965150db10774aa09855dc98 104 bytes 363 us # eosio <= eosio::powerupexec {"user":"user","max":2} diff --git a/docs/index.md b/docs/index.md index 45e580e7..e36fd146 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,7 +2,7 @@ content_title: About System Contracts --- -The Antelope blockchain framework is unique in that the features and characteristics of the blockchain built on it are flexible, that is, they can be changed, or modified completely to suit each business case requirement. Core blockchain features such as consensus, fee schedules, account creation and modification, token economics, block producer registration, voting, multi-sig, etc., are implemented inside smart contracts which are deployed on the blockchain built on the Antelope framework. +The EOS blockchain is unique in that the features and characteristics of the blockchain built on it are flexible, that is, they can be changed, or modified completely to suit the EOS community needs. Core blockchain features such as consensus, fee schedules, account creation and modification, token economics, block producer registration, voting, multi-sig, are implemented inside smart contracts which are deployed on the EOS blockchain. ## System contracts defined in eos-system-contracts @@ -20,8 +20,9 @@ The `eos-system-contracts` repository contains the system contracts encapsulatin 2. [RAM](01_key-concepts/02_ram.md) 3. [CPU](01_key-concepts/03_cpu.md) 4. [NET](01_key-concepts/04_net.md) -5. [Stake](01_key-concepts/05_stake.md) +5. [Resource Allocation](01_key-concepts/05_system_resource_allocation.md) 6. [Vote](01_key-concepts/06_vote.md) ## Build and deploy + To build and deploy the system contract follow the instruction from [Build and deploy](03_build-and-deploy.md) section. \ No newline at end of file From c01a4aeaf2081a2f770991ad3155d986aa3fb81b Mon Sep 17 00:00:00 2001 From: iamveritas Date: Tue, 31 Jan 2023 00:44:03 +0200 Subject: [PATCH 42/96] second take, make sure stake CPU and NET are not mentioned anymore, because they are deprecated already for quite some time. SYS -> EOS --- docs/01_key-concepts/01_system.md | 8 ++-- docs/01_key-concepts/03_cpu.md | 2 +- docs/01_key-concepts/04_net.md | 2 +- docs/04_guides/02_how-to-buy-ram.md | 6 +-- docs/04_guides/03_how-to-stake.md | 10 ++--- docs/04_guides/04_how-to-vote.md | 4 +- ...ow-to-create-issue-and-transfer-a-token.md | 42 ++++++++++++------- ...-a-multisig-transaction-with-eosio.msig.md | 34 +++++++-------- docs/04_guides/07_how-to-use-eosio.wrap.md | 30 ++++++------- ...08_configure-use-powerup-resource-model.md | 12 +++--- 10 files changed, 82 insertions(+), 68 deletions(-) diff --git a/docs/01_key-concepts/01_system.md b/docs/01_key-concepts/01_system.md index 30a9f1f3..9562df9c 100644 --- a/docs/01_key-concepts/01_system.md +++ b/docs/01_key-concepts/01_system.md @@ -2,7 +2,9 @@ content_title: System contracts, system accounts, privileged accounts --- -At the genesis of an Antelope-based blockchain, there is only one account present, `eosio` account, which is the main `system account`. There are other `system account`s, created by `eosio` account, which control specific actions of the `system contract`s [mentioned in previous section](/index.md#system-contracts-defined-in-eos-system-contracts). __Note__ the terms `system contract` and `system account`. `Privileged accounts` are accounts which can execute a transaction while skipping the standard authorization check. To ensure that this is not a security hole, the permission authority over these accounts is granted to `eosio.prods` system account. +At the genesis of the EOS blockchain, there was only one account present, `eosio` account, which was and still is the main `system account`. During the EOS blockchain bootstrap process other `system account`s, were created by `eosio` account, which control specific actions of the `system contract`s. You can see them listed in the [About System Contract](../index.md#system-contracts-defined-in-eos-system-contracts) section. + +__Note__ the terms `system contract` and `system account`. `Privileged accounts` are accounts which can execute a transaction while skipping the standard authorization check. To ensure that this is not a security hole, the permission authority over these accounts is granted to `eosio.prods` system account. As you just learned the relation between a `system account` and a `system contract`, it is also important to remember that not all system accounts contain a system contract, but each system account has important roles in the blockchain functionality, as follows: @@ -15,9 +17,9 @@ As you just learned the relation between a `system account` and a `system contra |eosio.names|No|No|The account which is holding funds from namespace auctions.| |eosio.bpay|No|No|The account that pays the block producers for producing blocks. It assigns 0.25% of the inflation based on the amount of blocks a block producer created in the last 24 hours.| |eosio.prods|No|No|The account representing the union of all current active block producers permissions.| -|eosio.ram|No|No|The account that keeps track of the SYS balances based on users actions of buying or selling RAM.| +|eosio.ram|No|No|The account that keeps track of the EOS balances based on users actions of buying or selling RAM.| |eosio.ramfee|No|No|The account that keeps track of the fees collected from users RAM trading actions: 0.5% from the value of each trade goes into this account.| |eosio.saving|No|No|The account which holds the 4% of network inflation.| -|eosio.stake|No|No|The account that keeps track of all SYS tokens which have been staked for voting.| +|eosio.stake|No|No|The account that keeps track of all EOS tokens which have been staked for voting.| |eosio.vpay|No|No|The account that pays the block producers accordingly with the votes won. It assigns 0.75% of inflation based on the amount of votes a block producer won in the last 24 hours.| |eosio.rex|No|No|The account that keeps track of fees and balances resulted from REX related actions execution.| diff --git a/docs/01_key-concepts/03_cpu.md b/docs/01_key-concepts/03_cpu.md index add4b149..6be9436c 100644 --- a/docs/01_key-concepts/03_cpu.md +++ b/docs/01_key-concepts/03_cpu.md @@ -2,6 +2,6 @@ content_title: CPU as system resource --- -The system resource CPU provides processing power to blockchain accounts. The amount of CPU an account has is measured in microseconds and it is referred to as `cpu bandwidth` on the `dune -- cleos get account` command output. The `cpu bandwidth` represents the amount of processing time an account has at its disposal when actions sent to its contract are executed by the blockchain. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient CPU must be allocated to the account in order for transactions to complete. +The system resource CPU provides processing power to blockchain accounts. The amount of CPU an account has is measured in microseconds and it is referred to as `cpu bandwidth` on the `cleos get account` command output. The `cpu bandwidth` represents the amount of processing time an account has at its disposal when actions sent to its contract are executed by the blockchain. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient CPU must be allocated to the account in order for transactions to complete. For more details about resource allocation on the EOS blockchain refer to the [Resource Allocation](./05_system_resource_allocation.md) documentation. diff --git a/docs/01_key-concepts/04_net.md b/docs/01_key-concepts/04_net.md index 5ab148ed..0b1d15da 100644 --- a/docs/01_key-concepts/04_net.md +++ b/docs/01_key-concepts/04_net.md @@ -2,6 +2,6 @@ content_title: NET as system resource --- -NET, as CPU and RAM, is a very important system resource in the EOS blockchain. NET is measured by the byte size of the transactions saved in the blockchain database and it is referred to as `net bandwidth` on the `dune -- cleos get account` command output. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient NET must be allocated to the account in order for transactions to complete. +NET, as CPU and RAM, is a very important system resource in the EOS blockchain. NET is measured by the byte size of the transactions saved in the blockchain database and it is referred to as `net bandwidth` on the `cleos get account` command output. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient NET must be allocated to the account in order for transactions to complete. For more details about resource allocation on the EOS blockchain refer to the [Resource Allocation](./05_system_resource_allocation.md) documentation. diff --git a/docs/04_guides/02_how-to-buy-ram.md b/docs/04_guides/02_how-to-buy-ram.md index 02267e89..cfec2def 100644 --- a/docs/04_guides/02_how-to-buy-ram.md +++ b/docs/04_guides/02_how-to-buy-ram.md @@ -15,14 +15,14 @@ Setup an account that require multiple signatures for signing a transaction * You have sufficient token allocated to your account -* Install the currently supported version of dune +* Install the currently supported version of cleos * Unlock your wallet ## Steps -Buys RAM in value of 10 SYS tokens for account `alice`: +Buys RAM in value of 10 EOS tokens for account `alice`: ```shell -dune -- cleos system buyram alice alice "10 SYS" -p alice@active +cleos system buyram alice alice "10 EOS" -p alice@active ``` \ No newline at end of file diff --git a/docs/04_guides/03_how-to-stake.md b/docs/04_guides/03_how-to-stake.md index 1d19b800..a188d021 100644 --- a/docs/04_guides/03_how-to-stake.md +++ b/docs/04_guides/03_how-to-stake.md @@ -9,7 +9,7 @@ Stake resources for your account to participate in the on-chain voting and gover ## Before you begin -* Install the currently supported version of dune +* Install the currently supported version of cleos * Ensure the reference system contracts from `eos-system-contracts` repository is deployed and used to manage system resources @@ -20,14 +20,14 @@ Stake resources for your account to participate in the on-chain voting and gover ## Steps -Stake 10 SYS network bandwidth for `alice` +Stake 10 EOS network bandwidth for `alice` ```shell -dune -- cleos system delegatebw alice alice "0 SYS" "10 SYS" +cleos system delegatebw alice alice "0 EOS" "10 EOS" ``` -Stake 10 SYS CPU bandwidth for `alice`: +Stake 10 EOS CPU bandwidth for `alice`: ```shell -dune -- cleos system delegatebw alice alice "10 SYS" "0 SYS" +cleos system delegatebw alice alice "10 EOS" "0 EOS" ``` diff --git a/docs/04_guides/04_how-to-vote.md b/docs/04_guides/04_how-to-vote.md index 4a34e38e..66866d77 100644 --- a/docs/04_guides/04_how-to-vote.md +++ b/docs/04_guides/04_how-to-vote.md @@ -9,7 +9,7 @@ Vote for a block producer ## Before you begin -* Install the current supported version of dune +* Install the current supported version of cleos * Ensure the reference system contracts from `eos-system-contracts` repository is deployed and used to manage system resources @@ -24,7 +24,7 @@ Vote for a block producer Assume you are going to vote for blockproducer1 and blockproducer2 from an account called `eosiotestts2`, execute the following: ```bash -dune -- cleos system voteproducer prods eosiotestts2 blockproducer1 blockproducer2 +cleos system voteproducer prods eosiotestts2 blockproducer1 blockproducer2 ``` You should see something like below: diff --git a/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md b/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md index c228b23b..54f6b166 100644 --- a/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md +++ b/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md @@ -12,6 +12,7 @@ cd CONTRACTS_DIR ``` Pull the source + ```sh git clone https://github.com/eosnetworkfoundation/eos-system-contracts --branch release/3.1 --single-branch ``` @@ -21,6 +22,7 @@ cd eos-system-contracts/contracts/eosio.token ``` ## Step 2: Create Account for Contract + [[info]] | You may have to unlock your wallet first! @@ -37,10 +39,12 @@ eosio-cpp -I include -o eosio.token.wasm src/eosio.token.cpp --abigen ## Step 4: Deploy the Token Contract ```shell + cleos set contract eosio.token CONTRACTS_DIR/eos-system-contracts/contracts/eosio.token --abi eosio.token.abi -p eosio.token@active ``` Result should look similar to the one below: + ```console Reading WASM from ... Publishing contract... @@ -53,40 +57,44 @@ warning: transaction executed locally, but may not be confirmed by the network y ## Step 5: Create the Token ```shell -cleos push action eosio.token create '[ "eosio", "1000000000.0000 SYS"]' -p eosio.token@active +cleos push action eosio.token create '[ "eosio", "1000000000.0000 NEWT"]' -p eosio.token@active ``` Result should look similar to the one below: + ```console executed transaction: 0e49a421f6e75f4c5e09dd738a02d3f51bd18a0cf31894f68d335cd70d9c0e12 120 bytes 1000 cycles -# eosio.token <= eosio.token::create {"issuer":"eosio","maximum_supply":"1000000000.0000 SYS"} +# eosio.token <= eosio.token::create {"issuer":"eosio","maximum_supply":"1000000000.0000 NEWT"} ``` An alternate approach uses named arguments: ```shell -cleos push action eosio.token create '{"issuer":"eosio", "maximum_supply":"1000000000.0000 SYS"}' -p eosio.token@active +cleos push action eosio.token create '{"issuer":"eosio", "maximum_supply":"1000000000.0000 NEWT"}' -p eosio.token@active ``` Result should look similar to the one below: + ```console executed transaction: 0e49a421f6e75f4c5e09dd738a02d3f51bd18a0cf31894f68d335cd70d9c0e12 120 bytes 1000 cycles -# eosio.token <= eosio.token::create {"issuer":"eosio","maximum_supply":"1000000000.0000 SYS"} +# eosio.token <= eosio.token::create {"issuer":"eosio","maximum_supply":"1000000000.0000 NEWT"} ``` -This command created a new token `SYS` with a precision of 4 decimals and a maximum supply of 1000000000.0000 SYS. To create this token requires the permission of the `eosio.token` contract. For this reason, `-p eosio.token@active` was passed to authorize the request. + +This command created a new token `NEWT` with a precision of 4 decimals and a maximum supply of 1000000000.0000 NEWT. To create this token requires the permission of the `eosio.token` contract. For this reason, `-p eosio.token@active` was passed to authorize the request. ## Step 6: Issue Tokens The issuer can issue new tokens to the issuer account in our case `eosio`. ```sh -cleos push action eosio.token issue '[ "eosio", "100.0000 SYS", "memo" ]' -p eosio@active +cleos push action eosio.token issue '[ "eosio", "100.0000 NEWT", "memo" ]' -p eosio@active ``` Result should look similar to the one below: + ```console executed transaction: a26b29d66044ad95edf0fc04bad3073e99718bc26d27f3c006589adedb717936 128 bytes 337 us -# eosio.token <= eosio.token::issue {"to":"eosio","quantity":"100.0000 SYS","memo":"memo"} +# eosio.token <= eosio.token::issue {"to":"eosio","quantity":"100.0000 NEWT","memo":"memo"} warning: transaction executed locally, but may not be confirmed by the network yet ] ``` @@ -95,35 +103,39 @@ warning: transaction executed locally, but may not be confirmed by the network y Now that account `eosio` has been issued tokens, transfer some of them to account `bob`. ```shell -cleos push action eosio.token transfer '[ "eosio", "bob", "25.0000 SYS", "m" ]' -p eosio@active +cleos push action eosio.token transfer '[ "eosio", "bob", "25.0000 NEWT", "m" ]' -p eosio@active ``` Result should look similar to the one below: + ```console executed transaction: 60d334850151cb95c35fe31ce2e8b536b51441c5fd4c3f2fea98edcc6d69f39d 128 bytes 497 us -# eosio.token <= eosio.token::transfer {"from":"eosio","to":"bob","quantity":"25.0000 SYS","memo":"m"} -# eosio <= eosio.token::transfer {"from":"eosio","to":"bob","quantity":"25.0000 SYS","memo":"m"} -# bob <= eosio.token::transfer {"from":"eosio","to":"bob","quantity":"25.0000 SYS","memo":"m"} +# eosio.token <= eosio.token::transfer {"from":"eosio","to":"bob","quantity":"25.0000 NEWT","memo":"m"} +# eosio <= eosio.token::transfer {"from":"eosio","to":"bob","quantity":"25.0000 NEWT","memo":"m"} +# bob <= eosio.token::transfer {"from":"eosio","to":"bob","quantity":"25.0000 NEWT","memo":"m"} warning: transaction executed locally, but may not be confirmed by the network yet ] ``` + Now check if "bob" got the tokens using [cleos get currency balance](https://docs.eosnetwork.com/leap/latest/cleos/command-reference/get/currency-balance) ```shell -cleos get currency balance eosio.token bob SYS +cleos get currency balance eosio.token bob NEWT ``` Result: + ```console -25.00 SYS +25.00 NEWT ``` Check "eosio's" balance, notice that tokens were deducted from the account ```shell -cleos get currency balance eosio.token eosio SYS +cleos get currency balance eosio.token eosio NEWT ``` Result: + ```console -75.00 SYS +75.00 NEWT ``` diff --git a/docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md b/docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md index 6014c9ba..243c430a 100644 --- a/docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md +++ b/docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md @@ -7,13 +7,13 @@ link_text: How to sign a multisig transaction with eosio.msig ### Prerequisites: - eosio.token contract installed to eosio.token account, eosio.msig contract installed on eosio.msig account which is a priviliged account. - - account 'treasury' is the issuer of SYS token. + - account 'treasury' is the issuer of EOS token. - account 'tester' exists. - keys to accounts 'treasury' and 'tester' imported into local wallet, the wallet is unlocked. ### One user creates a proposal: ```sh -cleos multisig propose test '[{"actor": "treasury", "permission": "active"}]' '[{"actor": "treasury", "permission": "active"}]' eosio.token issue '{"to": "tester", "quantity": "1000.0000 SYS", "memo": ""}' -p tester +cleos multisig propose test '[{"actor": "treasury", "permission": "active"}]' '[{"actor": "treasury", "permission": "active"}]' eosio.token issue '{"to": "tester", "quantity": "1000.0000 EOS", "memo": ""}' -p tester ``` ```console executed transaction: e26f3a3a7cba524a7b15a0b6c77c7daa73d3ba9bf84e83f9c2cdf27fcb183d61 336 bytes 107520 cycles @@ -53,7 +53,7 @@ cleos multisig review tester test ], "data": { "to": "tester", - "quantity": "1000.0000 SYS", + "quantity": "1000.0000 EOS", "memo": "" }, "hex_data": "000000005c95b1ca809698000000000004454f530000000000" @@ -86,13 +86,13 @@ executed transaction: 64e5eaceb77362694055f572ae35876111e87b637a55250de315b1b55e ### Prerequisites: - eosio.token contract installed to eosio.token account, eosio.msig contract installed on eosio.msig account which is a priviliged account. - - account 'treasury' has at least 1.1000 SYS token balance. + - account 'treasury' has at least 1.1000 EOS token balance. - account 'tester' exists. - keys to accounts 'treasury' and 'tester' imported into local wallet, the wallet is unlocked. ### One user creates a proposal: ```sh -cleos multisig propose test '[{"actor": "treasury", "permission": "active"}]' '[{"actor": "treasury", "permission": "active"}]' eosio.token transfer '{"from": "treasury", "to": "tester", "quantity": "1.0000 SYS", "memo": ""}' -p tester +cleos multisig propose test '[{"actor": "treasury", "permission": "active"}]' '[{"actor": "treasury", "permission": "active"}]' eosio.token transfer '{"from": "treasury", "to": "tester", "quantity": "1.0000 EOS", "memo": ""}' -p tester ``` ```console executed transaction: e26f3a3a7cba524a7b15a0b6c77c7daa73d3ba9bf84e83f9c2cdf27fcb183d61 336 bytes 107520 cycles @@ -133,7 +133,7 @@ cleos multisig review tester test "data": { "from": "treasury", "to": "tester", - "quantity": "1.0000 SYS", + "quantity": "1.0000 EOS", "memo": "" }, "hex_data": "000000005c95b1ca809698000000000004454f530000000000" @@ -158,11 +158,11 @@ cleos get account tester ``` ```console ... -SYS balances: - liquid: 1.0487 SYS - staked: 2.0000 SYS - unstaking: 0.0000 SYS - total: 4.0487 SYS +EOS balances: + liquid: 1.0487 EOS + staked: 2.0000 EOS + unstaking: 0.0000 EOS + total: 4.0487 EOS ``` ### First user initiates execution of proposed transaction: @@ -174,15 +174,15 @@ executed transaction: 64e5eaceb77362694055f572ae35876111e87b637a55250de315b1b55e # eosio.msig <= eosio.msig::exec {"proposer":"tester","proposal_name":"test","executer":"tester"} ``` -### First user can check account balance, it should be increased by 1.0000 SYS +### First user can check account balance, it should be increased by 1.0000 EOS ```sh cleos get account tester ``` ```console ... -SYS balances: - liquid: 2.0487 SYS - staked: 2.0000 SYS - unstaking: 0.0000 SYS - total: 4.0487 SYS +EOS balances: + liquid: 2.0487 EOS + staked: 2.0000 EOS + unstaking: 0.0000 EOS + total: 4.0487 EOS ``` diff --git a/docs/04_guides/07_how-to-use-eosio.wrap.md b/docs/04_guides/07_how-to-use-eosio.wrap.md index 25f04e10..d052fe03 100644 --- a/docs/04_guides/07_how-to-use-eosio.wrap.md +++ b/docs/04_guides/07_how-to-use-eosio.wrap.md @@ -9,7 +9,7 @@ The eosio.wrap contract needs to be installed on a privileged account to functio First, the account `eosio.wrap` needs to be created. Since it has the restricted `eosio.` prefix, only a privileged account can create this account. So this guide will use the `eosio` account to create the `eosio.wrap` account. On typical live blockchain configurations, the `eosio` account can only be controlled by a supermajority of the current active block producers. So, this guide will use the `eosio.msig` contract to help coordinate the approvals of the proposed transaction that creates the `eosio.wrap` account. -The `eosio.wrap` account also needs to have sufficient RAM to host the contract and sufficient CPU and network bandwidth to deploy the contract. This means that the creator of the account (`eosio`) needs to gift sufficient RAM to the new account and delegate (preferably with transfer) sufficient bandwidth to the new account. To pull this off the `eosio` account needs to have enough of the core system token (the `SYS` token will be used within this guide) in its liquid balance. So prior to continuing with the next steps of this guide, the active block producers of the chain who are coordinating this process need to ensure that a sufficient amount of core system tokens that they are authorized to spend is placed in the liquid balance of the `eosio` account. +The `eosio.wrap` account also needs to have sufficient RAM to host the contract and sufficient CPU and network bandwidth to deploy the contract. This means that the creator of the account (`eosio`) needs to gift sufficient RAM to the new account and delegate (preferably with transfer) sufficient bandwidth to the new account. To pull this off the `eosio` account needs to have enough of the core system token (the `EOS` token will be used within this guide) in its liquid balance. So prior to continuing with the next steps of this guide, the active block producers of the chain who are coordinating this process need to ensure that a sufficient amount of core system tokens that they are authorized to spend is placed in the liquid balance of the `eosio` account. This guide will be using cleos to carry out the process. @@ -25,11 +25,11 @@ Three unsigned transactions will be generated using cleos and then the actions w First, generate a transaction to capture the necessary actions involved in creating a new account: ```sh -cleos system newaccount -s -j -d --transfer --stake-net "1.000 SYS" --stake-cpu "1.000 SYS" --buy-ram-kbytes 50 eosio eosio.wrap EOS8MMUW11TAdTDxqdSwSqJodefSoZbFhcprndomgLi9MeR2o8MT4 > generated_account_creation_trx.json +cleos system newaccount -s -j -d --transfer --stake-net "1.000 EOS" --stake-cpu "1.000 EOS" --buy-ram-kbytes 50 eosio eosio.wrap EOS8MMUW11TAdTDxqdSwSqJodefSoZbFhcprndomgLi9MeR2o8MT4 > generated_account_creation_trx.json ``` ```console 726964ms thread-0 main.cpp:429 create_action ] result: {"binargs":"0000000000ea305500004d1a03ea305500c80000"} arg: {"code":"eosio","action":"buyrambytes","args":{"payer":"eosio","receiver":"eosio.wrap","bytes":51200}} -726967ms thread-0 main.cpp:429 create_action ] result: {"binargs":"0000000000ea305500004d1a03ea3055102700000000000004535953000000001027000000000000045359530000000001"} arg: {"code":"eosio","action":"delegatebw","args":{"from":"eosio","receiver":"eosio.wrap","stake_net_quantity":"1.0000 SYS","stake_cpu_quantity":"1.0000 SYS","transfer":true}} +726967ms thread-0 main.cpp:429 create_action ] result: {"binargs":"0000000000ea305500004d1a03ea3055102700000000000004535953000000001027000000000000045359530000000001"} arg: {"code":"eosio","action":"delegatebw","args":{"from":"eosio","receiver":"eosio.wrap","stake_net_quantity":"1.0000 EOS","stake_cpu_quantity":"1.0000 EOS","transfer":true}} ``` ```sh cat generated_account_creation_trx.json @@ -412,15 +412,15 @@ memory: quota: 49.74 KiB used: 3.33 KiB net bandwidth: - staked: 1.0000 SYS (total stake delegated from account to self) - delegated: 0.0000 SYS (total staked delegated to account from others) + staked: 1.0000 EOS (total stake delegated from account to self) + delegated: 0.0000 EOS (total staked delegated to account from others) used: 0 bytes available: 2.304 MiB limit: 2.304 MiB cpu bandwidth: - staked: 1.0000 SYS (total stake delegated from account to self) - delegated: 0.0000 SYS (total staked delegated to account from others) + staked: 1.0000 EOS (total stake delegated from account to self) + delegated: 0.0000 EOS (total staked delegated to account from others) used: 0 us available: 460.8 ms limit: 460.8 ms @@ -685,15 +685,15 @@ memory: quota: 49.74 KiB used: 3.365 KiB net bandwidth: - staked: 1.0000 SYS (total stake delegated from account to self) - delegated: 0.0000 SYS (total staked delegated to account from others) + staked: 1.0000 EOS (total stake delegated from account to self) + delegated: 0.0000 EOS (total staked delegated to account from others) used: 0 bytes available: 2.304 MiB limit: 2.304 MiB cpu bandwidth: - staked: 1.0000 SYS (total stake delegated from account to self) - delegated: 0.0000 SYS (total staked delegated to account from others) + staked: 1.0000 EOS (total stake delegated from account to self) + delegated: 0.0000 EOS (total staked delegated to account from others) used: 0 us available: 460.8 ms limit: 460.8 ms @@ -953,15 +953,15 @@ memory: quota: 49.74 KiB used: 3.348 KiB net bandwidth: - staked: 1.0000 SYS (total stake delegated from account to self) - delegated: 0.0000 SYS (total staked delegated to account from others) + staked: 1.0000 EOS (total stake delegated from account to self) + delegated: 0.0000 EOS (total staked delegated to account from others) used: 0 bytes available: 2.304 MiB limit: 2.304 MiB cpu bandwidth: - staked: 1.0000 SYS (total stake delegated from account to self) - delegated: 0.0000 SYS (total staked delegated to account from others) + staked: 1.0000 EOS (total stake delegated from account to self) + delegated: 0.0000 EOS (total staked delegated to account from others) used: 413 us available: 460.4 ms limit: 460.8 ms diff --git a/docs/04_guides/08_configure-use-powerup-resource-model.md b/docs/04_guides/08_configure-use-powerup-resource-model.md index 4b981c6e..8213d57f 100644 --- a/docs/04_guides/08_configure-use-powerup-resource-model.md +++ b/docs/04_guides/08_configure-use-powerup-resource-model.md @@ -89,7 +89,7 @@ struct powerup_state_resource { uint8_t version = 0; int64_t weight = 0; // resource market weight. calculated; varies over time. // 1 represents the same amount of resources as 1 - // satoshi of SYS staked. + // satoshi of EOS staked. int64_t weight_ratio = 0; // resource market weight ratio: // assumed_stake_weight / (assumed_stake_weight + weight). // calculated; varies over time. 1x = 10^15. 0.01x = 10^13. @@ -171,13 +171,13 @@ struct powerup_state { ```sh # call to `cfgpowerup` -dune -- cleos push action eosio cfgpowerup "[`cat ./config.json`]" -p eosio +cleos push action eosio cfgpowerup "[`cat ./config.json`]" -p eosio ``` ##### Check state ```sh -dune -- cleos get table eosio 0 powup.state +cleos get table eosio 0 powup.state ``` ```json @@ -234,7 +234,7 @@ dune -- cleos get table eosio 0 powup.state The action to power up an account is `powerup`. It takes a `payer` of the fee and a `receiver` of the resources. The `days` must always match `state.powerup_days`. `net_frac` and `cpu_frac` are the percentage of the resources that you need. The easiest way to caclulate the percentage is to multiple 10^15 (100%) by the desired percentage. For example: 10^15 * 0.01 = 10^13. ```sh -dune -- cleos push action eosio powerup '[user, user, 1, 10000000000000, 10000000000000, "1000.0000 TST"]' -p user +cleos push action eosio powerup '[user, user, 1, 10000000000000, 10000000000000, "1000.0000 TST"]' -p user ``` ```console @@ -257,7 +257,7 @@ The resources in loans that expire do not automatically get reclaimed by the sys The orders table `powup.order` can be viewed by calling: ```sh -dune -- cleos get table eosio 0 powup.order +cleos get table eosio 0 powup.order ``` ```json @@ -279,7 +279,7 @@ dune -- cleos get table eosio 0 powup.order Example `powerupexec` call: ```sh -dune -- cleos push action eosio powerupexec '[user, 2]' -p user +cleos push action eosio powerupexec '[user, 2]' -p user ``` ```console From 1eb061bd84aaf8f36cb3493a163792c66a0089d1 Mon Sep 17 00:00:00 2001 From: iamveritas Date: Wed, 1 Feb 2023 10:26:19 +0200 Subject: [PATCH 43/96] "content_title: " -> "title: " --- docs/01_key-concepts/01_system.md | 2 +- docs/01_key-concepts/02_ram.md | 2 +- docs/01_key-concepts/03_cpu.md | 2 +- docs/01_key-concepts/04_net.md | 2 +- docs/01_key-concepts/05_system_resource_allocation.md | 2 +- docs/01_key-concepts/06_vote.md | 2 +- docs/01_key-concepts/07_powerup_model.md | 2 +- docs/03_build-and-deploy.md | 2 +- docs/04_guides/01_upgrading-the-eosio.system-contract.md | 2 +- docs/04_guides/02_how-to-buy-ram.md | 2 +- docs/04_guides/03_how-to-stake.md | 2 +- docs/04_guides/04_how-to-vote.md | 2 +- docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md | 2 +- .../06_how-to-sign-a-multisig-transaction-with-eosio.msig.md | 2 +- docs/04_guides/07_how-to-use-eosio.wrap.md | 2 +- docs/04_guides/08_configure-use-powerup-resource-model.md | 2 +- docs/index.md | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/01_key-concepts/01_system.md b/docs/01_key-concepts/01_system.md index 9562df9c..a4d31090 100644 --- a/docs/01_key-concepts/01_system.md +++ b/docs/01_key-concepts/01_system.md @@ -1,5 +1,5 @@ --- -content_title: System contracts, system accounts, privileged accounts +title: System contracts, system accounts, privileged accounts --- At the genesis of the EOS blockchain, there was only one account present, `eosio` account, which was and still is the main `system account`. During the EOS blockchain bootstrap process other `system account`s, were created by `eosio` account, which control specific actions of the `system contract`s. You can see them listed in the [About System Contract](../index.md#system-contracts-defined-in-eos-system-contracts) section. diff --git a/docs/01_key-concepts/02_ram.md b/docs/01_key-concepts/02_ram.md index 0089afd2..7aac6e38 100644 --- a/docs/01_key-concepts/02_ram.md +++ b/docs/01_key-concepts/02_ram.md @@ -1,5 +1,5 @@ --- -content_title: RAM as system resource +title: RAM as system resource --- ## What is RAM diff --git a/docs/01_key-concepts/03_cpu.md b/docs/01_key-concepts/03_cpu.md index 6be9436c..1a16c081 100644 --- a/docs/01_key-concepts/03_cpu.md +++ b/docs/01_key-concepts/03_cpu.md @@ -1,5 +1,5 @@ --- -content_title: CPU as system resource +title: CPU as system resource --- The system resource CPU provides processing power to blockchain accounts. The amount of CPU an account has is measured in microseconds and it is referred to as `cpu bandwidth` on the `cleos get account` command output. The `cpu bandwidth` represents the amount of processing time an account has at its disposal when actions sent to its contract are executed by the blockchain. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient CPU must be allocated to the account in order for transactions to complete. diff --git a/docs/01_key-concepts/04_net.md b/docs/01_key-concepts/04_net.md index 0b1d15da..c9da0453 100644 --- a/docs/01_key-concepts/04_net.md +++ b/docs/01_key-concepts/04_net.md @@ -1,5 +1,5 @@ --- -content_title: NET as system resource +title: NET as system resource --- NET, as CPU and RAM, is a very important system resource in the EOS blockchain. NET is measured by the byte size of the transactions saved in the blockchain database and it is referred to as `net bandwidth` on the `cleos get account` command output. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient NET must be allocated to the account in order for transactions to complete. diff --git a/docs/01_key-concepts/05_system_resource_allocation.md b/docs/01_key-concepts/05_system_resource_allocation.md index 1a07b350..6ee096ce 100644 --- a/docs/01_key-concepts/05_system_resource_allocation.md +++ b/docs/01_key-concepts/05_system_resource_allocation.md @@ -1,5 +1,5 @@ --- -content_title: System Resource Allocation +title: System Resource Allocation --- ## System Resources diff --git a/docs/01_key-concepts/06_vote.md b/docs/01_key-concepts/06_vote.md index aa271e38..f66076a2 100644 --- a/docs/01_key-concepts/06_vote.md +++ b/docs/01_key-concepts/06_vote.md @@ -1,5 +1,5 @@ --- -content_title: Voting on EOS blockchain +title: Voting on EOS blockchain --- The EOS blockchain is kept alive by nodes which are interconnected between each other, communicating with each other via peer to peer protocols. Some of these nodes are elected, via a voting process, by the token holders to be producer nodes. They produce blocks, validate them and reach consensus on what transactions are allowed in each block, their order, and what blocks are finalized and stored forever in the blockchain state. This way the governance, the mechanism by which collective decisions are made, of the blockchain is achieved through the 21 active block producers which are appointed by token holders' votes. It is the 21 active block producers which continuously advancing the blockchain by creating blocks, and securing them by validating them, and reaching consensus. Consensus is reached when 2/3+1 active block producers agree on validity of a block, that is all transactions contained in it and their order. The 21 producers is the default value however it can be configured to be higher or smaller to meet each business case requirements. diff --git a/docs/01_key-concepts/07_powerup_model.md b/docs/01_key-concepts/07_powerup_model.md index 36f3b895..a16521e6 100644 --- a/docs/01_key-concepts/07_powerup_model.md +++ b/docs/01_key-concepts/07_powerup_model.md @@ -1,5 +1,5 @@ --- -content_title: PowerUp Model +title: PowerUp Model --- ## What Is PowerUp Model diff --git a/docs/03_build-and-deploy.md b/docs/03_build-and-deploy.md index 7e2c9592..4f575d51 100644 --- a/docs/03_build-and-deploy.md +++ b/docs/03_build-and-deploy.md @@ -1,5 +1,5 @@ --- -content_title: How to build the EOS system contracts +title: How to build the EOS system contracts --- For building instructions, refer to the [Building](https://github.com/eosnetworkfoundation/eos-system-contracts#building) section. diff --git a/docs/04_guides/01_upgrading-the-eosio.system-contract.md b/docs/04_guides/01_upgrading-the-eosio.system-contract.md index 8196453f..c53e0424 100644 --- a/docs/04_guides/01_upgrading-the-eosio.system-contract.md +++ b/docs/04_guides/01_upgrading-the-eosio.system-contract.md @@ -1,5 +1,5 @@ --- -content_title: Upgrading the system contract +title: Upgrading the system contract link_text: Upgrading the system contract --- diff --git a/docs/04_guides/02_how-to-buy-ram.md b/docs/04_guides/02_how-to-buy-ram.md index cfec2def..2643e619 100644 --- a/docs/04_guides/02_how-to-buy-ram.md +++ b/docs/04_guides/02_how-to-buy-ram.md @@ -1,5 +1,5 @@ --- -content_title: How to buy RAM +title: How to buy RAM link_text: How to buy RAM --- diff --git a/docs/04_guides/03_how-to-stake.md b/docs/04_guides/03_how-to-stake.md index a188d021..5e88f063 100644 --- a/docs/04_guides/03_how-to-stake.md +++ b/docs/04_guides/03_how-to-stake.md @@ -1,5 +1,5 @@ --- -content_title: How to stake +title: How to stake link_text: How to stake --- diff --git a/docs/04_guides/04_how-to-vote.md b/docs/04_guides/04_how-to-vote.md index 66866d77..9afea42a 100644 --- a/docs/04_guides/04_how-to-vote.md +++ b/docs/04_guides/04_how-to-vote.md @@ -1,5 +1,5 @@ --- -content_title: How to vote +title: How to vote link_text: How to vote --- diff --git a/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md b/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md index 54f6b166..33947917 100644 --- a/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md +++ b/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md @@ -1,5 +1,5 @@ --- -content_title: How to create, issue and transfer a token +title: How to create, issue and transfer a token link_text: How to create, issue and transfer a token --- diff --git a/docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md b/docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md index 243c430a..b8d7c70e 100644 --- a/docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md +++ b/docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md @@ -1,5 +1,5 @@ --- -content_title: How to sign a multisig transaction with eosio.msig +title: How to sign a multisig transaction with eosio.msig link_text: How to sign a multisig transaction with eosio.msig --- diff --git a/docs/04_guides/07_how-to-use-eosio.wrap.md b/docs/04_guides/07_how-to-use-eosio.wrap.md index d052fe03..955f9e7b 100644 --- a/docs/04_guides/07_how-to-use-eosio.wrap.md +++ b/docs/04_guides/07_how-to-use-eosio.wrap.md @@ -1,5 +1,5 @@ --- -content_title: How to use eosio.wrap +title: How to use eosio.wrap link_text: How to use eosio.wrap --- diff --git a/docs/04_guides/08_configure-use-powerup-resource-model.md b/docs/04_guides/08_configure-use-powerup-resource-model.md index 8213d57f..614de06b 100644 --- a/docs/04_guides/08_configure-use-powerup-resource-model.md +++ b/docs/04_guides/08_configure-use-powerup-resource-model.md @@ -1,5 +1,5 @@ --- -content_title: How to configure PowerUp resource model +title: How to configure PowerUp resource model link_text: How to configure PowerUp resource model --- diff --git a/docs/index.md b/docs/index.md index e36fd146..c05d8156 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,5 +1,5 @@ --- -content_title: About System Contracts +title: About System Contracts --- The EOS blockchain is unique in that the features and characteristics of the blockchain built on it are flexible, that is, they can be changed, or modified completely to suit the EOS community needs. Core blockchain features such as consensus, fee schedules, account creation and modification, token economics, block producer registration, voting, multi-sig, are implemented inside smart contracts which are deployed on the EOS blockchain. From e6e8149b987661c3574869c94b914e18f4a847ab Mon Sep 17 00:00:00 2001 From: iamveritas Date: Wed, 1 Feb 2023 17:35:08 +0200 Subject: [PATCH 44/96] updates on the how to configure and use PowerUp resource model --- ...o-configure-use-powerup-resource-model.md} | 30 +++++++------------ 1 file changed, 10 insertions(+), 20 deletions(-) rename docs/04_guides/{08_configure-use-powerup-resource-model.md => 08_how-to-configure-use-powerup-resource-model.md} (94%) diff --git a/docs/04_guides/08_configure-use-powerup-resource-model.md b/docs/04_guides/08_how-to-configure-use-powerup-resource-model.md similarity index 94% rename from docs/04_guides/08_configure-use-powerup-resource-model.md rename to docs/04_guides/08_how-to-configure-use-powerup-resource-model.md index 614de06b..209f71af 100644 --- a/docs/04_guides/08_configure-use-powerup-resource-model.md +++ b/docs/04_guides/08_how-to-configure-use-powerup-resource-model.md @@ -1,26 +1,15 @@ --- -title: How to configure PowerUp resource model -link_text: How to configure PowerUp resource model +title: How To Configure And Use PowerUp Resource Model --- ## Configure and Use the PowerUp Resource Model ### Overview -This new system will create a new optional NET and CPU marketplace which displaces (over time) -the existing staking system and REX market. Under the old model, system token holders -own NET and CPU and may choose to use it themselves, delegate it to others, or make -it available for others to rent using the REX market. Under this new model, the chain -owns almost all NET and CPU resources and the only way to access these resources is -through the new `powerup` action. It channels fees to the REX pool to enable token holders -to profit off the new market. +The PowerUp Resource Model creates a new NET and CPU marketplace which renders obsolete the existing staking mechanism and REX market. Under the old model, EOS token holders own NET and CPU and may choose to use it themselves, delegate it to others, or make it available for others to rent using the REX market. With the new model, the chain owns almost all NET and CPU resources and the only way to access these resources is through the new `powerup` action. Equally important, the PowerUp Resource Model channels fees to the REX pool to enable token holders to profit off the new market. ### Configuration -#### Definitions - -##### Configuration - ```c++ // configure the `powerup` market. The market becomes available the first time this action is invoked void cfgpowerup( powerup_config& args ); @@ -70,9 +59,10 @@ struct powerup_config { }; ``` -#### State +#### Definitions Definitions useful to help understand the configuration, including defaults: + ```c++ inline constexpr int64_t powerup_frac = 1'000'000'000'000'000ll; // 1.0 = 10^15 @@ -126,7 +116,7 @@ struct powerup_state { }; ``` -#### Preparation for Upgrade +### Preparation for Upgrade 1. Build [eos-system-contracts](https://github.com/eosnetworkfoundation/eos-system-contracts) with `powerup` code. 2. Deploy eosio.system contract to `eosio`. @@ -136,7 +126,7 @@ struct powerup_state { #### Configure PowerUp -##### Config file +##### Config File **config.json** @@ -174,7 +164,7 @@ struct powerup_state { cleos push action eosio cfgpowerup "[`cat ./config.json`]" -p eosio ``` -##### Check state +#### Check state ```sh cleos get table eosio 0 powup.state @@ -227,9 +217,9 @@ cleos get table eosio 0 powup.state } ``` -#### Using PowerUp +### Use PowerUp -##### Execute An Order +#### Execute An Order The action to power up an account is `powerup`. It takes a `payer` of the fee and a `receiver` of the resources. The `days` must always match `state.powerup_days`. `net_frac` and `cpu_frac` are the percentage of the resources that you need. The easiest way to caclulate the percentage is to multiple 10^15 (100%) by the desired percentage. For example: 10^15 * 0.01 = 10^13. @@ -250,7 +240,7 @@ You can see how much NET and CPU weight was received as well as the fee by looki *It is worth mentioning that the network being used for the example has not fully transitioned so the available resources are minimal therefore 1% of the resources are quite expensive. As the system continues the transition more resources are available to the `PowerUp` resource model and will become more affordable.* -##### Process Expired Orders +#### Process Expired Orders The resources in loans that expire do not automatically get reclaimed by the system. The expired loans sit in a queue that must be processed. Anyone calling the `powerup` action will help with processing this queue (limited to processing at most two expired loans at a time) so that normally the expired loans will be automatically processed in a timely manner. However, in some cases it may be necessary to manual process expired loans in the queue to make resources available to the system again and thus make prices cheaper. In such a scenario, any account may process up to an arbitrary number of expired loans by calling the `powerupexec` action. From c605bac418a8318052356b0004a9223082984adc Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 2 Feb 2023 21:58:01 +0200 Subject: [PATCH 45/96] update CPU and NET -- take 1 --- docs/01_key-concepts/03_cpu.md | 19 +++++++++++++++++-- docs/01_key-concepts/04_net.md | 15 +++++++++++++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/docs/01_key-concepts/03_cpu.md b/docs/01_key-concepts/03_cpu.md index 1a16c081..3e4de01f 100644 --- a/docs/01_key-concepts/03_cpu.md +++ b/docs/01_key-concepts/03_cpu.md @@ -2,6 +2,21 @@ title: CPU as system resource --- -The system resource CPU provides processing power to blockchain accounts. The amount of CPU an account has is measured in microseconds and it is referred to as `cpu bandwidth` on the `cleos get account` command output. The `cpu bandwidth` represents the amount of processing time an account has at its disposal when actions sent to its contract are executed by the blockchain. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient CPU must be allocated to the account in order for transactions to complete. +CPU, as NET and RAM, is a very important system resource in the EOS blockchain. The system resource CPU provides processing power to blockchain accounts. When the blockchain executes a transaction it consumes CPU and NET, therefore sufficient CPU must be allocated to the payer account for transactions to complete. The amount of CPU an account has is measured in microseconds and it is referred to as `cpu bandwidth` on the `cleos get account` command output. -For more details about resource allocation on the EOS blockchain refer to the [Resource Allocation](./05_system_resource_allocation.md) documentation. +## How Is CPU Calculated + +Before a transaction is prepared for execution, the blockchain makes sure the payer account has enough CPU to cover for the transaction execution. The necessary CPU is calculated by measuring the time for executing it on the node that is actively building the current block. If the account has enough CPU resources the transaction can be executed otherwise it is rejected. For technical details please refer to the following sources: + +- [The defined CPU configuration variables](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L66) +- [The transaction initialization](https://github.com/AntelopeIO/leap/blob/e55669c42dfe4ac112e3072186f3a449936c0c61/libraries/chain/controller.cpp#L1559) +- [The transaction CPU billing](https://github.com/AntelopeIO/leap/blob/e55669c42dfe4ac112e3072186f3a449936c0c61/libraries/chain/controller.cpp#L1577) +- [The check of CPU usage for a transaction](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/transaction_context.cpp#L381) + +## Subjective CPU Billing + + + +## How To Allocated CPU + +For details on how to allocated CPU resources refer to the [Resource Allocation](./05_system_resource_allocation.md) documentation. diff --git a/docs/01_key-concepts/04_net.md b/docs/01_key-concepts/04_net.md index c9da0453..3f58284a 100644 --- a/docs/01_key-concepts/04_net.md +++ b/docs/01_key-concepts/04_net.md @@ -2,6 +2,17 @@ title: NET as system resource --- -NET, as CPU and RAM, is a very important system resource in the EOS blockchain. NET is measured by the byte size of the transactions saved in the blockchain database and it is referred to as `net bandwidth` on the `cleos get account` command output. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient NET must be allocated to the account in order for transactions to complete. +NET, as CPU and RAM, is a very important system resource in the EOS blockchain. When the blockchain executes a transaction it consumes CPU and NET, therefore sufficient NET must be allocated to the payer account for transactions to complete. NET is referred to as `net bandwidth` on the `cleos get account` command output. -For more details about resource allocation on the EOS blockchain refer to the [Resource Allocation](./05_system_resource_allocation.md) documentation. +## How Is NET Calculated + +Before a transaction is prepared for execution, the blockchain makes sure the payer account has enough NET to cover for the transaction execution. The necessary NET is calculated based on the transaction size, that is, the size of the packed transaction as it is stored in the blockchain. If the account has enough NET resources the transaction can be executed otherwise it is rejected. For technical details please refer to the following sources: + +- [The defined NET configuration variables](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L57) +- [The transaction initialization](https://github.com/AntelopeIO/leap/blob/e55669c42dfe4ac112e3072186f3a449936c0c61/libraries/chain/controller.cpp#L1559) +- [The transaction NET billing](https://github.com/AntelopeIO/leap/blob/e55669c42dfe4ac112e3072186f3a449936c0c61/libraries/chain/controller.cpp#L1577) +- [The check of NET usage for a transaction](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/transaction_context.cpp#L376) + +## How To Allocated NET + +For details on how to allocated NET resources refer to the [Resource Allocation](./05_system_resource_allocation.md) documentation. From 57eaffae1a26661dd6cef4d3df20590ef737b2bd Mon Sep 17 00:00:00 2001 From: ovi Date: Sat, 4 Feb 2023 18:55:26 +0200 Subject: [PATCH 46/96] resource guide -- take 2 --- README.md | 18 +++--- docs/01_key-concepts/01_system.md | 4 +- docs/01_key-concepts/02_ram.md | 33 ++++++---- docs/01_key-concepts/03_cpu.md | 6 +- docs/01_key-concepts/04_net.md | 4 +- .../05_system_resource_allocation.md | 8 ++- docs/01_key-concepts/07_powerup_model.md | 63 ++++++++++++++++++- docs/04_guides/07_how-to-use-eosio.wrap.md | 2 +- ...o-configure-the-powerup-resource-model.md} | 63 +------------------ 9 files changed, 107 insertions(+), 94 deletions(-) rename docs/04_guides/{08_how-to-configure-use-powerup-resource-model.md => 08_how-to-configure-the-powerup-resource-model.md} (79%) diff --git a/README.md b/README.md index 876f16b9..5b1ea09e 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,15 @@ # EOS system contracts -EOS system contracts are a collection of contracts deployable to an [Antelope](https://github.com/AntelopeIO) blockchain, but specifically designed for the EOS blockchain, which implements a lot of critical functionality that goes beyond what is provided by the base Antelope protocol. +EOS system contracts are a collection of contracts specifically designed for the EOS blockchain, which implements a lot of critical functionality that goes beyond what is provided by the base Antelope protocol, the protocol on which EOS blockchain is built on. The Antelope protocol includes capabilities such as: + * an accounts and permissions system which enables a flexible permission system that allows authorization authority over specific actions in a transaction to be satisfied by the appropriate combination of signatures; * a consensus algorithm to propose and finalize blocks by a set of active block producers that can be arbitrarily selected by privileged smart contracts running on the blockchain; * a basic resource management system that tracks usage of CPU/NET and RAM per account and enforces limits based on per-account quotas that can be adjusted by privileged smart contracts. However, the Antelope protocol itself does not immediately provide: + * a mechanism for multiple accounts to reach consensus on authorization of a proposed transaction on-chain before executing it; * a consensus mechanism that goes beyond the consensus algorithm to determine how block producers are selected and to align incentives by providing appropriate rewards and punishments to block producers or the entities that get them into that position; * more sophisticated resource management systems that create markets for users to acquire resource rights; @@ -36,6 +38,7 @@ The `main` branch contains the latest state of development; do not use this for [CDT](https://github.com/AntelopeIO/cdt) is required to build contracts. Any operating systems supported by CDT is sufficient to build the system contracts. To build and run the tests as well, [Leap](https://github.com/AntelopeIO/leap) is also required as a dependency, which may have its further restrictions on supported operating systems. + ## Building The build guide below will assume you are running Ubuntu 20.04. However, as mentioned above, other operating systems may also be supported. @@ -66,7 +69,7 @@ For all configurations, you should first `cd` into the directory containing clon Build system contracts with tests using Leap built from source and with installed CDT package: -``` +```shell mkdir build cd build cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=ON -Dleap_DIR="${LEAP_BUILD_PATH}/lib/cmake/leap" .. @@ -78,18 +81,19 @@ make -j $(nproc)
Build system contracts with tests using Leap and CDT both built from source -``` +```shell mkdir build cd build cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=ON -Dcdt_DIR="${CDT_BUILD_PATH}/lib/cmake/cdt" -Dleap_DIR="${LEAP_BUILD_PATH}/lib/cmake/leap" .. make -j $(nproc) ``` +
Build system contracts without tests and with CDT build from source -``` +```shell mkdir build cd build cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=OFF -Dcdt_DIR="${CDT_BUILD_PATH}/lib/cmake/cdt" .. @@ -102,7 +106,7 @@ make -j $(nproc) The following is a list of custom CMake options supported in building the system contracts (default values are shown below): -``` +```text -DBUILD_TESTS=OFF Do not build the tests -DSYSTEM_CONFIGURABLE_WASM_LIMITS=ON Enable use of the CONFIGURABLE_WASM_LIMITS @@ -116,11 +120,11 @@ The following is a list of custom CMake options supported in building the system Assuming you built with `BUILD_TESTS=ON`, you can run the tests. -``` +```shell cd build/tests ctest -j $(nproc) ``` ## License -[MIT](LICENSE) \ No newline at end of file +[MIT](LICENSE) diff --git a/docs/01_key-concepts/01_system.md b/docs/01_key-concepts/01_system.md index a4d31090..77afa28a 100644 --- a/docs/01_key-concepts/01_system.md +++ b/docs/01_key-concepts/01_system.md @@ -10,10 +10,10 @@ As you just learned the relation between a `system account` and a `system contra |Account|Privileged|Has contract|Description| |---|---|---|---| -|eosio|Yes|It contains the `eosio.system` contract|The main system account on an Antelope-based blockchain.| +|eosio|Yes|It contains the `eosio.system` contract|The main system account on the EOS blockchain.| |eosio.msig|Yes|It contains the `eosio.msig` contract|Allows the signing of a multi-sig transaction proposal for later execution if all required parties sign the proposal before the expiration time.| |eosio.wrap|Yes|It contains the `eosio.wrap` contract.|Simplifies block producer superuser actions by making them more readable and easier to audit.| -|eosio.token|No|It contains the `eosio.token` contract.|Defines the structures and actions allowing users to create, issue, and manage tokens on Antelope-based blockchains.| +|eosio.token|No|It contains the `eosio.token` contract.|Defines the structures and actions allowing users to create, issue, and manage tokens on the EOS blockchain.| |eosio.names|No|No|The account which is holding funds from namespace auctions.| |eosio.bpay|No|No|The account that pays the block producers for producing blocks. It assigns 0.25% of the inflation based on the amount of blocks a block producer created in the last 24 hours.| |eosio.prods|No|No|The account representing the union of all current active block producers permissions.| diff --git a/docs/01_key-concepts/02_ram.md b/docs/01_key-concepts/02_ram.md index 7aac6e38..7289efdf 100644 --- a/docs/01_key-concepts/02_ram.md +++ b/docs/01_key-concepts/02_ram.md @@ -6,25 +6,15 @@ title: RAM as system resource RAM is the memory, the storage space, where the blockchain stores data. If your contract needs to store data on the blockchain, like in a database, then it can store it in the blockchain's RAM using either a `multi-index table` or a `singleton`. -### Related documentation articles - -- Multi-index table [reference documentation page](http://docs.eosnetwork.com/cdt/latest/reference/Modules/group__multiindex) - -- Multi-index table [how to documentation page](https://docs.eosnetwork.com/cdt/latest/how-to-guides/multi-index) - -- Singleton [reference documentation page](https://docs.eosnetwork.com/cdt/latest/reference/Classes/classeosio_1_1singleton) - -- Singleton [how to documentation page](https://docs.eosnetwork.com/cdt/latest/how-to-guides/multi-index/how-to-define-a-singleton) - ## RAM High Performance -The Antelope-based blockchains are known for their high performance, which is achieved also because the data stored on the blockchain is using RAM as the storage medium, and thus access to blockchain data is very fast, helping the performance benchmarks to reach levels no other blockchain has been able to. +The EOS blockchain is known for its high performance, which is achieved also because the data stored on the blockchain is using RAM as the storage medium, and thus access to blockchain data is very fast, helping the performance benchmarks to reach levels very few blockchains has been able to. ## RAM Importance RAM is a very important system resource because of the following reasons: -- It is a limited resource, each Antelope-based blockchain can have different policies and rules around RAM; for example the public EOS blockchain started with 64GB of RAM and after that the block producers decided to increase the memory with 1KB per block, thus increasing constantly the supply of RAM for its price to not grow too high due to the increased demand from blockchain applications. +- It is a limited resource, the public EOS blockchain started with 64GB of RAM and after that the block producers decided to increase the memory with 1KB per block, thus increasing constantly the supply of RAM for its price to not grow too high due to the increased demand from blockchain applications. - RAM is used in executing many actions sent to the blockchain; creating a new account action, for example, it needs to store in the blockchain memory the new account's information; also when an account accepts a new type of token a new record has to be created, somewhere in the blockchain memory, that holds the balance of the new token accepted, and that memory, the storage space on the blockchain, has to be purchased either by the account that transfers the token or by the account that accepts the new token type. @@ -33,6 +23,23 @@ RAM is a very important system resource because of the following reasons: - A portion of the occupied RAM is freed by the smart contract. - More RAM is allocated to the smart contract account through the RAM buying process. -RAM is a scarce resource priced according to the unique Bancor liquidity algorithm which is implemented in the system contract [here](https://docs.eosnetwork.com/system-contracts/latest/reference/Classes/structeosiosystem_1_1exchange__state). +The price o RAM is calculated according to the unique Bancor liquidity algorithm which is implemented in the system contract [here](https://docs.eosnetwork.com/system-contracts/latest/reference/Classes/structeosiosystem_1_1exchange__state). The RAM system resource must be purchased using the system token. Refer to the [cleos manual](https://docs.eosnetwork.com/leap/latest/cleos/how-to-guides/how-to-buy-ram) to learn how to buy RAM via the command line interface. + +## How Is RAM Calculated + +The necessary RAM needed for a smart contract to store its data is calculated from the used blockchain state. There are also extra amounts added in for various things so it is not an exact bill of used computer RAM. For more details consult the following pointers in the source code: + +- [Fixed overhead shared vector RAM bytes](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L108) +- [Overhead per row per index RAM bytes](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L109) +- [Overhead per account RAM bytes](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L110) +- [Setcode RAM bytes multiplier](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L111) +- [RAM usage update function](https://github.com/AntelopeIO/leap/blob/9f0679bd0a42d6c24a966bb79de6d8c0591872a5/libraries/chain/apply_context.cpp#L725) + +## Related documentation articles + +- Multi-index table [reference documentation page](http://docs.eosnetwork.com/cdt/latest/reference/Modules/group__multiindex) +- Multi-index table [how to documentation page](https://docs.eosnetwork.com/cdt/latest/how-to-guides/multi-index) +- Singleton [reference documentation page](https://docs.eosnetwork.com/cdt/latest/reference/Classes/classeosio_1_1singleton) +- Singleton [how to documentation page](https://docs.eosnetwork.com/cdt/latest/how-to-guides/multi-index/how-to-define-a-singleton) diff --git a/docs/01_key-concepts/03_cpu.md b/docs/01_key-concepts/03_cpu.md index 3e4de01f..1dbf61b3 100644 --- a/docs/01_key-concepts/03_cpu.md +++ b/docs/01_key-concepts/03_cpu.md @@ -6,16 +6,18 @@ CPU, as NET and RAM, is a very important system resource in the EOS blockchain. ## How Is CPU Calculated -Before a transaction is prepared for execution, the blockchain makes sure the payer account has enough CPU to cover for the transaction execution. The necessary CPU is calculated by measuring the time for executing it on the node that is actively building the current block. If the account has enough CPU resources the transaction can be executed otherwise it is rejected. For technical details please refer to the following sources: +When a transaction is prepared for execution, the blockchain makes sure the payer account has enough CPU to cover for the transaction execution. The necessary CPU is calculated by measuring the time for executing it on the node that is actively building the current block. If the account has enough CPU resources the transaction can be executed otherwise it is rejected. For technical details please refer to the following sources: -- [The defined CPU configuration variables](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L66) +- [The CPU configuration variables](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L66) - [The transaction initialization](https://github.com/AntelopeIO/leap/blob/e55669c42dfe4ac112e3072186f3a449936c0c61/libraries/chain/controller.cpp#L1559) - [The transaction CPU billing](https://github.com/AntelopeIO/leap/blob/e55669c42dfe4ac112e3072186f3a449936c0c61/libraries/chain/controller.cpp#L1577) - [The check of CPU usage for a transaction](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/transaction_context.cpp#L381) ## Subjective CPU Billing +Subjective billing is an optional feature of the EOS blockchain that lets nodes bill account resources locally in their own node without sharing the billing with the rest of the network. It has, since its introduction, benefited the adopting nodes because it reduced node CPU usage by almost 90%. On the other side, sometimes, it results in failing transactions or lost transactions. As a developer you should be aware that when a smart contract code uses a "check" function, like `assert()` or `check()`, to verify data, it can trigger transaction failure and thus can lead to subjective billing issues. One alternative is to assert or check earlier in a contract’s execution to reduce the billing applied. Or as long as the lack of an error message does not affect user experience, some contracts may also benefit from replacing some asserts and checks with return statements to ensure their transactions succeed and are billed objectively on-chain. +More details about subjective billing can be found in [Introduction to subjective billing and lost transactions](https://eosnetwork.com/blog/api-plus-an-introduction-to-subjective-billing-and-lost-transactions/) article. ## How To Allocated CPU diff --git a/docs/01_key-concepts/04_net.md b/docs/01_key-concepts/04_net.md index 3f58284a..12a33460 100644 --- a/docs/01_key-concepts/04_net.md +++ b/docs/01_key-concepts/04_net.md @@ -6,9 +6,9 @@ NET, as CPU and RAM, is a very important system resource in the EOS blockchain. ## How Is NET Calculated -Before a transaction is prepared for execution, the blockchain makes sure the payer account has enough NET to cover for the transaction execution. The necessary NET is calculated based on the transaction size, that is, the size of the packed transaction as it is stored in the blockchain. If the account has enough NET resources the transaction can be executed otherwise it is rejected. For technical details please refer to the following sources: +When a transaction is prepared for execution, the blockchain makes sure the payer account has enough NET to cover for the transaction execution. The necessary NET is calculated based on the transaction size, that is, the size of the packed transaction as it is stored in the blockchain. If the account has enough NET resources the transaction can be executed otherwise it is rejected. For technical details please refer to the following sources: -- [The defined NET configuration variables](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L57) +- [The NET configuration variables](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L57) - [The transaction initialization](https://github.com/AntelopeIO/leap/blob/e55669c42dfe4ac112e3072186f3a449936c0c61/libraries/chain/controller.cpp#L1559) - [The transaction NET billing](https://github.com/AntelopeIO/leap/blob/e55669c42dfe4ac112e3072186f3a449936c0c61/libraries/chain/controller.cpp#L1577) - [The check of NET usage for a transaction](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/transaction_context.cpp#L376) diff --git a/docs/01_key-concepts/05_system_resource_allocation.md b/docs/01_key-concepts/05_system_resource_allocation.md index 6ee096ce..c6df437d 100644 --- a/docs/01_key-concepts/05_system_resource_allocation.md +++ b/docs/01_key-concepts/05_system_resource_allocation.md @@ -4,7 +4,7 @@ title: System Resource Allocation ## System Resources -Antelope-based blockchains work with three system resources: +EOS Blockchain work with three system resources: * [RAM](02_ram.md) * [CPU](03_cpu.md) @@ -25,4 +25,8 @@ When an account uses the rented resources, the amount that can be used in one tr ### Buy RAM -The RAM resource must be bought using the system token. Refer to the [cleos manual](https://docs.eosnetwork.com/leap/latest/cleos/how-to-guides/how-to-buy-ram) to learn how to do it via the command line interface. When an account consumes all its allocated RAM can not store any additional information on the blockchain database until it frees some of the occupied RAM or more RAM is allocated to the account through the RAM buying process. +The RAM resource must be bought using the system token. + +Refer to the [cleos manual](https://docs.eosnetwork.com/leap/latest/cleos/how-to-guides/how-to-buy-ram) to learn how to do it via the command line interface. When an account consumes all its allocated RAM can not store any additional information on the blockchain database until it frees some of the occupied RAM or more RAM is allocated to the account through the RAM buying process. + +Another way to buy RAM is through an EOS wallet that supports this feature. diff --git a/docs/01_key-concepts/07_powerup_model.md b/docs/01_key-concepts/07_powerup_model.md index a16521e6..25fabd95 100644 --- a/docs/01_key-concepts/07_powerup_model.md +++ b/docs/01_key-concepts/07_powerup_model.md @@ -1,7 +1,64 @@ --- -title: PowerUp Model +title: How To Use The PowerUp Model --- -## What Is PowerUp Model +## Execute An Order -## How To Use The PowerUp Model +The action to power up an account is `powerup`. It takes a `payer` of the fee and a `receiver` of the resources. The `days` must always match `state.powerup_days`. The `net_frac` and `cpu_frac` are the percentage of the resources that you need. The easiest way to calculate the percentage is to multiple 10^15 (100%) by the desired percentage. For example: 10^15 * 0.01 = 10^13. + +```sh +cleos push action eosio powerup '[user, user, 1, 10000000000000, 10000000000000, "1000.0000 TST"]' -p user +``` + +```console +executed transaction: 82b7124601612b371b812e3bf65cf63bb44616802d3cd33a2c0422b58399f54f 144 bytes 521 us +# eosio <= eosio::powerup {"payer":"user","receiver":"user","days":1,"net_frac":"10000000000000","cpu_frac":"10000000000000","... +# eosio.token <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 TST","memo":"transfer from user to eosio.rex"} +# eosio.reserv <= eosio.reserv::powupresult {"fee":"999.9901 TST","powup_net_weight":"16354","powup_cpu_weight":"65416"} +# user <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 TST","memo":"transfer from user to eosio.rex"} +# eosio.rex <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 TST","memo":"transfer from user to eosio.rex"} +``` + +You can see how much NET and CPU weight was received as well as the fee by looking at the `eosio.reserv::powupresult` informational action. + +## Process Expired Orders + +The resources in loans that expire do not automatically get reclaimed by the system. The expired loans sit in a queue that must be processed. Anyone calling the `powerup` action will help with processing this queue (limited to processing at most two expired loans at a time) so that normally the expired loans will be automatically processed in a timely manner. However, in some cases it may be necessary to manual process expired loans in the queue to make resources available to the system again and thus make prices cheaper. In such a scenario, any account may process up to an arbitrary number of expired loans by calling the `powerupexec` action. + +The orders table `powup.order` can be viewed by calling: + +```sh +cleos get table eosio 0 powup.order +``` + +```json +{ + "rows": [{ + "version": 0, + "id": 0, + "owner": "user", + "net_weight": 16354, + "cpu_weight": 65416, + "expires": "2020-11-18T13:04:33" + } + ], + "more": false, + "next_key": "" +} +``` + +Example `powerupexec` call: + +```sh +cleos push action eosio powerupexec '[user, 2]' -p user +``` + +```console +executed transaction: 93ab4ac900a7902e4e59e5e925e8b54622715328965150db10774aa09855dc98 104 bytes 363 us +# eosio <= eosio::powerupexec {"user":"user","max":2} +warning: transaction executed locally, but may not be confirmed by the network yet ] +``` + +## Alternative Ways To Use The PowerUp Model + +You can also use the PowerUp model to power your account with CPU and NET, using an EOS wallet that supports the PowerUp function. diff --git a/docs/04_guides/07_how-to-use-eosio.wrap.md b/docs/04_guides/07_how-to-use-eosio.wrap.md index 955f9e7b..dea01d81 100644 --- a/docs/04_guides/07_how-to-use-eosio.wrap.md +++ b/docs/04_guides/07_how-to-use-eosio.wrap.md @@ -638,7 +638,7 @@ If the two hashes match then the local WebAssembly code is the one deployed on t ## 2.1 Example: Updating owner authority of an arbitrary account -This example will demonstrate how to use the deployed eosio.wrap contract together with the eosio.msig contract to allow a greater than two-thirds supermajority of block producers of an Antelope blockchain to change the owner authority of an arbitrary account. The example will use cleos: in particular, the `cleos multisig` command, the `cleos set account permission` sub-command, and the `cleos wrap exec` sub-command. However, the guide also demonstrates what to do if the `cleos wrap exec` sub-command is not available. +This example will demonstrate how to use the deployed eosio.wrap contract together with the eosio.msig contract to allow a greater than two-thirds supermajority of block producers of the EOS blockchain to change the owner authority of an arbitrary account. The example will use cleos: in particular, the `cleos multisig` command, the `cleos set account permission` sub-command, and the `cleos wrap exec` sub-command. However, the guide also demonstrates what to do if the `cleos wrap exec` sub-command is not available. This guide assumes that there are 21 active block producers on the chain with account names: `blkproducera`, `blkproducerb`, ..., `blkproduceru`. Block producer `blkproducera` will act as the lead block producer handling the proposal of the transaction. diff --git a/docs/04_guides/08_how-to-configure-use-powerup-resource-model.md b/docs/04_guides/08_how-to-configure-the-powerup-resource-model.md similarity index 79% rename from docs/04_guides/08_how-to-configure-use-powerup-resource-model.md rename to docs/04_guides/08_how-to-configure-the-powerup-resource-model.md index 209f71af..32b43301 100644 --- a/docs/04_guides/08_how-to-configure-use-powerup-resource-model.md +++ b/docs/04_guides/08_how-to-configure-the-powerup-resource-model.md @@ -1,5 +1,5 @@ --- -title: How To Configure And Use PowerUp Resource Model +title: How To Configure The PowerUp Resource Model --- ## Configure and Use the PowerUp Resource Model @@ -216,64 +216,3 @@ cleos get table eosio 0 powup.state "next_key": "" } ``` - -### Use PowerUp - -#### Execute An Order - -The action to power up an account is `powerup`. It takes a `payer` of the fee and a `receiver` of the resources. The `days` must always match `state.powerup_days`. `net_frac` and `cpu_frac` are the percentage of the resources that you need. The easiest way to caclulate the percentage is to multiple 10^15 (100%) by the desired percentage. For example: 10^15 * 0.01 = 10^13. - -```sh -cleos push action eosio powerup '[user, user, 1, 10000000000000, 10000000000000, "1000.0000 TST"]' -p user -``` - -```console -executed transaction: 82b7124601612b371b812e3bf65cf63bb44616802d3cd33a2c0422b58399f54f 144 bytes 521 us -# eosio <= eosio::powerup {"payer":"user","receiver":"user","days":1,"net_frac":"10000000000000","cpu_frac":"10000000000000","... -# eosio.token <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 TST","memo":"transfer from user to eosio.rex"} -# eosio.reserv <= eosio.reserv::powupresult {"fee":"999.9901 TST","powup_net_weight":"16354","powup_cpu_weight":"65416"} -# user <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 TST","memo":"transfer from user to eosio.rex"} -# eosio.rex <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 TST","memo":"transfer from user to eosio.rex"} -``` - -You can see how much NET and CPU weight was received as well as the fee by looking at the `eosio.reserv::powupresult` informational action. - -*It is worth mentioning that the network being used for the example has not fully transitioned so the available resources are minimal therefore 1% of the resources are quite expensive. As the system continues the transition more resources are available to the `PowerUp` resource model and will become more affordable.* - -#### Process Expired Orders - -The resources in loans that expire do not automatically get reclaimed by the system. The expired loans sit in a queue that must be processed. Anyone calling the `powerup` action will help with processing this queue (limited to processing at most two expired loans at a time) so that normally the expired loans will be automatically processed in a timely manner. However, in some cases it may be necessary to manual process expired loans in the queue to make resources available to the system again and thus make prices cheaper. In such a scenario, any account may process up to an arbitrary number of expired loans by calling the `powerupexec` action. - -The orders table `powup.order` can be viewed by calling: - -```sh -cleos get table eosio 0 powup.order -``` - -```json -{ - "rows": [{ - "version": 0, - "id": 0, - "owner": "user", - "net_weight": 16354, - "cpu_weight": 65416, - "expires": "2020-11-18T13:04:33" - } - ], - "more": false, - "next_key": "" -} -``` - -Example `powerupexec` call: - -```sh -cleos push action eosio powerupexec '[user, 2]' -p user -``` - -```console -executed transaction: 93ab4ac900a7902e4e59e5e925e8b54622715328965150db10774aa09855dc98 104 bytes 363 us -# eosio <= eosio::powerupexec {"user":"user","max":2} -warning: transaction executed locally, but may not be confirmed by the network yet ] -``` From 430deabfac3fa3a86acf817f1d0eec13e52653e5 Mon Sep 17 00:00:00 2001 From: ovi Date: Sun, 5 Feb 2023 13:41:24 +0200 Subject: [PATCH 47/96] resources guide -- take 3 --- docs/01_key-concepts/02_system_resources.md | 10 ++++++ docs/01_key-concepts/03_cpu.md | 8 +++-- docs/01_key-concepts/04_net.md | 6 ++-- docs/01_key-concepts/{02_ram.md => 05_ram.md} | 16 ++++++++-- .../05_system_resource_allocation.md | 32 ------------------- docs/01_key-concepts/07_powerup_model.md | 14 ++++---- ...to-configure-the-powerup-resource-model.md | 20 ++++++------ docs/index.md | 4 +-- 8 files changed, 51 insertions(+), 59 deletions(-) create mode 100644 docs/01_key-concepts/02_system_resources.md rename docs/01_key-concepts/{02_ram.md => 05_ram.md} (90%) delete mode 100644 docs/01_key-concepts/05_system_resource_allocation.md diff --git a/docs/01_key-concepts/02_system_resources.md b/docs/01_key-concepts/02_system_resources.md new file mode 100644 index 00000000..d17a4cb2 --- /dev/null +++ b/docs/01_key-concepts/02_system_resources.md @@ -0,0 +1,10 @@ +--- +title: System Resources +--- + +The EOS accounts need sufficient system resources to interact with the smart contracts deployed on the blockchain. +The EOS blockchain works with three system resources: + +* [CPU](03_cpu.md) +* [NET](04_net.md) +* [RAM](05_ram.md) diff --git a/docs/01_key-concepts/03_cpu.md b/docs/01_key-concepts/03_cpu.md index 1dbf61b3..bec2f18a 100644 --- a/docs/01_key-concepts/03_cpu.md +++ b/docs/01_key-concepts/03_cpu.md @@ -6,7 +6,9 @@ CPU, as NET and RAM, is a very important system resource in the EOS blockchain. ## How Is CPU Calculated -When a transaction is prepared for execution, the blockchain makes sure the payer account has enough CPU to cover for the transaction execution. The necessary CPU is calculated by measuring the time for executing it on the node that is actively building the current block. If the account has enough CPU resources the transaction can be executed otherwise it is rejected. For technical details please refer to the following sources: +When an account uses the rented CPU, the amount that can be used in one transaction is limited by predefine [maximum CPU](https://docs.eosnetwork.com/cdt/latest/reference/Classes/structeosio_1_1blockchain__parameters#variable-max-transaction-cpu-usage) and [minimum CPU](https://docs.eosnetwork.com/cdt/latest/reference/Classes/structeosio_1_1blockchain__parameters#variable-min-transaction-cpu-usage) limits. Transactions executed by the blockchain contain one or more actions, and each transaction must consume an amount of CPU which is in the limits defined by the aforementioned blockchain settings. + +The blockchain calculates and updates the remaining resources, for the accounts which execute transactions, with each block, before each transaction is executed. When a transaction is prepared for execution, the blockchain makes sure the payer account has enough CPU to cover for the transaction execution. The necessary CPU is calculated by measuring the time for executing the transaction on the node that is actively building the current block. If the account has enough CPU the transaction can be executed otherwise it is rejected. For technical details please refer to the following pointers: - [The CPU configuration variables](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L66) - [The transaction initialization](https://github.com/AntelopeIO/leap/blob/e55669c42dfe4ac112e3072186f3a449936c0c61/libraries/chain/controller.cpp#L1559) @@ -19,6 +21,6 @@ Subjective billing is an optional feature of the EOS blockchain that lets nodes More details about subjective billing can be found in [Introduction to subjective billing and lost transactions](https://eosnetwork.com/blog/api-plus-an-introduction-to-subjective-billing-and-lost-transactions/) article. -## How To Allocated CPU +## How To Rent CPU -For details on how to allocated CPU resources refer to the [Resource Allocation](./05_system_resource_allocation.md) documentation. +For details on how to rent CPU resources refer to the [PowerUp Model](./07_powerup_model.md) documentation. diff --git a/docs/01_key-concepts/04_net.md b/docs/01_key-concepts/04_net.md index 12a33460..abced504 100644 --- a/docs/01_key-concepts/04_net.md +++ b/docs/01_key-concepts/04_net.md @@ -6,7 +6,9 @@ NET, as CPU and RAM, is a very important system resource in the EOS blockchain. ## How Is NET Calculated -When a transaction is prepared for execution, the blockchain makes sure the payer account has enough NET to cover for the transaction execution. The necessary NET is calculated based on the transaction size, that is, the size of the packed transaction as it is stored in the blockchain. If the account has enough NET resources the transaction can be executed otherwise it is rejected. For technical details please refer to the following sources: +When an account uses the allocated NET, the amount that can be used in one transaction is limited by predefine [maximum NET](https://docs.eosnetwork.com/cdt/latest/reference/Classes/structeosio_1_1blockchain__parameters#variable-max-transaction-net-usage) limit. Transactions executed by the blockchain contain one or more actions, and each transaction must consume an amount of NET which is in the limits defined by the aforementioned blockchain settings. + +The blockchain calculates and updates the remaining resources, for the accounts which execute transactions, with each block, before each transaction is executed. When a transaction is prepared for execution, the blockchain makes sure the payer account has enough NET to cover for the transaction execution. The necessary NET is calculated based on the transaction size, that is, the size of the packed transaction as it is stored in the blockchain. If the account has enough NET resources the transaction can be executed otherwise it is rejected. For technical details please refer to the following sources: - [The NET configuration variables](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L57) - [The transaction initialization](https://github.com/AntelopeIO/leap/blob/e55669c42dfe4ac112e3072186f3a449936c0c61/libraries/chain/controller.cpp#L1559) @@ -15,4 +17,4 @@ When a transaction is prepared for execution, the blockchain makes sure the paye ## How To Allocated NET -For details on how to allocated NET resources refer to the [Resource Allocation](./05_system_resource_allocation.md) documentation. +For details on how to allocated NET resources refer to the [PowerUp Model](./07_powerup_model.md) documentation. diff --git a/docs/01_key-concepts/02_ram.md b/docs/01_key-concepts/05_ram.md similarity index 90% rename from docs/01_key-concepts/02_ram.md rename to docs/01_key-concepts/05_ram.md index 7289efdf..9de35a7e 100644 --- a/docs/01_key-concepts/02_ram.md +++ b/docs/01_key-concepts/05_ram.md @@ -21,14 +21,24 @@ RAM is a very important system resource because of the following reasons: - The smart contract can not store any additional information if it consumes all its allocated RAM. To continue to save data in the blockchain database, one, or both of the following conditions must be met: - A portion of the occupied RAM is freed by the smart contract. - - More RAM is allocated to the smart contract account through the RAM buying process. + - More RAM is allocated to the smart contract account through the RAM purchase process. -The price o RAM is calculated according to the unique Bancor liquidity algorithm which is implemented in the system contract [here](https://docs.eosnetwork.com/system-contracts/latest/reference/Classes/structeosiosystem_1_1exchange__state). +## How To Purchase RAM + +The RAM resource must be bought using the system token. + +### Buy RAM With Command Line Interface + +Refer to the [cleos manual](https://docs.eosnetwork.com/leap/latest/cleos/how-to-guides/how-to-buy-ram) to learn how to do it via the command line interface. -The RAM system resource must be purchased using the system token. Refer to the [cleos manual](https://docs.eosnetwork.com/leap/latest/cleos/how-to-guides/how-to-buy-ram) to learn how to buy RAM via the command line interface. +### Buy RAM With EOS Wallet + +Another way to buy RAM is through an EOS wallet that supports this feature. ## How Is RAM Calculated +The price o RAM is calculated according to the unique Bancor liquidity algorithm which is implemented in the system contract [here](https://docs.eosnetwork.com/system-contracts/latest/reference/Classes/structeosiosystem_1_1exchange__state). + The necessary RAM needed for a smart contract to store its data is calculated from the used blockchain state. There are also extra amounts added in for various things so it is not an exact bill of used computer RAM. For more details consult the following pointers in the source code: - [Fixed overhead shared vector RAM bytes](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L108) diff --git a/docs/01_key-concepts/05_system_resource_allocation.md b/docs/01_key-concepts/05_system_resource_allocation.md deleted file mode 100644 index c6df437d..00000000 --- a/docs/01_key-concepts/05_system_resource_allocation.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -title: System Resource Allocation ---- - -## System Resources - -EOS Blockchain work with three system resources: - -* [RAM](02_ram.md) -* [CPU](03_cpu.md) -* [NET](04_net.md) - -## How To Allocate System Resources - -The EOS accounts need sufficient system resources, RAM, CPU and NET, to interact with the smart contracts deployed on the blockchain. - -### Rent NET and CPU - -The CPU and NET system resources are rented by the account owner through the [PowerUp model](./07_powerup_model.md). - -When an account uses the rented resources, the amount that can be used in one transaction is limited by predefine [maximum CPU](https://docs.eosnetwork.com/cdt/latest/reference/Classes/structeosio_1_1blockchain__parameters#variable-max-transaction-cpu-usage), [minimum CPU](https://docs.eosnetwork.com/cdt/latest/reference/Classes/structeosio_1_1blockchain__parameters#variable-min-transaction-cpu-usage), and [maximum NET](https://docs.eosnetwork.com/cdt/latest/reference/Classes/structeosio_1_1blockchain__parameters#variable-max-transaction-net-usage) limits. Transactions executed by the blockchain contain one or more actions, and each transaction must consume an amount of CPU and NET which is in the limits defined by the aforementioned blockchain settings. - -[[info]] -| The blockchain calculates and updates the remaining resources, for the accounts which execute transactions, with each block, before each transaction is executed. - -### Buy RAM - -The RAM resource must be bought using the system token. - -Refer to the [cleos manual](https://docs.eosnetwork.com/leap/latest/cleos/how-to-guides/how-to-buy-ram) to learn how to do it via the command line interface. When an account consumes all its allocated RAM can not store any additional information on the blockchain database until it frees some of the occupied RAM or more RAM is allocated to the account through the RAM buying process. - -Another way to buy RAM is through an EOS wallet that supports this feature. diff --git a/docs/01_key-concepts/07_powerup_model.md b/docs/01_key-concepts/07_powerup_model.md index 25fabd95..29f89b22 100644 --- a/docs/01_key-concepts/07_powerup_model.md +++ b/docs/01_key-concepts/07_powerup_model.md @@ -2,21 +2,21 @@ title: How To Use The PowerUp Model --- -## Execute An Order +## Power Up Your Account -The action to power up an account is `powerup`. It takes a `payer` of the fee and a `receiver` of the resources. The `days` must always match `state.powerup_days`. The `net_frac` and `cpu_frac` are the percentage of the resources that you need. The easiest way to calculate the percentage is to multiple 10^15 (100%) by the desired percentage. For example: 10^15 * 0.01 = 10^13. +To rent CPU and NET you have to power up your account. The action to power up an account is `powerup`. It takes a `payer` of the fee and a `receiver` of the resources. The `days` must always match `state.powerup_days`. The `net_frac` and `cpu_frac` are the percentage of the resources that you need. The easiest way to calculate the percentage is to multiple 10^15 (100%) by the desired percentage. For example: 10^15 * 0.01 = 10^13. ```sh -cleos push action eosio powerup '[user, user, 1, 10000000000000, 10000000000000, "1000.0000 TST"]' -p user +cleos push action eosio powerup '[user, user, 1, 10000000000000, 10000000000000, "1000.0000 EOS"]' -p user ``` ```console executed transaction: 82b7124601612b371b812e3bf65cf63bb44616802d3cd33a2c0422b58399f54f 144 bytes 521 us # eosio <= eosio::powerup {"payer":"user","receiver":"user","days":1,"net_frac":"10000000000000","cpu_frac":"10000000000000","... -# eosio.token <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 TST","memo":"transfer from user to eosio.rex"} -# eosio.reserv <= eosio.reserv::powupresult {"fee":"999.9901 TST","powup_net_weight":"16354","powup_cpu_weight":"65416"} -# user <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 TST","memo":"transfer from user to eosio.rex"} -# eosio.rex <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 TST","memo":"transfer from user to eosio.rex"} +# eosio.token <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 EOS","memo":"transfer from user to eosio.rex"} +# eosio.reserv <= eosio.reserv::powupresult {"fee":"999.9901 EOS","powup_net_weight":"16354","powup_cpu_weight":"65416"} +# user <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 EOS","memo":"transfer from user to eosio.rex"} +# eosio.rex <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 EOS","memo":"transfer from user to eosio.rex"} ``` You can see how much NET and CPU weight was received as well as the fee by looking at the `eosio.reserv::powupresult` informational action. diff --git a/docs/04_guides/08_how-to-configure-the-powerup-resource-model.md b/docs/04_guides/08_how-to-configure-the-powerup-resource-model.md index 32b43301..7aba4ce2 100644 --- a/docs/04_guides/08_how-to-configure-the-powerup-resource-model.md +++ b/docs/04_guides/08_how-to-configure-the-powerup-resource-model.md @@ -137,8 +137,8 @@ struct powerup_state { "current_weight_ratio": 1000000000000000, "decay_secs": 86400, "exponent": 2, - "max_price": "10000000.0000 TST", - "min_price": "0.0000 TST", + "max_price": "10000000.0000 EOS", + "min_price": "0.0000 EOS", "target_timestamp": "2022-01-01T00:00:00.000", "target_weight_ratio": 10000000000000 }, @@ -147,12 +147,12 @@ struct powerup_state { "current_weight_ratio": 1000000000000000, "decay_secs": 86400, "exponent": 2, - "max_price": "10000000.0000 TST", - "min_price": "0.0000 TST", + "max_price": "10000000.0000 EOS", + "min_price": "0.0000 EOS", "target_timestamp": "2022-01-01T00:00:00.000", "target_weight_ratio": 10000000000000 }, - "min_powerup_fee": "0.0001 TST", + "min_powerup_fee": "0.0001 EOS", "powerup_days": 1 } ``` @@ -185,8 +185,8 @@ cleos get table eosio 0 powup.state "target_timestamp": "2022-01-01T00:00:00", "exponent": "2.00000000000000000", "decay_secs": 3600, - "min_price": "0.0000 TST", - "max_price": "10000000.0000 TST", + "min_price": "0.0000 EOS", + "max_price": "10000000.0000 EOS", "utilization": 0, "adjusted_utilization": 0, "utilization_timestamp": "2020-11-16T19:52:50" @@ -202,14 +202,14 @@ cleos get table eosio 0 powup.state "target_timestamp": "2022-01-01T00:00:00", "exponent": "2.00000000000000000", "decay_secs": 3600, - "min_price": "0.0000 TST", - "max_price": "10000000.0000 TST", + "min_price": "0.0000 EOS", + "max_price": "10000000.0000 EOS", "utilization": 0, "adjusted_utilization": 0, "utilization_timestamp": "2020-11-16T19:52:50" }, "powerup_days": 1, - "min_powerup_fee": "0.0001 TST" + "min_powerup_fee": "0.0001 EOS" } ], "more": false, diff --git a/docs/index.md b/docs/index.md index c05d8156..dbd1f6ad 100644 --- a/docs/index.md +++ b/docs/index.md @@ -17,10 +17,10 @@ The `eos-system-contracts` repository contains the system contracts encapsulatin ## Key Concepts Implemented by eosio.system 1. [System](01_key-concepts/01_system.md) -2. [RAM](01_key-concepts/02_ram.md) +2. [System Resources](01_key-concepts/02_system_resources.md) 3. [CPU](01_key-concepts/03_cpu.md) 4. [NET](01_key-concepts/04_net.md) -5. [Resource Allocation](01_key-concepts/05_system_resource_allocation.md) +5. [RAM](01_key-concepts/05_ram.md) 6. [Vote](01_key-concepts/06_vote.md) ## Build and deploy From df22147bf5612a4d802d39947ee47192c4d9e99a Mon Sep 17 00:00:00 2001 From: ovi Date: Sun, 5 Feb 2023 18:06:59 +0200 Subject: [PATCH 48/96] resource guide - take 4 --- docs/01_key-concepts/04_net.md | 4 +- docs/01_key-concepts/05_ram.md | 50 ++++++++++++++++++++++-- docs/01_key-concepts/07_powerup_model.md | 14 +++++-- 3 files changed, 59 insertions(+), 9 deletions(-) diff --git a/docs/01_key-concepts/04_net.md b/docs/01_key-concepts/04_net.md index abced504..8e0b6ef4 100644 --- a/docs/01_key-concepts/04_net.md +++ b/docs/01_key-concepts/04_net.md @@ -15,6 +15,6 @@ The blockchain calculates and updates the remaining resources, for the accounts - [The transaction NET billing](https://github.com/AntelopeIO/leap/blob/e55669c42dfe4ac112e3072186f3a449936c0c61/libraries/chain/controller.cpp#L1577) - [The check of NET usage for a transaction](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/transaction_context.cpp#L376) -## How To Allocated NET +## How To Rent NET -For details on how to allocated NET resources refer to the [PowerUp Model](./07_powerup_model.md) documentation. +For details on how to rent NET resources refer to the [PowerUp Model](./07_powerup_model.md) documentation. diff --git a/docs/01_key-concepts/05_ram.md b/docs/01_key-concepts/05_ram.md index 9de35a7e..4965bc54 100644 --- a/docs/01_key-concepts/05_ram.md +++ b/docs/01_key-concepts/05_ram.md @@ -25,11 +25,55 @@ RAM is a very important system resource because of the following reasons: ## How To Purchase RAM -The RAM resource must be bought using the system token. +The RAM resource must be bought using the system token. The price of RAM is calculated according to the unique Bancor liquidity algorithm which is implemented in the system contract [here](https://docs.eosnetwork.com/system-contracts/latest/reference/Classes/structeosiosystem_1_1exchange__state). + +The quickest way to calculate the price of RAM is the following: + +1. Run the following cleos command, make sure you run it against the mainnet or the testnet of your choice: + + ```shell + cleos get table eosio eosio rammarket + ``` + +2. Observe the output which should look like the following: + + ```text + { + "supply": "10000000000.0000 RAMCORE", + "base": { + "balance": "35044821247 RAM", + "weight": "0.50000000000000000" + }, + "quote": { + "balance": "3158350.8754 EOS", + "weight": "0.50000000000000000" + } + } + ``` + +3. Make note of the `base balance`, in this case is 35044821247 +4. Make note of the `quote balance`, in this case is 3158350.8754 +5. Calculate the price of 1Kib of RAM as `quote balance` * 1024 / `base balance` = 0.0922 EOS ### Buy RAM With Command Line Interface -Refer to the [cleos manual](https://docs.eosnetwork.com/leap/latest/cleos/how-to-guides/how-to-buy-ram) to learn how to do it via the command line interface. +You can buy RAM through cleos command line interface tool. And you can buy either an explicit amount of RAM expressed in bytes or an amount of RAM worth of an explicit amount of EOS. + +### Buy RAM In EOS + +For example the below command buys for account `bob` 0.1 EOS worth of RAM at the current market RAM price. The cost for the RAM and the execution of this transaction is covered by the `alice` account and the transaction is authorized by the `active` key of the `alice` account. + +```shell +cleos system buyram alice bob "0.1 EOS" -p alice@active +``` + +### Buy RAM In Bytes + +For example the below command buys for account `bob` 1000 RAM bytes at the current market RAM price. The cost for the RAM and the execution of this transaction is covered by the `alice` account and the transaction is authorized by the `active` key of the `alice` account. + +```shell +cleos system buyrambytes alice bob "1000" -p alice@active +``` ### Buy RAM With EOS Wallet @@ -37,8 +81,6 @@ Another way to buy RAM is through an EOS wallet that supports this feature. ## How Is RAM Calculated -The price o RAM is calculated according to the unique Bancor liquidity algorithm which is implemented in the system contract [here](https://docs.eosnetwork.com/system-contracts/latest/reference/Classes/structeosiosystem_1_1exchange__state). - The necessary RAM needed for a smart contract to store its data is calculated from the used blockchain state. There are also extra amounts added in for various things so it is not an exact bill of used computer RAM. For more details consult the following pointers in the source code: - [Fixed overhead shared vector RAM bytes](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L108) diff --git a/docs/01_key-concepts/07_powerup_model.md b/docs/01_key-concepts/07_powerup_model.md index 29f89b22..a27e5a6c 100644 --- a/docs/01_key-concepts/07_powerup_model.md +++ b/docs/01_key-concepts/07_powerup_model.md @@ -4,12 +4,20 @@ title: How To Use The PowerUp Model ## Power Up Your Account -To rent CPU and NET you have to power up your account. The action to power up an account is `powerup`. It takes a `payer` of the fee and a `receiver` of the resources. The `days` must always match `state.powerup_days`. The `net_frac` and `cpu_frac` are the percentage of the resources that you need. The easiest way to calculate the percentage is to multiple 10^15 (100%) by the desired percentage. For example: 10^15 * 0.01 = 10^13. +To power up your account means to rent CPU and NET from the PowerUp resource model which is implemented as a smart contract on the blockchain. The action to power up an account is `powerup`. It takes as parameters: + +- The `payer` of the fee, must be a valid EOS account. +- The `receiver` of the resources, must be a valid EOS account. +- The `days` which must always match `state.powerup_days` specified in the [PowerUp configuration settings](https://github.com/eosnetworkfoundation/eos-system-contracts/blob/7cec470b17bd53b8c78465d4cbd889dbaf1baffb/contracts/eosio.system/include/eosio.system/eosio.system.hpp#L588). +- The `net_frac`, and the `cpu_frac` are the percentage of the resources that you need. The easiest way to calculate the percentage is to multiple 10^15 (100%) by the desired percentage. For example: 10^15 * 0.01 = 10^13. +- The `max_payment`, must be expressed in EOS and is the maximum amount the `payer` is willing to pay. ```sh cleos push action eosio powerup '[user, user, 1, 10000000000000, 10000000000000, "1000.0000 EOS"]' -p user ``` +You can see how much NET and CPU weight was received as well as the fee by looking at the `eosio.reserv::powupresult` informational action. + ```console executed transaction: 82b7124601612b371b812e3bf65cf63bb44616802d3cd33a2c0422b58399f54f 144 bytes 521 us # eosio <= eosio::powerup {"payer":"user","receiver":"user","days":1,"net_frac":"10000000000000","cpu_frac":"10000000000000","... @@ -19,7 +27,7 @@ executed transaction: 82b7124601612b371b812e3bf65cf63bb44616802d3cd33a2c0422b583 # eosio.rex <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 EOS","memo":"transfer from user to eosio.rex"} ``` -You can see how much NET and CPU weight was received as well as the fee by looking at the `eosio.reserv::powupresult` informational action. +The PowerUp resource model on EOS blockchain is initialized with `"powerup_days": 1,` which means the maximum period you can rent CPU and NET is 24 hours. If you do not use them in the 24 hours interval the rented CPU and NET will expire. ## Process Expired Orders @@ -61,4 +69,4 @@ warning: transaction executed locally, but may not be confirmed by the network y ## Alternative Ways To Use The PowerUp Model -You can also use the PowerUp model to power your account with CPU and NET, using an EOS wallet that supports the PowerUp function. +You can also use the PowerUp model to power your account with CPU and NET, using an EOS wallet that supports the PowerUp resource model. From 3641819584813dc569a3dcf5bfdde8dceeaa9a94 Mon Sep 17 00:00:00 2001 From: ovi Date: Sun, 5 Feb 2023 18:48:54 +0200 Subject: [PATCH 49/96] improve RAM calculation details --- docs/01_key-concepts/05_ram.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/01_key-concepts/05_ram.md b/docs/01_key-concepts/05_ram.md index 4965bc54..16fca2a2 100644 --- a/docs/01_key-concepts/05_ram.md +++ b/docs/01_key-concepts/05_ram.md @@ -81,10 +81,13 @@ Another way to buy RAM is through an EOS wallet that supports this feature. ## How Is RAM Calculated -The necessary RAM needed for a smart contract to store its data is calculated from the used blockchain state. There are also extra amounts added in for various things so it is not an exact bill of used computer RAM. For more details consult the following pointers in the source code: +The necessary RAM needed for a smart contract to store its data is calculated from the used blockchain state. -- [Fixed overhead shared vector RAM bytes](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L108) +As a developer when you attempt to understand the amount of RAM your smart contract needs you have to pay attention to the data structure underlying the multi-index tables your smart contract instantiates and uses. The data structure underlying one multi-index table defines a row in the table. Each data member of the data structure corresponds with a row cell of the table. Summing the type size of each data member and adding to it the overheads, defined by EOS code, will give you an approximate amount of RAM one multi-index row needs to be stored on the blockchain. On top of this, you will have to also take in consideration if there are any indexes defined on your multi-index table. The overheads defined by the EOS code for multi-index tables, indexes and data structures can be consulted below: + +- [Multi-index RAM bytes overhead](https://github.com/AntelopeIO/leap/blob/f6643e434e8dc304bba742422dd036a6fbc1f039/libraries/chain/include/eosio/chain/contract_table_objects.hpp#L240) - [Overhead per row per index RAM bytes](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L109) +- [Fixed overhead shared vector RAM bytes](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L108) - [Overhead per account RAM bytes](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L110) - [Setcode RAM bytes multiplier](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L111) - [RAM usage update function](https://github.com/AntelopeIO/leap/blob/9f0679bd0a42d6c24a966bb79de6d8c0591872a5/libraries/chain/apply_context.cpp#L725) @@ -92,6 +95,6 @@ The necessary RAM needed for a smart contract to store its data is calculated fr ## Related documentation articles - Multi-index table [reference documentation page](http://docs.eosnetwork.com/cdt/latest/reference/Modules/group__multiindex) -- Multi-index table [how to documentation page](https://docs.eosnetwork.com/cdt/latest/how-to-guides/multi-index) +- Multi-index table [how to documentation page](https://docs.eosnetwork.com/cdt/latest/how-to-guides/multi-index/how-to-define-a-primary-index/) - Singleton [reference documentation page](https://docs.eosnetwork.com/cdt/latest/reference/Classes/classeosio_1_1singleton) - Singleton [how to documentation page](https://docs.eosnetwork.com/cdt/latest/how-to-guides/multi-index/how-to-define-a-singleton) From f7e4cd31aa4a4f329c04171c511cdcb526f0136b Mon Sep 17 00:00:00 2001 From: ovi Date: Sun, 5 Feb 2023 19:04:55 +0200 Subject: [PATCH 50/96] improvement for RAM needed calculation --- docs/01_key-concepts/05_ram.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/01_key-concepts/05_ram.md b/docs/01_key-concepts/05_ram.md index 16fca2a2..b927e21d 100644 --- a/docs/01_key-concepts/05_ram.md +++ b/docs/01_key-concepts/05_ram.md @@ -83,7 +83,7 @@ Another way to buy RAM is through an EOS wallet that supports this feature. The necessary RAM needed for a smart contract to store its data is calculated from the used blockchain state. -As a developer when you attempt to understand the amount of RAM your smart contract needs you have to pay attention to the data structure underlying the multi-index tables your smart contract instantiates and uses. The data structure underlying one multi-index table defines a row in the table. Each data member of the data structure corresponds with a row cell of the table. Summing the type size of each data member and adding to it the overheads, defined by EOS code, will give you an approximate amount of RAM one multi-index row needs to be stored on the blockchain. On top of this, you will have to also take in consideration if there are any indexes defined on your multi-index table. The overheads defined by the EOS code for multi-index tables, indexes and data structures can be consulted below: +As a developer, to understand the amount of RAM your smart contract needs, you have to pay attention to the data structure underlying the multi-index tables your smart contract instantiates and uses. The data structure underlying one multi-index table defines a row in the table. And each data member of the data structure corresponds with a row cell of the table. Summing the type size of each data member and adding to it the overheads, defined by EOS code, will give you an approximate amount of RAM one multi-index row needs to be stored on the blockchain. On top of this, you will have to also take in consideration if there are any indexes defined on your multi-index table. The overheads defined by the EOS code for multi-index tables, indexes and data types can be consulted below: - [Multi-index RAM bytes overhead](https://github.com/AntelopeIO/leap/blob/f6643e434e8dc304bba742422dd036a6fbc1f039/libraries/chain/include/eosio/chain/contract_table_objects.hpp#L240) - [Overhead per row per index RAM bytes](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L109) From 9527dda605a44274ac7f7071eda338be48dc5b98 Mon Sep 17 00:00:00 2001 From: iamveritas Date: Tue, 14 Feb 2023 13:01:41 +0200 Subject: [PATCH 51/96] update according the the resource guide reviewed and approved by the team peers --- docs/01_key-concepts/02_system_resources.md | 22 +++-- docs/01_key-concepts/03_cpu.md | 24 ++--- docs/01_key-concepts/04_net.md | 20 +++-- docs/01_key-concepts/05_ram.md | 98 +++++++++------------ docs/01_key-concepts/06_vote.md | 2 +- docs/01_key-concepts/07_powerup_model.md | 34 ++++--- 6 files changed, 103 insertions(+), 97 deletions(-) diff --git a/docs/01_key-concepts/02_system_resources.md b/docs/01_key-concepts/02_system_resources.md index d17a4cb2..a59e7658 100644 --- a/docs/01_key-concepts/02_system_resources.md +++ b/docs/01_key-concepts/02_system_resources.md @@ -2,9 +2,21 @@ title: System Resources --- -The EOS accounts need sufficient system resources to interact with the smart contracts deployed on the blockchain. -The EOS blockchain works with three system resources: +The EOS blockchain works with three system resources: CPU, NET and RAM. The EOS accounts need sufficient system resources to interact with the smart contracts deployed on the blockchain. -* [CPU](03_cpu.md) -* [NET](04_net.md) -* [RAM](05_ram.md) +* [RAM Resource](./05_ram.md) +* [CPU Resource](./03_cpu.md) +* [NET Resource](./04_net.md) + +To allocate RAM resources to an account you have to [purchase RAM](./05_ram.md#how-to-purchase-ram). +To allocate CPU and NET resources to an account you have to [power up the account](./07_powerup_model.md#power-up-your-account). + +## Resource Cost Estimation + +As a developer if you want to estimate how much CPU and NET a transaction requires for execution, you can employ one of the following methods: + +* Use the `--dry-run` option for the `dune -- cleos push transaction` command. +* Use any tool that can pack a transaction and send it to the blockchain and specify the `--dry-run` option. +* Use the chain API endpoint [`compute_transaction`](https://github.com/AntelopeIO/leap/blob/51c11175e54831474a89a449beea1fb067e3d1e9/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp#L489). + +In all cases, when the transaction is processed, the blockchain node simulates the execution of the transaction and, as a consequence, the state of the blockchain is changed speculatively, which allows for the CPU and NET measurements to be done. However, the transaction is not sent to the blockchain and the caller receives the estimated CPU and NET costs in return. diff --git a/docs/01_key-concepts/03_cpu.md b/docs/01_key-concepts/03_cpu.md index bec2f18a..c1b985a0 100644 --- a/docs/01_key-concepts/03_cpu.md +++ b/docs/01_key-concepts/03_cpu.md @@ -2,25 +2,29 @@ title: CPU as system resource --- -CPU, as NET and RAM, is a very important system resource in the EOS blockchain. The system resource CPU provides processing power to blockchain accounts. When the blockchain executes a transaction it consumes CPU and NET, therefore sufficient CPU must be allocated to the payer account for transactions to complete. The amount of CPU an account has is measured in microseconds and it is referred to as `cpu bandwidth` on the `cleos get account` command output. +As NET and RAM, the CPU resource is a very important system resource in the EOS blockchain. The CPU system resource provides processing power to blockchain accounts. When the blockchain executes a transaction, it consumes CPU and NET. For transactions to complete, sufficient CPU must be allocated to the payer account. The amount of CPU an account has is measured in microseconds and it is referred to as `cpu bandwidth` on the `dune -- cleos get account` command output. ## How Is CPU Calculated -When an account uses the rented CPU, the amount that can be used in one transaction is limited by predefine [maximum CPU](https://docs.eosnetwork.com/cdt/latest/reference/Classes/structeosio_1_1blockchain__parameters#variable-max-transaction-cpu-usage) and [minimum CPU](https://docs.eosnetwork.com/cdt/latest/reference/Classes/structeosio_1_1blockchain__parameters#variable-min-transaction-cpu-usage) limits. Transactions executed by the blockchain contain one or more actions, and each transaction must consume an amount of CPU which is in the limits defined by the aforementioned blockchain settings. +Transactions executed by the blockchain contain one or more actions. Each transaction must consume an amount of CPU within the limits predefined by the minimum and maximum transaction CPU usage values. For EOS blockchain these limits are set in the blockchain's configuration. You can find out these limits by running the following command and consult the `min_transaction_cpu_usage` and the `max_transaction_cpu_usage` which are expressed in microseconds: -The blockchain calculates and updates the remaining resources, for the accounts which execute transactions, with each block, before each transaction is executed. When a transaction is prepared for execution, the blockchain makes sure the payer account has enough CPU to cover for the transaction execution. The necessary CPU is calculated by measuring the time for executing the transaction on the node that is actively building the current block. If the account has enough CPU the transaction can be executed otherwise it is rejected. For technical details please refer to the following pointers: +```shell +dune -- cleos get consensus_parameters +``` -- [The CPU configuration variables](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L66) -- [The transaction initialization](https://github.com/AntelopeIO/leap/blob/e55669c42dfe4ac112e3072186f3a449936c0c61/libraries/chain/controller.cpp#L1559) -- [The transaction CPU billing](https://github.com/AntelopeIO/leap/blob/e55669c42dfe4ac112e3072186f3a449936c0c61/libraries/chain/controller.cpp#L1577) -- [The check of CPU usage for a transaction](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/transaction_context.cpp#L381) +For accounts that execute transactions, the blockchain calculates and updates the remaining resources with each block before each transaction is executed. When a transaction is prepared for execution, the blockchain determines whether the payer account has enough CPU to cover the transaction execution. To calculate the necessary CPU, the node that actively builds the current block measures the time to execute the transaction. If the account has enough CPU, the transaction is executed; otherwise it is rejected. For technical details please refer to the following links: + +* [The CPU configuration variables](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L66) +* [The transaction initialization](https://github.com/AntelopeIO/leap/blob/e55669c42dfe4ac112e3072186f3a449936c0c61/libraries/chain/controller.cpp#L1559) +* [The transaction CPU billing](https://github.com/AntelopeIO/leap/blob/e55669c42dfe4ac112e3072186f3a449936c0c61/libraries/chain/controller.cpp#L1577) +* [The check of CPU usage for a transaction](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/transaction_context.cpp#L381) ## Subjective CPU Billing -Subjective billing is an optional feature of the EOS blockchain that lets nodes bill account resources locally in their own node without sharing the billing with the rest of the network. It has, since its introduction, benefited the adopting nodes because it reduced node CPU usage by almost 90%. On the other side, sometimes, it results in failing transactions or lost transactions. As a developer you should be aware that when a smart contract code uses a "check" function, like `assert()` or `check()`, to verify data, it can trigger transaction failure and thus can lead to subjective billing issues. One alternative is to assert or check earlier in a contract’s execution to reduce the billing applied. Or as long as the lack of an error message does not affect user experience, some contracts may also benefit from replacing some asserts and checks with return statements to ensure their transactions succeed and are billed objectively on-chain. +Subjective billing is an optional feature of the EOS blockchain. It allows nodes to bill account resources locally in their own node without sharing the billing with the rest of the network. Since its introduction, subjective billing benefited the nodes that adopted it because it reduced the node CPU usage by almost 90%. But it can result in failed transactions or lost transactions. Subjective billing can trigger transaction failure when a smart contract code uses a "check" function, like `assert()` or `check()` command to verify data. When this situation occurs, assert or check earlier in the system contract execution to reduce the applied billing. If the lack of an error message does not affect the user experience, a system contract may benefit by replacing some asserts and checks with a return statement. This replacement ensures their transactions succeed and are billed objectively on-chain. -More details about subjective billing can be found in [Introduction to subjective billing and lost transactions](https://eosnetwork.com/blog/api-plus-an-introduction-to-subjective-billing-and-lost-transactions/) article. +Find more details about subjective billing in the [Introduction to subjective billing and lost transactions](https://eosnetwork.com/blog/api-plus-an-introduction-to-subjective-billing-and-lost-transactions/) article. ## How To Rent CPU -For details on how to rent CPU resources refer to the [PowerUp Model](./07_powerup_model.md) documentation. +For details on how to rent CPU resources refer to the [Account Power Up](./07_powerup_model.md#power-up-your-account) section. diff --git a/docs/01_key-concepts/04_net.md b/docs/01_key-concepts/04_net.md index 8e0b6ef4..4efa7172 100644 --- a/docs/01_key-concepts/04_net.md +++ b/docs/01_key-concepts/04_net.md @@ -2,19 +2,23 @@ title: NET as system resource --- -NET, as CPU and RAM, is a very important system resource in the EOS blockchain. When the blockchain executes a transaction it consumes CPU and NET, therefore sufficient NET must be allocated to the payer account for transactions to complete. NET is referred to as `net bandwidth` on the `cleos get account` command output. +As CPU and RAM, the NET resource is an important system resource in the EOS blockchain. When the blockchain executes a transaction, it consumes CPU and NET. Sufficient NET must be allocated to the payer account for transactions to complete. NET is referred to as `net bandwidth` on the `dune -- cleos get account` command output. ## How Is NET Calculated -When an account uses the allocated NET, the amount that can be used in one transaction is limited by predefine [maximum NET](https://docs.eosnetwork.com/cdt/latest/reference/Classes/structeosio_1_1blockchain__parameters#variable-max-transaction-net-usage) limit. Transactions executed by the blockchain contain one or more actions, and each transaction must consume an amount of NET which is in the limits defined by the aforementioned blockchain settings. +Each transaction must consume an amount of NET which can not exceed the predefined maximum transaction NET usage value. For EOS blockchain this limit is set in the blockchain's configuration. You can find out this limit by running the following command and consult the `max_transaction_net_usage` which is expressed in bytes. -The blockchain calculates and updates the remaining resources, for the accounts which execute transactions, with each block, before each transaction is executed. When a transaction is prepared for execution, the blockchain makes sure the payer account has enough NET to cover for the transaction execution. The necessary NET is calculated based on the transaction size, that is, the size of the packed transaction as it is stored in the blockchain. If the account has enough NET resources the transaction can be executed otherwise it is rejected. For technical details please refer to the following sources: +```shell +dune -- cleos get consensus_parameters +``` -- [The NET configuration variables](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L57) -- [The transaction initialization](https://github.com/AntelopeIO/leap/blob/e55669c42dfe4ac112e3072186f3a449936c0c61/libraries/chain/controller.cpp#L1559) -- [The transaction NET billing](https://github.com/AntelopeIO/leap/blob/e55669c42dfe4ac112e3072186f3a449936c0c61/libraries/chain/controller.cpp#L1577) -- [The check of NET usage for a transaction](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/transaction_context.cpp#L376) +For the accounts that execute transactions, the blockchain calculates and updates the remaining resources for each block before each transaction is executed. When a transaction is prepared for execution, the blockchain determines whether the payer account has enough NET to cover the transaction execution. The necessary NET is calculated based on the transaction size, which is the size of the packed transaction as it is stored in the blockchain. If the account has enough NET resources, the transaction can be executed; otherwise it is rejected. For technical details please refer to the following sources: + +* [The NET configuration variables](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L57) +* [The transaction initialization](https://github.com/AntelopeIO/leap/blob/e55669c42dfe4ac112e3072186f3a449936c0c61/libraries/chain/controller.cpp#L1559) +* [The transaction NET billing](https://github.com/AntelopeIO/leap/blob/e55669c42dfe4ac112e3072186f3a449936c0c61/libraries/chain/controller.cpp#L1577) +* [The check of NET usage for a transaction](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/transaction_context.cpp#L376) ## How To Rent NET -For details on how to rent NET resources refer to the [PowerUp Model](./07_powerup_model.md) documentation. +For details on how to rent NET resources refer to the [Account Power Up](./07_powerup_model.md#power-up-your-account) section. diff --git a/docs/01_key-concepts/05_ram.md b/docs/01_key-concepts/05_ram.md index b927e21d..23c29901 100644 --- a/docs/01_key-concepts/05_ram.md +++ b/docs/01_key-concepts/05_ram.md @@ -2,99 +2,87 @@ title: RAM as system resource --- -## What is RAM - -RAM is the memory, the storage space, where the blockchain stores data. If your contract needs to store data on the blockchain, like in a database, then it can store it in the blockchain's RAM using either a `multi-index table` or a `singleton`. +The RAM resource is the memory, the storage space, where the blockchain stores data. If your contract needs to store data on the blockchain, it can store it in the blockchain's RAM as a `multi-index table` or a `singleton`. ## RAM High Performance -The EOS blockchain is known for its high performance, which is achieved also because the data stored on the blockchain is using RAM as the storage medium, and thus access to blockchain data is very fast, helping the performance benchmarks to reach levels very few blockchains has been able to. +Data stored on the EOS blockchain uses RAM as its storage medium. Therefore, access to the blockchain data is highly performant and fast. Its performance benchmarks can reach levels rarely achieved by other blockchains. This ability elevates the EOS blockchain to be a contender for the fastest blockchain worldwide. ## RAM Importance -RAM is a very important system resource because of the following reasons: +RAM is an important system resource because of the following reasons: -- It is a limited resource, the public EOS blockchain started with 64GB of RAM and after that the block producers decided to increase the memory with 1KB per block, thus increasing constantly the supply of RAM for its price to not grow too high due to the increased demand from blockchain applications. +* Ram is a limited resource. The public EOS blockchain started with 64GB of total RAM. After a brief period the block producers decided to increase the memory with 1KB per block. In this way the supply of RAM constantly increases, yet its price accelerates at a slower pace. -- RAM is used in executing many actions sent to the blockchain; creating a new account action, for example, it needs to store in the blockchain memory the new account's information; also when an account accepts a new type of token a new record has to be created, somewhere in the blockchain memory, that holds the balance of the new token accepted, and that memory, the storage space on the blockchain, has to be purchased either by the account that transfers the token or by the account that accepts the new token type. +* The execution of many actions by the blockchain uses RAM. For example, when you create a new account, the new account information is stored in the blockchain's RAM. Also, when an account accepts a token which it did not hold before, a new record has to be created, that holds the balance of the newly accepted token. The blockchain memory has to be purchased either by the account that transfers the tokens or by the account that accepts the new token type. -- The smart contract can not store any additional information if it consumes all its allocated RAM. To continue to save data in the blockchain database, one, or both of the following conditions must be met: +* If a smart contract consumes all of its allocated RAM, it cannot store any additional information. To continue to save data in the blockchain database, one or both of the following conditions must be met: - - A portion of the occupied RAM is freed by the smart contract. - - More RAM is allocated to the smart contract account through the RAM purchase process. + * A portion of the occupied RAM is freed by the smart contract. + * More RAM is allocated to the smart contract account through the RAM purchase process. ## How To Purchase RAM -The RAM resource must be bought using the system token. The price of RAM is calculated according to the unique Bancor liquidity algorithm which is implemented in the system contract [here](https://docs.eosnetwork.com/system-contracts/latest/reference/Classes/structeosiosystem_1_1exchange__state). +The RAM resource must be bought with the `EOS` system token. The price of RAM is calculated according to the unique Bancor liquidity algorithm that is implemented in the system contract. -The quickest way to calculate the price of RAM is the following: +The quickest way to calculate the price of RAM: -1. Run the following cleos command, make sure you run it against the mainnet or the testnet of your choice: +1. Run the following dune command: (**Note:** Make sure you run it against the mainnet or the testnet of your choice.) - ```shell - cleos get table eosio eosio rammarket - ``` + ```shell + dune -- cleos get table eosio eosio rammarket + ``` -2. Observe the output which should look like the following: +2. Observe the output which should look like the sample below: - ```text - { - "supply": "10000000000.0000 RAMCORE", - "base": { - "balance": "35044821247 RAM", - "weight": "0.50000000000000000" - }, - "quote": { - "balance": "3158350.8754 EOS", - "weight": "0.50000000000000000" + ```text + { + "supply": "10000000000.0000 RAMCORE", + "base": { + "balance": "35044821247 RAM", + "weight": "0.50000000000000000" + }, + "quote": { + "balance": "3158350.8754 EOS", + "weight": "0.50000000000000000" + } } - } - ``` + ``` -3. Make note of the `base balance`, in this case is 35044821247 -4. Make note of the `quote balance`, in this case is 3158350.8754 -5. Calculate the price of 1Kib of RAM as `quote balance` * 1024 / `base balance` = 0.0922 EOS +3. Make note of the `base balance`, in this case it is 35044821247. +4. Make note of the `quote balance`, in this case it is 3158350.8754. +5. Calculate the price of 1Kib of RAM as `quote balance` * 1024 / `base balance` = 0.0922 EOS. ### Buy RAM With Command Line Interface -You can buy RAM through cleos command line interface tool. And you can buy either an explicit amount of RAM expressed in bytes or an amount of RAM worth of an explicit amount of EOS. +You can buy RAM through the dune command line interface tool. You can buy either an explicit amount of RAM expressed in bytes or an amount of RAM worth an explicit amount of EOS. ### Buy RAM In EOS -For example the below command buys for account `bob` 0.1 EOS worth of RAM at the current market RAM price. The cost for the RAM and the execution of this transaction is covered by the `alice` account and the transaction is authorized by the `active` key of the `alice` account. +For example, the command below buys for account `bob` 0.1 EOS worth of RAM at the current market RAM price. The cost for the RAM and the execution of this transaction is covered by the `alice` account and the transaction is authorized by the `active` key of the `alice` account. ```shell -cleos system buyram alice bob "0.1 EOS" -p alice@active +dune -- cleos system buyram alice bob "0.1 EOS" -p alice@active ``` ### Buy RAM In Bytes -For example the below command buys for account `bob` 1000 RAM bytes at the current market RAM price. The cost for the RAM and the execution of this transaction is covered by the `alice` account and the transaction is authorized by the `active` key of the `alice` account. +For example, the command below buys for account `bob` 1000 RAM bytes at the current market RAM price. The cost for the RAM and the execution of this transaction is covered by the `alice` account and the transaction is authorized by the `active` key of the `alice` account. ```shell -cleos system buyrambytes alice bob "1000" -p alice@active +dune -- cleos system buyrambytes alice bob "1000" -p alice@active ``` -### Buy RAM With EOS Wallet - -Another way to buy RAM is through an EOS wallet that supports this feature. - ## How Is RAM Calculated The necessary RAM needed for a smart contract to store its data is calculated from the used blockchain state. -As a developer, to understand the amount of RAM your smart contract needs, you have to pay attention to the data structure underlying the multi-index tables your smart contract instantiates and uses. The data structure underlying one multi-index table defines a row in the table. And each data member of the data structure corresponds with a row cell of the table. Summing the type size of each data member and adding to it the overheads, defined by EOS code, will give you an approximate amount of RAM one multi-index row needs to be stored on the blockchain. On top of this, you will have to also take in consideration if there are any indexes defined on your multi-index table. The overheads defined by the EOS code for multi-index tables, indexes and data types can be consulted below: - -- [Multi-index RAM bytes overhead](https://github.com/AntelopeIO/leap/blob/f6643e434e8dc304bba742422dd036a6fbc1f039/libraries/chain/include/eosio/chain/contract_table_objects.hpp#L240) -- [Overhead per row per index RAM bytes](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L109) -- [Fixed overhead shared vector RAM bytes](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L108) -- [Overhead per account RAM bytes](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L110) -- [Setcode RAM bytes multiplier](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L111) -- [RAM usage update function](https://github.com/AntelopeIO/leap/blob/9f0679bd0a42d6c24a966bb79de6d8c0591872a5/libraries/chain/apply_context.cpp#L725) - -## Related documentation articles +As a developer, to understand the amount of RAM your smart contract needs, pay attention to the data structure underlying the multi-index tables your smart contract instantiates and uses. The data structure underlying one multi-index table defines a row in the table. Each data member of the data structure corresponds with a row cell of the table. +To approximate the amount of RAM one multi-index row needs to store on the blockchain, you have to add the size of the type of each data member and the memory overheads for each of the defined indexes, if any. Find below the overheads defined by the EOS code for multi-index tables, indexes, and data types: -- Multi-index table [reference documentation page](http://docs.eosnetwork.com/cdt/latest/reference/Modules/group__multiindex) -- Multi-index table [how to documentation page](https://docs.eosnetwork.com/cdt/latest/how-to-guides/multi-index/how-to-define-a-primary-index/) -- Singleton [reference documentation page](https://docs.eosnetwork.com/cdt/latest/reference/Classes/classeosio_1_1singleton) -- Singleton [how to documentation page](https://docs.eosnetwork.com/cdt/latest/how-to-guides/multi-index/how-to-define-a-singleton) +* [Multi-index RAM bytes overhead](https://github.com/AntelopeIO/leap/blob/f6643e434e8dc304bba742422dd036a6fbc1f039/libraries/chain/include/eosio/chain/contract_table_objects.hpp#L240) +* [Overhead per row per index RAM bytes](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L109) +* [Fixed overhead shared vector RAM bytes](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L108) +* [Overhead per account RAM bytes](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L110) +* [Setcode RAM bytes multiplier](https://github.com/AntelopeIO/leap/blob/a4c29608472dd195d36d732052784aadc3a779cb/libraries/chain/include/eosio/chain/config.hpp#L111) +* [RAM usage update function](https://github.com/AntelopeIO/leap/blob/9f0679bd0a42d6c24a966bb79de6d8c0591872a5/libraries/chain/apply_context.cpp#L725) \ No newline at end of file diff --git a/docs/01_key-concepts/06_vote.md b/docs/01_key-concepts/06_vote.md index f66076a2..6635bb97 100644 --- a/docs/01_key-concepts/06_vote.md +++ b/docs/01_key-concepts/06_vote.md @@ -4,4 +4,4 @@ title: Voting on EOS blockchain The EOS blockchain is kept alive by nodes which are interconnected between each other, communicating with each other via peer to peer protocols. Some of these nodes are elected, via a voting process, by the token holders to be producer nodes. They produce blocks, validate them and reach consensus on what transactions are allowed in each block, their order, and what blocks are finalized and stored forever in the blockchain state. This way the governance, the mechanism by which collective decisions are made, of the blockchain is achieved through the 21 active block producers which are appointed by token holders' votes. It is the 21 active block producers which continuously advancing the blockchain by creating blocks, and securing them by validating them, and reaching consensus. Consensus is reached when 2/3+1 active block producers agree on validity of a block, that is all transactions contained in it and their order. The 21 producers is the default value however it can be configured to be higher or smaller to meet each business case requirements. -The 21 block producers are elected through the voting process. Each EOS token holder that wants to vote for one or up to 30 block producers must stake their tokens. The more tokens are stake the more voting power. The voting power of one account is proportional with the amount of tokens staked by that account versus the total amount of tokens staked by whole accounts that stake their tokens. \ No newline at end of file +The 21 block producers are elected through the voting process. Each EOS token holder that wants to vote for one or up to 30 block producers must stake their tokens. The more tokens are stake the more voting power. The voting power of one account is proportional with the amount of tokens staked by that account versus the total amount of tokens staked by whole accounts that stake their tokens. diff --git a/docs/01_key-concepts/07_powerup_model.md b/docs/01_key-concepts/07_powerup_model.md index a27e5a6c..039d15d4 100644 --- a/docs/01_key-concepts/07_powerup_model.md +++ b/docs/01_key-concepts/07_powerup_model.md @@ -4,19 +4,19 @@ title: How To Use The PowerUp Model ## Power Up Your Account -To power up your account means to rent CPU and NET from the PowerUp resource model which is implemented as a smart contract on the blockchain. The action to power up an account is `powerup`. It takes as parameters: +To power up an account is a technique to rent CPU and NET resources from the PowerUp resource model. A smart contract implements this model on the blockchain and allocates these resources to the account of your choice. The action to power up an account is `powerup`. It takes as parameters: -- The `payer` of the fee, must be a valid EOS account. -- The `receiver` of the resources, must be a valid EOS account. -- The `days` which must always match `state.powerup_days` specified in the [PowerUp configuration settings](https://github.com/eosnetworkfoundation/eos-system-contracts/blob/7cec470b17bd53b8c78465d4cbd889dbaf1baffb/contracts/eosio.system/include/eosio.system/eosio.system.hpp#L588). -- The `net_frac`, and the `cpu_frac` are the percentage of the resources that you need. The easiest way to calculate the percentage is to multiple 10^15 (100%) by the desired percentage. For example: 10^15 * 0.01 = 10^13. -- The `max_payment`, must be expressed in EOS and is the maximum amount the `payer` is willing to pay. +* The `payer` of the fee, must be a valid EOS account. +* The `receiver` of the resources, must be a valid EOS account. +* The `days` which must always match `state.powerup_days` specified in the [PowerUp configuration settings](https://github.com/eosnetworkfoundation/eos-system-contracts/blob/7cec470b17bd53b8c78465d4cbd889dbaf1baffb/contracts/eosio.system/include/eosio.system/eosio.system.hpp#L588). +* The `net_frac`, and the `cpu_frac` are the percentage of the resources that you need. The easiest way to calculate the percentage is to multiple 10^15 (100%) by the desired percentage. For example: 10^15 * 0.01 = 10^13. +* The `max_payment`, must be expressed in EOS and is the maximum amount the `payer` is willing to pay. ```sh -cleos push action eosio powerup '[user, user, 1, 10000000000000, 10000000000000, "1000.0000 EOS"]' -p user +dune -- cleos push action eosio powerup '[user, user, 1, 10000000000000, 10000000000000, "1000.0000 EOS"]' -p user ``` -You can see how much NET and CPU weight was received as well as the fee by looking at the `eosio.reserv::powupresult` informational action. +To view the received NET and CPU weight as well as the amount of the fee, check the `eosio.reserv::powupresult` returned by the action, which should look similar to the one below: ```console executed transaction: 82b7124601612b371b812e3bf65cf63bb44616802d3cd33a2c0422b58399f54f 144 bytes 521 us @@ -27,16 +27,18 @@ executed transaction: 82b7124601612b371b812e3bf65cf63bb44616802d3cd33a2c0422b583 # eosio.rex <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 EOS","memo":"transfer from user to eosio.rex"} ``` -The PowerUp resource model on EOS blockchain is initialized with `"powerup_days": 1,` which means the maximum period you can rent CPU and NET is 24 hours. If you do not use them in the 24 hours interval the rented CPU and NET will expire. +The PowerUp resource model on the EOS blockchain is initialized with `"powerup_days": 1,`. This setting permits the maximum period to rent CPU and NET for 24 hours. If you do not use the resources within the 24 hour interval, the rented CPU and NET expires. -## Process Expired Orders +### Process Expired Orders -The resources in loans that expire do not automatically get reclaimed by the system. The expired loans sit in a queue that must be processed. Anyone calling the `powerup` action will help with processing this queue (limited to processing at most two expired loans at a time) so that normally the expired loans will be automatically processed in a timely manner. However, in some cases it may be necessary to manual process expired loans in the queue to make resources available to the system again and thus make prices cheaper. In such a scenario, any account may process up to an arbitrary number of expired loans by calling the `powerupexec` action. +The resources in loans that expire are not automatically reclaimed by the system. The expired loans remain in a queue that must be processed. -The orders table `powup.order` can be viewed by calling: +Any calls to the `powerup` action does process also this queue (limited to two expired loans at a time). Therefore, the expired loans are automatically processed in a timely manner. Sometimes, it may be necessary to manually process expired loans in the queue to release resources back to the system, which reduces prices. Therefore, any account may process up to an arbitrary number of expired loans if it calls the `powerupexec` action. + +To view the orders table `powup.order` execute the following command: ```sh -cleos get table eosio 0 powup.order +dune -- cleos get table eosio 0 powup.order ``` ```json @@ -58,7 +60,7 @@ cleos get table eosio 0 powup.order Example `powerupexec` call: ```sh -cleos push action eosio powerupexec '[user, 2]' -p user +dune -- cleos push action eosio powerupexec '[user, 2]' -p user ``` ```console @@ -66,7 +68,3 @@ executed transaction: 93ab4ac900a7902e4e59e5e925e8b54622715328965150db10774aa098 # eosio <= eosio::powerupexec {"user":"user","max":2} warning: transaction executed locally, but may not be confirmed by the network yet ] ``` - -## Alternative Ways To Use The PowerUp Model - -You can also use the PowerUp model to power your account with CPU and NET, using an EOS wallet that supports the PowerUp resource model. From 92c3fce237f3a0b185aac7655f4c021f0090889a Mon Sep 17 00:00:00 2001 From: Luis Date: Fri, 10 Mar 2023 16:39:13 -0500 Subject: [PATCH 52/96] remove eos.io references --- docs/01_key-concepts/03_cpu.md | 2 +- docs/01_key-concepts/04_net.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/01_key-concepts/03_cpu.md b/docs/01_key-concepts/03_cpu.md index f094beb7..2d20bceb 100644 --- a/docs/01_key-concepts/03_cpu.md +++ b/docs/01_key-concepts/03_cpu.md @@ -5,5 +5,5 @@ content_title: CPU as system resource The system resource CPU provides processing power to blockchain accounts. The amount of CPU an account has is measured in microseconds and it is referred to as `cpu bandwidth` on the `cleos get account` command output. The `cpu bandwidth` represents the amount of processing time an account has at its disposal when actions sent to its contract are executed by the blockchain. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient CPU must be staked in order for transactions to complete. For more details about staking on Antelope-based blockchains refer to the following: -* [Staking Mechanism](https://developers.eos.io/docs/latest/overview/technical_features#staking-mechanism). +* [Staking Mechanism](https://docs.eosnetwork.com/docs/latest/overview/technical_features#staking-mechanism). * [Staking on Antelope-based blockchains](05_stake.md) diff --git a/docs/01_key-concepts/04_net.md b/docs/01_key-concepts/04_net.md index c7a6e79d..9634c62b 100644 --- a/docs/01_key-concepts/04_net.md +++ b/docs/01_key-concepts/04_net.md @@ -5,5 +5,5 @@ content_title: NET as system resource NET, as CPU and RAM, is a very important system resource in Antelope-based blockchains. NET is measured by the byte size of the transactions saved in the blockchain database and it is referred to as `net bandwidth` on the cleos get account command result. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient NET must be staked in order for transactions to complete. For more details about staking on Antelope-based blockchains refer to the following: -* [Staking Mechanism](https://developers.eos.io/docs/latest/overview/technical_features#staking-mechanism). +* [Staking Mechanism](https://docs.eosnetwork.com/docs/latest/overview/technical_features#staking-mechanism). * [Staking on Antelope-based blockchains](05_stake.md) From 01a12a7ee810452952cb4c13429c64c7e055c433 Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Thu, 20 Apr 2023 21:36:15 -0400 Subject: [PATCH 53/96] remove `Runtime.h` include that no longer exists in Leap's libtester --- tests/eosio.limitauth_tests.cpp | 1 - tests/eosio.msig_tests.cpp | 2 -- tests/eosio.system_tests.cpp | 1 - tests/eosio.token_tests.cpp | 2 -- tests/eosio.wrap_tests.cpp | 2 -- tests/main.cpp | 1 - 6 files changed, 9 deletions(-) diff --git a/tests/eosio.limitauth_tests.cpp b/tests/eosio.limitauth_tests.cpp index ded793c2..c873d9ce 100644 --- a/tests/eosio.limitauth_tests.cpp +++ b/tests/eosio.limitauth_tests.cpp @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/tests/eosio.msig_tests.cpp b/tests/eosio.msig_tests.cpp index f3a9f968..a6de8707 100644 --- a/tests/eosio.msig_tests.cpp +++ b/tests/eosio.msig_tests.cpp @@ -4,8 +4,6 @@ #include #include -#include - #include #include "contracts.hpp" #include "test_symbol.hpp" diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index f4db7ee4..69f5092a 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include "eosio.system_tester.hpp" struct _abi_hash { diff --git a/tests/eosio.token_tests.cpp b/tests/eosio.token_tests.cpp index 6db45ac4..e2ca30f4 100644 --- a/tests/eosio.token_tests.cpp +++ b/tests/eosio.token_tests.cpp @@ -3,8 +3,6 @@ #include #include "eosio.system_tester.hpp" -#include "Runtime/Runtime.h" - #include using namespace eosio::testing; diff --git a/tests/eosio.wrap_tests.cpp b/tests/eosio.wrap_tests.cpp index 8f694c8f..bb0bf76d 100644 --- a/tests/eosio.wrap_tests.cpp +++ b/tests/eosio.wrap_tests.cpp @@ -2,8 +2,6 @@ #include #include -#include - #include #include "contracts.hpp" diff --git a/tests/main.cpp b/tests/main.cpp index e3d61750..027bdd13 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include "eosio.system_tester.hpp" From 0115cf33c5f3e576839feef2e1bf386907078df0 Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Thu, 20 Apr 2023 23:07:21 -0400 Subject: [PATCH 54/96] remove `Runtime.h` include that no longer exists in Leap's libtester --- tests/eosio.powerup_tests.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/eosio.powerup_tests.cpp b/tests/eosio.powerup_tests.cpp index 828a2925..dae4598e 100644 --- a/tests/eosio.powerup_tests.cpp +++ b/tests/eosio.powerup_tests.cpp @@ -1,4 +1,3 @@ -#include #include #include #include From 97d3faab7ee6995dd2d310e94e3f3dcb368ea602 Mon Sep 17 00:00:00 2001 From: 766C6164 Date: Tue, 23 May 2023 10:29:06 -0400 Subject: [PATCH 55/96] Fix for explicit time_point_sec conversion, bump max version to 4.1 --- tests/CMakeLists.txt | 2 +- tests/eosio.powerup_tests.cpp | 27 ++++++++++++++------------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f21e9118..c6e1af7e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.5) set(EOSIO_VERSION_MIN "3.1") -set(EOSIO_VERSION_SOFT_MAX "3.1") +set(EOSIO_VERSION_SOFT_MAX "4.1") # set(EOSIO_VERSION_HARD_MAX "") find_package(leap REQUIRED) diff --git a/tests/eosio.powerup_tests.cpp b/tests/eosio.powerup_tests.cpp index dae4598e..81c87ae1 100644 --- a/tests/eosio.powerup_tests.cpp +++ b/tests/eosio.powerup_tests.cpp @@ -97,7 +97,7 @@ struct powerup_tester : eosio_system_tester { config.net.current_weight_ratio = powerup_frac; config.net.target_weight_ratio = powerup_frac / 100; config.net.assumed_stake_weight = stake_weight; - config.net.target_timestamp = control->head_block_time() + fc::days(100); + config.net.target_timestamp = time_point_sec(control->head_block_time() + fc::days(100)); config.net.exponent = 2; config.net.decay_secs = fc::days(1).to_seconds(); config.net.min_price = asset::from_string("0.0000 TST"); @@ -106,7 +106,7 @@ struct powerup_tester : eosio_system_tester { config.cpu.current_weight_ratio = powerup_frac; config.cpu.target_weight_ratio = powerup_frac / 100; config.cpu.assumed_stake_weight = stake_weight; - config.cpu.target_timestamp = control->head_block_time() + fc::days(100); + config.cpu.target_timestamp = time_point_sec(control->head_block_time() + fc::days(100)); config.cpu.exponent = 2; config.cpu.decay_secs = fc::days(1).to_seconds(); config.cpu.min_price = asset::from_string("0.0000 TST"); @@ -287,9 +287,9 @@ BOOST_FIXTURE_TEST_CASE(config_tests, powerup_tester) try { BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_timestamp does not have a default value"), configbw(make_config([&](auto& c) { c.net.target_timestamp = {}; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_timestamp must be in the future"), - configbw(make_config([&](auto& c) { c.net.target_timestamp = control->head_block_time(); }))); + configbw(make_config([&](auto& c) { c.net.target_timestamp = time_point_sec(control->head_block_time()); }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_timestamp must be in the future"), configbw(make_config([&](auto& c) { - c.net.target_timestamp = control->head_block_time() - fc::seconds(1); + c.net.target_timestamp = time_point_sec(control->head_block_time() - fc::seconds(1)); }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("exponent must be >= 1"), configbw(make_config([&](auto& c) { c.net.exponent = .999; }))); @@ -332,9 +332,9 @@ BOOST_FIXTURE_TEST_CASE(config_tests, powerup_tester) try { BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_timestamp does not have a default value"), configbw(make_config([&](auto& c) { c.cpu.target_timestamp = {}; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_timestamp must be in the future"), - configbw(make_config([&](auto& c) { c.cpu.target_timestamp = control->head_block_time(); }))); + configbw(make_config([&](auto& c) { c.cpu.target_timestamp = time_point_sec(control->head_block_time()); }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_timestamp must be in the future"), configbw(make_config([&](auto& c) { - c.cpu.target_timestamp = control->head_block_time() - fc::seconds(1); + c.cpu.target_timestamp = time_point_sec(control->head_block_time() - fc::seconds(1)); }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("exponent must be >= 1"), configbw(make_config([&](auto& c) { c.cpu.exponent = .999; }))); @@ -374,12 +374,12 @@ BOOST_FIXTURE_TEST_CASE(weight_tests, powerup_tester) try { config.net.current_weight_ratio = net_start; config.net.target_weight_ratio = net_target; config.net.assumed_stake_weight = stake_weight; - config.net.target_timestamp = control->head_block_time() + fc::days(10); + config.net.target_timestamp = time_point_sec(control->head_block_time() + fc::days(10)); config.cpu.current_weight_ratio = cpu_start; config.cpu.target_weight_ratio = cpu_target; config.cpu.assumed_stake_weight = stake_weight; - config.cpu.target_timestamp = control->head_block_time() + fc::days(20); + config.cpu.target_timestamp = time_point_sec(control->head_block_time() + fc::days(20)); }))); int64_t net; @@ -415,8 +415,8 @@ BOOST_FIXTURE_TEST_CASE(weight_tests, powerup_tester) try { int i = 7; produce_block(fc::days(1) - fc::milliseconds(500)); BOOST_REQUIRE_EQUAL("", configbw(make_default_config([&](powerup_config& config) { - config.net.target_timestamp = control->head_block_time() + fc::days(30); - config.cpu.target_timestamp = control->head_block_time() + fc::days(40); + config.net.target_timestamp = time_point_sec(control->head_block_time() + fc::days(30)); + config.cpu.target_timestamp = time_point_sec(control->head_block_time() + fc::days(40)); }))); net_start = net = net_start + i * (net_target - net_start) / 10; cpu_start = cpu = cpu_start + i * (cpu_target - cpu_start) / 20; @@ -471,9 +471,10 @@ BOOST_FIXTURE_TEST_CASE(weight_tests, powerup_tester) try { // Move transition time to immediate future { produce_block(fc::days(1) - fc::milliseconds(500)); + time_point_sec tps(control->head_block_time() + fc::milliseconds(1000)); BOOST_REQUIRE_EQUAL("", configbw(make_default_config([&](powerup_config& config) { - config.net.target_timestamp = control->head_block_time() + fc::milliseconds(1000); - config.cpu.target_timestamp = control->head_block_time() + fc::milliseconds(1000); + config.net.target_timestamp = tps; + config.cpu.target_timestamp = tps; }))); produce_blocks(2); } @@ -854,4 +855,4 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { } // rent_tests FC_LOG_AND_RETHROW() -BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file From 10ff2c1f69e5b90b94ffbe28bdb61f7423c6279b Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Wed, 7 Jun 2023 22:06:11 -0400 Subject: [PATCH 56/96] fix misspelling in wasmcfg invalid configuration assertion --- contracts/eosio.system/src/eosio.system.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/eosio.system/src/eosio.system.cpp b/contracts/eosio.system/src/eosio.system.cpp index 8b0b2edc..527b0324 100644 --- a/contracts/eosio.system/src/eosio.system.cpp +++ b/contracts/eosio.system/src/eosio.system.cpp @@ -223,7 +223,7 @@ namespace eosiosystem { } else { - check(false, "Unkown configuration"); + check(false, "Unknown configuration"); } } From 260652aa5ecd1e7965e5e26cd9dfaf8f1e064064 Mon Sep 17 00:00:00 2001 From: Peter Oschwald Date: Wed, 21 Jun 2023 13:53:18 -0500 Subject: [PATCH 57/96] add cmake option to enable/disable Leap eosiotester version check. set SYSTEM_ENABLE_LEAP_VERSION_CHECK off in CI --- .github/workflows/build.yaml | 2 +- CMakeLists.txt | 3 +++ tests/CMakeLists.txt | 36 +++++++++++++++++++----------------- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 1b211e8a..8e12bada 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -92,7 +92,7 @@ jobs: path: src - name: Build & Test run: | - cmake -S src -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=On + cmake -S src -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=On -DSYSTEM_ENABLE_LEAP_VERSION_CHECK=Off cmake --build build -- -j $(nproc) tar zcf build.tar.gz build ctest --test-dir build/tests --output-on-failure -j $(nproc) diff --git a/CMakeLists.txt b/CMakeLists.txt index 288cfa1e..94c5e7ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,9 @@ option(SYSTEM_CONFIGURABLE_WASM_LIMITS option(SYSTEM_BLOCKCHAIN_PARAMETERS "Enables use of the host functions activated by the BLOCKCHAIN_PARAMETERS protocol feature" ON) +option(SYSTEM_ENABLE_LEAP_VERSION_CHECK + "Enables a configure-time check that the version of Leap's tester library is compatible with this project's unit tests" ON) + ExternalProject_Add( contracts_project SOURCE_DIR ${CMAKE_SOURCE_DIR}/contracts diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index aa8e3e04..f21e9118 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -4,25 +4,27 @@ set(EOSIO_VERSION_MIN "3.1") set(EOSIO_VERSION_SOFT_MAX "3.1") # set(EOSIO_VERSION_HARD_MAX "") -find_package(leap) +find_package(leap REQUIRED) # Check the version of Leap -set(VERSION_MATCH_ERROR_MSG "") -eosio_check_version(VERSION_OUTPUT "${EOSIO_VERSION}" "${EOSIO_VERSION_MIN}" "${EOSIO_VERSION_SOFT_MAX}" - "${EOSIO_VERSION_HARD_MAX}" VERSION_MATCH_ERROR_MSG) -if(VERSION_OUTPUT STREQUAL "MATCH") - message(STATUS "Using Leap version ${EOSIO_VERSION}") -elseif(VERSION_OUTPUT STREQUAL "WARN") - message( - WARNING - "Using Leap version ${EOSIO_VERSION} even though it exceeds the maximum supported version of ${EOSIO_VERSION_SOFT_MAX}; continuing with configuration, however build may fail.\nIt is recommended to use Leap version ${EOSIO_VERSION_SOFT_MAX}.x" - ) -else() # INVALID OR MISMATCH - message( - FATAL_ERROR - "Found Leap version ${EOSIO_VERSION} but it does not satisfy version requirements: ${VERSION_MATCH_ERROR_MSG}\nPlease use Leap version ${EOSIO_VERSION_SOFT_MAX}.x" - ) -endif(VERSION_OUTPUT STREQUAL "MATCH") +if(SYSTEM_ENABLE_LEAP_VERSION_CHECK) + set(VERSION_MATCH_ERROR_MSG "") + eosio_check_version(VERSION_OUTPUT "${EOSIO_VERSION}" "${EOSIO_VERSION_MIN}" "${EOSIO_VERSION_SOFT_MAX}" + "${EOSIO_VERSION_HARD_MAX}" VERSION_MATCH_ERROR_MSG) + if(VERSION_OUTPUT STREQUAL "MATCH") + message(STATUS "Using Leap version ${EOSIO_VERSION}") + elseif(VERSION_OUTPUT STREQUAL "WARN") + message( + WARNING + "Using Leap version ${EOSIO_VERSION} even though it exceeds the maximum supported version of ${EOSIO_VERSION_SOFT_MAX}; continuing with configuration, however build may fail.\nIt is recommended to use Leap version ${EOSIO_VERSION_SOFT_MAX}.x" + ) + else() # INVALID OR MISMATCH + message( + FATAL_ERROR + "Found Leap version ${EOSIO_VERSION} but it does not satisfy version requirements: ${VERSION_MATCH_ERROR_MSG}\nPlease use Leap version ${EOSIO_VERSION_SOFT_MAX}.x" + ) + endif() +endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/contracts.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/contracts.hpp) From 01fab108a3f246a036da64499282172a4e3cb613 Mon Sep 17 00:00:00 2001 From: Peter Oschwald Date: Wed, 21 Jun 2023 14:07:16 -0500 Subject: [PATCH 58/96] add cmake option to enable/disable cdt version check. --- CMakeLists.txt | 3 +++ contracts/CMakeLists.txt | 36 +++++++++++++++++++----------------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 94c5e7ec..e997d090 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,9 @@ option(SYSTEM_BLOCKCHAIN_PARAMETERS option(SYSTEM_ENABLE_LEAP_VERSION_CHECK "Enables a configure-time check that the version of Leap's tester library is compatible with this project's unit tests" ON) +option(SYSTEM_ENABLE_CDT_VERSION_CHECK + "Enables a configure-time check that the version of CDT is compatible with this project's contracts" ON) + ExternalProject_Add( contracts_project SOURCE_DIR ${CMAKE_SOURCE_DIR}/contracts diff --git a/contracts/CMakeLists.txt b/contracts/CMakeLists.txt index 52a5a6a9..b8bdcf0a 100644 --- a/contracts/CMakeLists.txt +++ b/contracts/CMakeLists.txt @@ -8,29 +8,31 @@ option(SYSTEM_CONFIGURABLE_WASM_LIMITS option(SYSTEM_BLOCKCHAIN_PARAMETERS "Enables use of the host functions activated by the BLOCKCHAIN_PARAMETERS protocol feature" ON) -find_package(cdt) +find_package(cdt REQUIRED) set(CDT_VERSION_MIN "3.0") set(CDT_VERSION_SOFT_MAX "3.0") # set(CDT_VERSION_HARD_MAX "") # Check the version of CDT -set(VERSION_MATCH_ERROR_MSG "") -CDT_CHECK_VERSION(VERSION_OUTPUT "${CDT_VERSION}" "${CDT_VERSION_MIN}" "${CDT_VERSION_SOFT_MAX}" - "${CDT_VERSION_HARD_MAX}" VERSION_MATCH_ERROR_MSG) -if(VERSION_OUTPUT STREQUAL "MATCH") - message(STATUS "Using CDT version ${CDT_VERSION}") -elseif(VERSION_OUTPUT STREQUAL "WARN") - message( - WARNING - "Using CDT version ${CDT_VERSION} even though it exceeds the maximum supported version of ${CDT_VERSION_SOFT_MAX}; continuing with configuration, however build may fail.\nIt is recommended to use CDT version ${CDT_VERSION_SOFT_MAX}.x" - ) -else() # INVALID OR MISMATCH - message( - FATAL_ERROR - "Found CDT version ${CDT_VERSION} but it does not satisfy version requirements: ${VERSION_MATCH_ERROR_MSG}\nPlease use CDT version ${CDT_VERSION_SOFT_MAX}.x" - ) -endif(VERSION_OUTPUT STREQUAL "MATCH") +if(SYSTEM_ENABLE_CDT_VERSION_CHECK) + set(VERSION_MATCH_ERROR_MSG "") + CDT_CHECK_VERSION(VERSION_OUTPUT "${CDT_VERSION}" "${CDT_VERSION_MIN}" "${CDT_VERSION_SOFT_MAX}" + "${CDT_VERSION_HARD_MAX}" VERSION_MATCH_ERROR_MSG) + if(VERSION_OUTPUT STREQUAL "MATCH") + message(STATUS "Using CDT version ${CDT_VERSION}") + elseif(VERSION_OUTPUT STREQUAL "WARN") + message( + WARNING + "Using CDT version ${CDT_VERSION} even though it exceeds the maximum supported version of ${CDT_VERSION_SOFT_MAX}; continuing with configuration, however build may fail.\nIt is recommended to use CDT version ${CDT_VERSION_SOFT_MAX}.x" + ) + else() # INVALID OR MISMATCH + message( + FATAL_ERROR + "Found CDT version ${CDT_VERSION} but it does not satisfy version requirements: ${VERSION_MATCH_ERROR_MSG}\nPlease use CDT version ${CDT_VERSION_SOFT_MAX}.x" + ) + endif() +endif() set(ICON_BASE_URL "https://raw.githubusercontent.com/eosnetworkfoundation/eos-system-contracts/main/contracts/icons") From 7aadf529572abe73d01a6f4d52994e9d62dfb25f Mon Sep 17 00:00:00 2001 From: Peter Oschwald Date: Wed, 21 Jun 2023 14:11:56 -0500 Subject: [PATCH 59/96] set SYSTEM_ENABLE_CDT_VERSION_CHECK off in CI --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 8e12bada..89c8766e 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -92,7 +92,7 @@ jobs: path: src - name: Build & Test run: | - cmake -S src -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=On -DSYSTEM_ENABLE_LEAP_VERSION_CHECK=Off + cmake -S src -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=On -DSYSTEM_ENABLE_LEAP_VERSION_CHECK=Off -DSYSTEM_ENABLE_CDT_VERSION_CHECK=Off cmake --build build -- -j $(nproc) tar zcf build.tar.gz build ctest --test-dir build/tests --output-on-failure -j $(nproc) From d0e8934d214acebc080696b415feb58e3f8eda11 Mon Sep 17 00:00:00 2001 From: Peter Oschwald Date: Thu, 22 Jun 2023 08:56:19 -0500 Subject: [PATCH 60/96] remove Runtime.h include that no longer exists in Leap's libtester --- tests/eosio.limitauth_tests.cpp | 1 - tests/eosio.msig_tests.cpp | 2 -- tests/eosio.powerup_tests.cpp | 1 - tests/eosio.system_tests.cpp | 1 - tests/eosio.token_tests.cpp | 2 -- tests/eosio.wrap_tests.cpp | 2 -- tests/main.cpp | 1 - 7 files changed, 10 deletions(-) diff --git a/tests/eosio.limitauth_tests.cpp b/tests/eosio.limitauth_tests.cpp index ded793c2..c873d9ce 100644 --- a/tests/eosio.limitauth_tests.cpp +++ b/tests/eosio.limitauth_tests.cpp @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/tests/eosio.msig_tests.cpp b/tests/eosio.msig_tests.cpp index 685c87db..8ecd1812 100644 --- a/tests/eosio.msig_tests.cpp +++ b/tests/eosio.msig_tests.cpp @@ -3,8 +3,6 @@ #include #include -#include - #include #include "contracts.hpp" #include "test_symbol.hpp" diff --git a/tests/eosio.powerup_tests.cpp b/tests/eosio.powerup_tests.cpp index 828a2925..dae4598e 100644 --- a/tests/eosio.powerup_tests.cpp +++ b/tests/eosio.powerup_tests.cpp @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 1989d8f6..d07dcc02 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include "eosio.system_tester.hpp" struct _abi_hash { diff --git a/tests/eosio.token_tests.cpp b/tests/eosio.token_tests.cpp index 68e7d554..d469ce01 100644 --- a/tests/eosio.token_tests.cpp +++ b/tests/eosio.token_tests.cpp @@ -3,8 +3,6 @@ #include #include "eosio.system_tester.hpp" -#include "Runtime/Runtime.h" - #include using namespace eosio::testing; diff --git a/tests/eosio.wrap_tests.cpp b/tests/eosio.wrap_tests.cpp index 094c3502..e974ef66 100644 --- a/tests/eosio.wrap_tests.cpp +++ b/tests/eosio.wrap_tests.cpp @@ -2,8 +2,6 @@ #include #include -#include - #include #include "contracts.hpp" diff --git a/tests/main.cpp b/tests/main.cpp index e3d61750..027bdd13 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include "eosio.system_tester.hpp" From 2512525081da17de7a22457842f29289f2385b94 Mon Sep 17 00:00:00 2001 From: 766C6164 Date: Tue, 23 May 2023 10:29:06 -0400 Subject: [PATCH 61/96] Fix for explicit time_point_sec conversion Excludes max version bump. --- tests/eosio.powerup_tests.cpp | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/tests/eosio.powerup_tests.cpp b/tests/eosio.powerup_tests.cpp index dae4598e..81c87ae1 100644 --- a/tests/eosio.powerup_tests.cpp +++ b/tests/eosio.powerup_tests.cpp @@ -97,7 +97,7 @@ struct powerup_tester : eosio_system_tester { config.net.current_weight_ratio = powerup_frac; config.net.target_weight_ratio = powerup_frac / 100; config.net.assumed_stake_weight = stake_weight; - config.net.target_timestamp = control->head_block_time() + fc::days(100); + config.net.target_timestamp = time_point_sec(control->head_block_time() + fc::days(100)); config.net.exponent = 2; config.net.decay_secs = fc::days(1).to_seconds(); config.net.min_price = asset::from_string("0.0000 TST"); @@ -106,7 +106,7 @@ struct powerup_tester : eosio_system_tester { config.cpu.current_weight_ratio = powerup_frac; config.cpu.target_weight_ratio = powerup_frac / 100; config.cpu.assumed_stake_weight = stake_weight; - config.cpu.target_timestamp = control->head_block_time() + fc::days(100); + config.cpu.target_timestamp = time_point_sec(control->head_block_time() + fc::days(100)); config.cpu.exponent = 2; config.cpu.decay_secs = fc::days(1).to_seconds(); config.cpu.min_price = asset::from_string("0.0000 TST"); @@ -287,9 +287,9 @@ BOOST_FIXTURE_TEST_CASE(config_tests, powerup_tester) try { BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_timestamp does not have a default value"), configbw(make_config([&](auto& c) { c.net.target_timestamp = {}; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_timestamp must be in the future"), - configbw(make_config([&](auto& c) { c.net.target_timestamp = control->head_block_time(); }))); + configbw(make_config([&](auto& c) { c.net.target_timestamp = time_point_sec(control->head_block_time()); }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_timestamp must be in the future"), configbw(make_config([&](auto& c) { - c.net.target_timestamp = control->head_block_time() - fc::seconds(1); + c.net.target_timestamp = time_point_sec(control->head_block_time() - fc::seconds(1)); }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("exponent must be >= 1"), configbw(make_config([&](auto& c) { c.net.exponent = .999; }))); @@ -332,9 +332,9 @@ BOOST_FIXTURE_TEST_CASE(config_tests, powerup_tester) try { BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_timestamp does not have a default value"), configbw(make_config([&](auto& c) { c.cpu.target_timestamp = {}; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_timestamp must be in the future"), - configbw(make_config([&](auto& c) { c.cpu.target_timestamp = control->head_block_time(); }))); + configbw(make_config([&](auto& c) { c.cpu.target_timestamp = time_point_sec(control->head_block_time()); }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_timestamp must be in the future"), configbw(make_config([&](auto& c) { - c.cpu.target_timestamp = control->head_block_time() - fc::seconds(1); + c.cpu.target_timestamp = time_point_sec(control->head_block_time() - fc::seconds(1)); }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("exponent must be >= 1"), configbw(make_config([&](auto& c) { c.cpu.exponent = .999; }))); @@ -374,12 +374,12 @@ BOOST_FIXTURE_TEST_CASE(weight_tests, powerup_tester) try { config.net.current_weight_ratio = net_start; config.net.target_weight_ratio = net_target; config.net.assumed_stake_weight = stake_weight; - config.net.target_timestamp = control->head_block_time() + fc::days(10); + config.net.target_timestamp = time_point_sec(control->head_block_time() + fc::days(10)); config.cpu.current_weight_ratio = cpu_start; config.cpu.target_weight_ratio = cpu_target; config.cpu.assumed_stake_weight = stake_weight; - config.cpu.target_timestamp = control->head_block_time() + fc::days(20); + config.cpu.target_timestamp = time_point_sec(control->head_block_time() + fc::days(20)); }))); int64_t net; @@ -415,8 +415,8 @@ BOOST_FIXTURE_TEST_CASE(weight_tests, powerup_tester) try { int i = 7; produce_block(fc::days(1) - fc::milliseconds(500)); BOOST_REQUIRE_EQUAL("", configbw(make_default_config([&](powerup_config& config) { - config.net.target_timestamp = control->head_block_time() + fc::days(30); - config.cpu.target_timestamp = control->head_block_time() + fc::days(40); + config.net.target_timestamp = time_point_sec(control->head_block_time() + fc::days(30)); + config.cpu.target_timestamp = time_point_sec(control->head_block_time() + fc::days(40)); }))); net_start = net = net_start + i * (net_target - net_start) / 10; cpu_start = cpu = cpu_start + i * (cpu_target - cpu_start) / 20; @@ -471,9 +471,10 @@ BOOST_FIXTURE_TEST_CASE(weight_tests, powerup_tester) try { // Move transition time to immediate future { produce_block(fc::days(1) - fc::milliseconds(500)); + time_point_sec tps(control->head_block_time() + fc::milliseconds(1000)); BOOST_REQUIRE_EQUAL("", configbw(make_default_config([&](powerup_config& config) { - config.net.target_timestamp = control->head_block_time() + fc::milliseconds(1000); - config.cpu.target_timestamp = control->head_block_time() + fc::milliseconds(1000); + config.net.target_timestamp = tps; + config.cpu.target_timestamp = tps; }))); produce_blocks(2); } @@ -854,4 +855,4 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { } // rent_tests FC_LOG_AND_RETHROW() -BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file From 5f846a6040bd7c75d62489d8a8872e981a471524 Mon Sep 17 00:00:00 2001 From: Eric Passmore Date: Fri, 22 Sep 2023 09:28:13 -0700 Subject: [PATCH 62/96] rm deferred trx --- .../eosio.system/src/delegate_bandwidth.cpp | 19 -------------- contracts/eosio.system/src/name_bidding.cpp | 10 -------- .../01_upgrading-the-eosio.system-contract.md | 2 +- docs/04_guides/07_how-to-use-eosio.wrap.md | 8 +++--- tests/eosio.system_tests.cpp | 25 +++++++++++++++++-- 5 files changed, 28 insertions(+), 36 deletions(-) diff --git a/contracts/eosio.system/src/delegate_bandwidth.cpp b/contracts/eosio.system/src/delegate_bandwidth.cpp index 9d1bd6b4..f8fc6f67 100644 --- a/contracts/eosio.system/src/delegate_bandwidth.cpp +++ b/contracts/eosio.system/src/delegate_bandwidth.cpp @@ -261,8 +261,6 @@ namespace eosiosystem { //create/update/delete refund auto net_balance = stake_net_delta; auto cpu_balance = stake_cpu_delta; - bool need_deferred_trx = false; - // net and cpu are same sign by assertions in delegatebw and undelegatebw // redundant assertion also at start of changebw to protect against misuse of changebw @@ -296,9 +294,6 @@ namespace eosiosystem { if ( req->is_empty() ) { refunds_tbl.erase( req ); - need_deferred_trx = false; - } else { - need_deferred_trx = true; } } else if ( net_balance.amount < 0 || cpu_balance.amount < 0 ) { //need to create refund refunds_tbl.emplace( from, [&]( refund_request& r ) { @@ -317,23 +312,9 @@ namespace eosiosystem { } r.request_time = current_time_point(); }); - need_deferred_trx = true; } // else stake increase requested with no existing row in refunds_tbl -> nothing to do with refunds_tbl } /// end if is_delegating_to_self || is_undelegating - if ( need_deferred_trx ) { - eosio::transaction out; - out.actions.emplace_back( permission_level{from, active_permission}, - get_self(), "refund"_n, - from - ); - out.delay_sec = refund_delay_sec; - eosio::cancel_deferred( from.value ); // TODO: Remove this line when replacing deferred transactions is fixed - out.send( from.value, from, true ); - } else { - eosio::cancel_deferred( from.value ); - } - auto transfer_amount = net_balance + cpu_balance; if ( 0 < transfer_amount.amount ) { token::transfer_action transfer_act{ token_account, { {source_stake_from, active_permission} } }; diff --git a/contracts/eosio.system/src/name_bidding.cpp b/contracts/eosio.system/src/name_bidding.cpp index 4c01f353..6fed7b7c 100644 --- a/contracts/eosio.system/src/name_bidding.cpp +++ b/contracts/eosio.system/src/name_bidding.cpp @@ -49,16 +49,6 @@ namespace eosiosystem { }); } - eosio::transaction t; - t.actions.emplace_back( permission_level{current->high_bidder, active_permission}, - get_self(), "bidrefund"_n, - std::make_tuple( current->high_bidder, newname ) - ); - t.delay_sec = 0; - uint128_t deferred_id = (uint128_t(newname.value) << 64) | current->high_bidder.value; - eosio::cancel_deferred( deferred_id ); - t.send( deferred_id, bidder ); - bids.modify( current, bidder, [&]( auto& b ) { b.high_bidder = bidder; b.high_bid = bid.amount; diff --git a/docs/04_guides/01_upgrading-the-eosio.system-contract.md b/docs/04_guides/01_upgrading-the-eosio.system-contract.md index c53e0424..62d4265f 100644 --- a/docs/04_guides/01_upgrading-the-eosio.system-contract.md +++ b/docs/04_guides/01_upgrading-the-eosio.system-contract.md @@ -218,7 +218,7 @@ diff original_system_contract.abi new_system_contract.abi ```json 584,592d583 < },{ -< "name": "deferred_trx_id", +< "name": "trx_id", < "type": "uint32" < },{ < "name": "last_unstake_time", diff --git a/docs/04_guides/07_how-to-use-eosio.wrap.md b/docs/04_guides/07_how-to-use-eosio.wrap.md index dea01d81..370fc0dc 100644 --- a/docs/04_guides/07_how-to-use-eosio.wrap.md +++ b/docs/04_guides/07_how-to-use-eosio.wrap.md @@ -202,7 +202,7 @@ cat create_wrap_account_trx.json } ``` -The `ref_block_num` and `ref_block_prefix` values were set to 0. The proposed transaction does not need to have a valid TaPoS reference block because it will be reset anyway when scheduled as a deferred transaction during the `eosio.msig::exec` action. The `expiration` field, which was the only other field that was changed, will also be reset when the proposed transaction is scheduled as a deferred transaction during `eosio.msig::exec`. However, this field actually does matter during the propose-approve-exec lifecycle of the proposed transaction. If the present time passes the time in the `expiration` field of the proposed transaction, it will not be possible to execute the proposed transaction even if all necessary approvals are gathered. Therefore, it is important to set the expiration time to some point well enough in the future to give all necessary approvers enough time to review and approve the proposed transaction, but it is otherwise arbitrary. Generally, for reviewing/validation purposes it is important that all potential approvers of the transaction (i.e. the block producers) choose the exact same `expiration` time so that there is not any discrepancy in bytes of the serialized transaction if it was to later be included in payload data of some other action. +The `ref_block_num` and `ref_block_prefix` values were set to 0. The proposed transaction does not need to have a valid TaPoS reference block because it will be reset anyway when scheduled during the `eosio.msig::exec` action. The `expiration` field, which was the only other field that was changed, will also be reset when the proposed transaction is scheduled during `eosio.msig::exec`. However, this field actually does matter during the propose-approve-exec lifecycle of the proposed transaction. If the present time passes the time in the `expiration` field of the proposed transaction, it will not be possible to execute the proposed transaction even if all necessary approvals are gathered. Therefore, it is important to set the expiration time to some point well enough in the future to give all necessary approvers enough time to review and approve the proposed transaction, but it is otherwise arbitrary. Generally, for reviewing/validation purposes it is important that all potential approvers of the transaction (i.e. the block producers) choose the exact same `expiration` time so that there is not any discrepancy in bytes of the serialized transaction if it was to later be included in payload data of some other action. Then, all but the first action JSON object of generated_account_creation_trx.json should be appended to the `actions` array of create_wrap_account_trx.json, and then the single action JSON object of generated_setpriv_trx.json should be appended to the `actions` array of create_wrap_account_trx.json. The final result is a create_wrap_account_trx.json file that looks like the following: ```sh @@ -388,7 +388,7 @@ warning: transaction executed locally, but may not be confirmed by the network y ### 1.1.4 Execute the transaction to create the eosio.wrap account -When the necessary approvals are collected (in this example, with 21 block producers, at least 15 of their approvals were required), anyone can push the `eosio.msig::exec` action which executes the approved transaction. It makes a lot of sense for the lead block producer who proposed the transaction to also execute it (this will incur another temporary RAM cost for the deferred transaction that is generated by the eosio.msig contract). +When the necessary approvals are collected (in this example, with 21 block producers, at least 15 of their approvals were required), anyone can push the `eosio.msig::exec` action which executes the approved transaction. It makes a lot of sense for the lead block producer who proposed the transaction to also execute it (this will incur another temporary RAM cost for the that is generated by the eosio.msig contract). ```sh cleos multisig exec blkproducera createwrap blkproducera @@ -606,7 +606,7 @@ warning: transaction executed locally, but may not be confirmed by the network y ### 1.2.4 Execute the transaction to create the eosio.wrap account -When the necessary approvals are collected (in this example, with 21 block producers, at least 15 of their approvals were required), anyone can push the `eosio.msig::exec` action which executes the approved transaction. It makes a lot of sense for the lead block producer who proposed the transaction to also execute it (this will incur another temporary RAM cost for the deferred transaction that is generated by the eosio.msig contract). +When the necessary approvals are collected (in this example, with 21 block producers, at least 15 of their approvals were required), anyone can push the `eosio.msig::exec` action which executes the approved transaction. It makes a lot of sense for the lead block producer who proposed the transaction to also execute it (this will incur another temporary RAM cost that is generated by the eosio.msig contract). ```sh cleos multisig exec blkproducera deploywrap blkproducera @@ -930,7 +930,7 @@ warning: transaction executed locally, but may not be confirmed by the network y ### 2.1.4 Execute the transaction to change the owner permission of an account -When the necessary approvals are collected (in this example, with 21 block producers, at least 15 of their approvals were required), anyone can push the `eosio.msig::exec` action which executes the approved transaction. It makes a lot of sense for the lead block producer who proposed the transaction to also execute it (this will incur another temporary RAM cost for the deferred transaction that is generated by the eosio.msig contract). +When the necessary approvals are collected (in this example, with 21 block producers, at least 15 of their approvals were required), anyone can push the `eosio.msig::exec` action which executes the approved transaction. It makes a lot of sense for the lead block producer who proposed the transaction to also execute it (this will incur another temporary RAM cost that is generated by the eosio.msig contract). ```sh cleos multisig exec blkproducera updatealice blkproducera diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 69f5092a..7ae4ed68 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -198,11 +198,18 @@ BOOST_FIXTURE_TEST_CASE( stake_unstake, eosio_system_tester ) try { produce_block( fc::hours(3*24-1) ); produce_blocks(1); + // testing balance still the same BOOST_REQUIRE_EQUAL( core_sym::from_string("700.0000"), get_balance( "alice1111111" ) ); BOOST_REQUIRE_EQUAL( init_eosio_stake_balance + core_sym::from_string("300.0000"), get_balance( "eosio.stake"_n ) ); - //after 3 days funds should be released + // call refund expected to fail too early + BOOST_REQUIRE_EQUAL( wasm_assert_msg("refund is not available yet"), + push_action( "alice1111111"_n, "refund"_n, mvo()("owner", "alice1111111") ) ); + + // after 1 hour refund ready produce_block( fc::hours(1) ); produce_blocks(1); + // now we can do the refund + BOOST_REQUIRE_EQUAL( success(), push_action( "alice1111111"_n, "refund"_n, mvo()("owner", "alice1111111") ) ); BOOST_REQUIRE_EQUAL( core_sym::from_string("1000.0000"), get_balance( "alice1111111" ) ); BOOST_REQUIRE_EQUAL( init_eosio_stake_balance, get_balance( "eosio.stake"_n ) ); @@ -235,6 +242,7 @@ BOOST_FIXTURE_TEST_CASE( stake_unstake, eosio_system_tester ) try { REQUIRE_MATCHING_OBJECT( voter( "alice1111111", core_sym::from_string("0.0000") ), get_voter_info( "alice1111111" ) ); produce_blocks(1); + BOOST_REQUIRE_EQUAL( success(), push_action( "alice1111111"_n, "refund"_n, mvo()("owner", "alice1111111") ) ); BOOST_REQUIRE_EQUAL( core_sym::from_string("1000.0000"), get_balance( "alice1111111" ) ); } FC_LOG_AND_RETHROW() @@ -278,6 +286,7 @@ BOOST_FIXTURE_TEST_CASE( stake_unstake_with_transfer, eosio_system_tester ) try produce_block( fc::hours(1) ); produce_blocks(1); + BOOST_REQUIRE_EQUAL( success(), push_action( "alice1111111"_n, "refund"_n, mvo()("owner", "alice1111111") ) ); BOOST_REQUIRE_EQUAL( core_sym::from_string("1300.0000"), get_balance( "alice1111111" ) ); //stake should be equal to what was staked in constructor, voting power should be 0 @@ -342,6 +351,7 @@ BOOST_FIXTURE_TEST_CASE( stake_while_pending_refund, eosio_system_tester ) try { produce_block( fc::hours(1) ); produce_blocks(1); + BOOST_REQUIRE_EQUAL( success(), push_action( "alice1111111"_n, "refund"_n, mvo()("owner", "alice1111111") ) ); BOOST_REQUIRE_EQUAL( core_sym::from_string("1300.0000"), get_balance( "alice1111111" ) ); //stake should be equal to what was staked in constructor, voting power should be 0 @@ -604,6 +614,7 @@ BOOST_FIXTURE_TEST_CASE( adding_stake_partial_unstake, eosio_system_tester ) try BOOST_REQUIRE_EQUAL( core_sym::from_string("550.0000"), get_balance( "alice1111111" ) ); produce_block( fc::days(1) ); produce_blocks(1); + BOOST_REQUIRE_EQUAL( success(), push_action( "alice1111111"_n, "refund"_n, mvo()("owner", "alice1111111") ) ); BOOST_REQUIRE_EQUAL( core_sym::from_string("850.0000"), get_balance( "alice1111111" ) ); } FC_LOG_AND_RETHROW() @@ -1078,6 +1089,9 @@ BOOST_FIXTURE_TEST_CASE( vote_for_producer, eosio_system_tester, * boost::unit_t //carol1111111 should receive funds in 3 days produce_block( fc::days(3) ); produce_block(); + + // do a bid refund for carol + BOOST_REQUIRE_EQUAL( success(), push_action( "carol1111111"_n, "refund"_n, mvo()("owner", "carol1111111") ) ); BOOST_REQUIRE_EQUAL( core_sym::from_string("3000.0000"), get_balance( "carol1111111" ) ); } FC_LOG_AND_RETHROW() @@ -3296,7 +3310,7 @@ BOOST_FIXTURE_TEST_CASE( multiple_namebids, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( success(), regproducer( "producer"_n ) ); produce_block(); - // stake but but not enough to go live + // stake but not enough to go live stake_with_transfer( config::system_account_name, "bob"_n, core_sym::from_string( "35000000.0000" ), core_sym::from_string( "35000000.0000" ) ); stake_with_transfer( config::system_account_name, "carl"_n, core_sym::from_string( "35000000.0000" ), core_sym::from_string( "35000000.0000" ) ); BOOST_REQUIRE_EQUAL( success(), vote( "bob"_n, { "producer"_n } ) ); @@ -3320,11 +3334,14 @@ BOOST_FIXTURE_TEST_CASE( multiple_namebids, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( core_sym::from_string( "9996.9997" ), get_balance("bob") ); BOOST_REQUIRE_EQUAL( core_sym::from_string( "10000.0000" ), get_balance("alice") ); + // alice outbids bob on prefb { const asset initial_names_balance = get_balance("eosio.names"_n); BOOST_REQUIRE_EQUAL( success(), bidname( "alice", "prefb", core_sym::from_string("1.1001") ) ); + // refund bob's failed bid on prefb + BOOST_REQUIRE_EQUAL( success(), push_action( "bob"_n, "bidrefund"_n, mvo()("bidder","bob")("newname", "prefb") ) ); BOOST_REQUIRE_EQUAL( core_sym::from_string( "9997.9997" ), get_balance("bob") ); BOOST_REQUIRE_EQUAL( core_sym::from_string( "9998.8999" ), get_balance("alice") ); BOOST_REQUIRE_EQUAL( initial_names_balance + core_sym::from_string("0.1001"), get_balance("eosio.names"_n) ); @@ -3336,6 +3353,8 @@ BOOST_FIXTURE_TEST_CASE( multiple_namebids, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( core_sym::from_string( "10000.0000" ), get_balance("david") ); BOOST_REQUIRE_EQUAL( success(), bidname( "david", "prefd", core_sym::from_string("1.9900") ) ); + // refund carls's failed bid on prefd + BOOST_REQUIRE_EQUAL( success(), push_action( "carl"_n, "bidrefund"_n, mvo()("bidder","carl")("newname", "prefd") ) ); BOOST_REQUIRE_EQUAL( core_sym::from_string( "9999.0000" ), get_balance("carl") ); BOOST_REQUIRE_EQUAL( core_sym::from_string( "9998.0100" ), get_balance("david") ); } @@ -4745,6 +4764,8 @@ BOOST_FIXTURE_TEST_CASE( ramfee_namebid_to_rex, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( success(), bidname( carol, "rndmbid"_n, core_sym::from_string("23.7000") ) ); BOOST_REQUIRE_EQUAL( core_sym::from_string("23.7000"), get_balance( "eosio.names"_n ) ); BOOST_REQUIRE_EQUAL( success(), bidname( alice, "rndmbid"_n, core_sym::from_string("29.3500") ) ); + // refund carol, the losing bid + BOOST_REQUIRE_EQUAL( success(), push_action( carol, "bidrefund"_n, mvo()("bidder","carolaccount")("newname", "rndmbid") ) ); BOOST_REQUIRE_EQUAL( core_sym::from_string("29.3500"), get_balance( "eosio.names"_n )); produce_block( fc::hours(24) ); From 629987a299a65a281502bdd0c2999902980d0284 Mon Sep 17 00:00:00 2001 From: Eric Passmore Date: Fri, 29 Sep 2023 20:27:51 -0700 Subject: [PATCH 63/96] bump version v3.2.0 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a5c1d38..992fc206 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ project(eosio_contracts) set(VERSION_MAJOR 3) set(VERSION_MINOR 2) set(VERSION_PATCH 0) -set(VERSION_SUFFIX dev) +set(VERSION_SUFFIX rc1) if(VERSION_SUFFIX) set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}") From 82e6d908e94a79136964cccb2e8ba4f2c9cd0ccf Mon Sep 17 00:00:00 2001 From: Eric Passmore Date: Mon, 2 Oct 2023 16:01:25 -0700 Subject: [PATCH 64/96] bump version of main to next v3.3.0-dev --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 992fc206..04ff765d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,9 +3,9 @@ cmake_minimum_required(VERSION 3.5) project(eosio_contracts) set(VERSION_MAJOR 3) -set(VERSION_MINOR 2) +set(VERSION_MINOR 3) set(VERSION_PATCH 0) -set(VERSION_SUFFIX rc1) +set(VERSION_SUFFIX dev) if(VERSION_SUFFIX) set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}") From 54a0e1ccf522942fa08d92a68cf845e4dc69fab7 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Fri, 5 Jan 2024 22:54:48 -0500 Subject: [PATCH 65/96] implement ramtransfer action --- .../include/eosio.system/eosio.system.hpp | 11 ++++ .../ricardian/eosio.system.contracts.md.in | 11 ++++ .../eosio.system/src/delegate_bandwidth.cpp | 63 +++++++++++++++---- tests/eosio.system_tests.cpp | 21 +++++++ 4 files changed, 94 insertions(+), 12 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 4c2574fa..cd968633 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1120,6 +1120,16 @@ namespace eosiosystem { [[eosio::action]] void sellram( const name& account, int64_t bytes ); + /** + * Transfer ram action, reduces sender's quota by bytes and increase receiver's quota by bytes. + * + * @param from - the ram sender account, + * @param to - the ram receiver account, + * @param bytes - the amount of ram to transfer in bytes. + */ + [[eosio::action]] + void ramtransfer( const name& from, const name& to, int64_t bytes ); + /** * Refund action, this action is called after the delegation-period to claim all pending * unstaked tokens belonging to owner. @@ -1496,6 +1506,7 @@ namespace eosiosystem { void changebw( name from, const name& receiver, const asset& stake_net_quantity, const asset& stake_cpu_quantity, bool transfer ); void update_voting_power( const name& voter, const asset& total_update ); + void set_resource_ram_bytes_limits( const name& owner, int64_t new_ram_bytes ); // defined in voting.cpp void register_producer( const name& producer, const eosio::block_signing_authority& producer_authority, const std::string& url, uint16_t location ); diff --git a/contracts/eosio.system/ricardian/eosio.system.contracts.md.in b/contracts/eosio.system/ricardian/eosio.system.contracts.md.in index bce8880a..98955037 100644 --- a/contracts/eosio.system/ricardian/eosio.system.contracts.md.in +++ b/contracts/eosio.system/ricardian/eosio.system.contracts.md.in @@ -413,6 +413,17 @@ icon: @ICON_BASE_URL@/@RESOURCE_ICON_URI@ Sell {{bytes}} bytes of unused RAM from account {{account}} at market price. This transaction will incur a 0.5% fee on the proceeds which depend on market rates. +

ramtransfer

+ +--- +spec_version: "0.2.0" +title: Transfer RAM from Account +summary: 'Transfer unused RAM from {{nowrap from}} to {{nowrap to}}' +icon: @ICON_BASE_URL@/@RESOURCE_ICON_URI@ +--- + +Transfer {{bytes}} bytes of unused RAM from account {{from}} to account {{to}}. +

sellrex

--- diff --git a/contracts/eosio.system/src/delegate_bandwidth.cpp b/contracts/eosio.system/src/delegate_bandwidth.cpp index f8fc6f67..ad27816c 100644 --- a/contracts/eosio.system/src/delegate_bandwidth.cpp +++ b/contracts/eosio.system/src/delegate_bandwidth.cpp @@ -94,12 +94,7 @@ namespace eosiosystem { }); } - auto voter_itr = _voters.find( res_itr->owner.value ); - if( voter_itr == _voters.end() || !has_field( voter_itr->flags1, voter_info::flags1_fields::ram_managed ) ) { - int64_t ram_bytes, net, cpu; - get_resource_limits( res_itr->owner, ram_bytes, net, cpu ); - set_resource_limits( res_itr->owner, res_itr->ram_bytes + ram_gift_bytes, net, cpu ); - } + set_resource_ram_bytes_limits( res_itr->owner, res_itr->ram_bytes ); } /** @@ -138,12 +133,7 @@ namespace eosiosystem { res.ram_bytes -= bytes; }); - auto voter_itr = _voters.find( res_itr->owner.value ); - if( voter_itr == _voters.end() || !has_field( voter_itr->flags1, voter_info::flags1_fields::ram_managed ) ) { - int64_t ram_bytes, net, cpu; - get_resource_limits( res_itr->owner, ram_bytes, net, cpu ); - set_resource_limits( res_itr->owner, res_itr->ram_bytes + ram_gift_bytes, net, cpu ); - } + set_resource_ram_bytes_limits( res_itr->owner, res_itr->ram_bytes ); { token::transfer_action transfer_act{ token_account, { {ram_account, active_permission}, {account, active_permission} } }; @@ -158,6 +148,55 @@ namespace eosiosystem { } } + /** + * This action will transfer RAM bytes from one account to another. + */ + void system_contract::ramtransfer( const name& from, const name& to, int64_t bytes ) { + require_auth( from ); + update_ram_supply(); + + check( bytes > 0, "cannot sell negative byte" ); + check(is_account(to), "to account does not exist"); + + user_resources_table userres( get_self(), from.value ); + + // reduce bytes from sender + auto from_itr = userres.find( from.value ); + check( from_itr != userres.end(), "no resource row" ); + check( from_itr->ram_bytes >= bytes, "insufficient quota" ); + + userres.modify( from_itr, from, [&]( auto& res ) { + res.ram_bytes -= bytes; + }); + + // add bytes to receiver + auto to_itr = userres.find( from.value ); + if ( to_itr == userres.end() ) { + to_itr = userres.emplace( from, [&]( auto& res ) { + res.owner = to; + res.net_weight = asset( 0, core_symbol() ); + res.cpu_weight = asset( 0, core_symbol() ); + res.ram_bytes = bytes; + }); + } else { + userres.modify( to_itr, from, [&]( auto& res ) { + res.ram_bytes += bytes; + }); + } + + set_resource_ram_bytes_limits( from_itr->owner, from_itr->ram_bytes ); + set_resource_ram_bytes_limits( to_itr->owner, to_itr->ram_bytes ); + } + + void set_resource_ram_bytes_limits( const name& owner, int64_t new_ram_bytes ) { + auto voter_itr = _voters.find( owner.value ); + if ( voter_itr == _voters.end() || !has_field( voter_itr->flags1, voter_info::flags1_fields::ram_managed ) ) { + int64_t ram_bytes, net, cpu; + get_resource_limits( owner, ram_bytes, net, cpu ); + set_resource_limits( owner, new_ram_bytes + ram_gift_bytes, net, cpu ); + } + } + void validate_b1_vesting( int64_t stake ) { const int64_t base_time = 1527811200; /// Friday, June 1, 2018 12:00:00 AM UTC const int64_t current_time = 1638921540; /// Tuesday, December 7, 2021 11:59:00 PM UTC diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 7ae4ed68..a72e8c18 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -4124,6 +4124,27 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_small_rex, eosio_system_tester ) try { } FC_LOG_AND_RETHROW() +// RAM transfer +BOOST_FIXTURE_TEST_CASE( ram_transfer, eosio_system_tester ) try { + const name alice = "alice1111111"_n; + const name bob = "bobbyaccount"_n; + + transfer( config::system_account_name, alice, core_sym::from_string("100.0000"), config::system_account_name ); + BOOST_REQUIRE_EQUAL( success(), buyrambytes( alice, alice, 1000 ) ); + + const uint64_t alice_before = get_total_stake( alice )["ram_bytes"]; + const uint64_t bob_before = get_total_stake( bob )["ram_bytes"]; + + BOOST_REQUIRE_EQUAL( success(), ramtransfer( alice, bob, 1000 ) ); + + const uint64_t alice_after = get_total_stake( alice )["ram_bytes"]; + const uint64_t bob_after = get_total_stake( bob )["ram_bytes"]; + + BOOST_REQUIRE_EQUAL( alice_before - 1000, alice_after ); + BOOST_REQUIRE_EQUAL( bob_before + 1000, bob_after ); + +} FC_LOG_AND_RETHROW() + BOOST_FIXTURE_TEST_CASE( unstake_buy_rex, eosio_system_tester, * boost::unit_test::tolerance(1e-10) ) try { const int64_t ratio = 10000; From c46257b30e03c49b879f79e6cf1f8644a3e15c90 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Fri, 5 Jan 2024 23:01:15 -0500 Subject: [PATCH 66/96] add system_contract --- contracts/eosio.system/src/delegate_bandwidth.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/eosio.system/src/delegate_bandwidth.cpp b/contracts/eosio.system/src/delegate_bandwidth.cpp index ad27816c..ba75ae98 100644 --- a/contracts/eosio.system/src/delegate_bandwidth.cpp +++ b/contracts/eosio.system/src/delegate_bandwidth.cpp @@ -154,6 +154,7 @@ namespace eosiosystem { void system_contract::ramtransfer( const name& from, const name& to, int64_t bytes ) { require_auth( from ); update_ram_supply(); + require_recipient( to ); check( bytes > 0, "cannot sell negative byte" ); check(is_account(to), "to account does not exist"); @@ -188,7 +189,7 @@ namespace eosiosystem { set_resource_ram_bytes_limits( to_itr->owner, to_itr->ram_bytes ); } - void set_resource_ram_bytes_limits( const name& owner, int64_t new_ram_bytes ) { + void system_contract::set_resource_ram_bytes_limits( const name& owner, int64_t new_ram_bytes ) { auto voter_itr = _voters.find( owner.value ); if ( voter_itr == _voters.end() || !has_field( voter_itr->flags1, voter_info::flags1_fields::ram_managed ) ) { int64_t ram_bytes, net, cpu; From 1f2a274e3d718322283d648e8862f81a5a28ddf7 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Fri, 5 Jan 2024 23:13:49 -0500 Subject: [PATCH 67/96] add as_uint64 to tests --- tests/eosio.system_tests.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index a72e8c18..a7458e75 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -4132,13 +4132,13 @@ BOOST_FIXTURE_TEST_CASE( ram_transfer, eosio_system_tester ) try { transfer( config::system_account_name, alice, core_sym::from_string("100.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), buyrambytes( alice, alice, 1000 ) ); - const uint64_t alice_before = get_total_stake( alice )["ram_bytes"]; - const uint64_t bob_before = get_total_stake( bob )["ram_bytes"]; + const uint64_t alice_before = get_total_stake( alice )["ram_bytes"].as_uint64(); + const uint64_t bob_before = get_total_stake( bob )["ram_bytes"].as_uint64(); BOOST_REQUIRE_EQUAL( success(), ramtransfer( alice, bob, 1000 ) ); - const uint64_t alice_after = get_total_stake( alice )["ram_bytes"]; - const uint64_t bob_after = get_total_stake( bob )["ram_bytes"]; + const uint64_t alice_after = get_total_stake( alice )["ram_bytes"].as_uint64(); + const uint64_t bob_after = get_total_stake( bob )["ram_bytes"].as_uint64(); BOOST_REQUIRE_EQUAL( alice_before - 1000, alice_after ); BOOST_REQUIRE_EQUAL( bob_before + 1000, bob_after ); From 1d8a12c764140c99938014a35c57d004a4731bdd Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Sat, 6 Jan 2024 00:01:19 -0500 Subject: [PATCH 68/96] update ramtransfer tests --- .../eosio.system/include/eosio.system/eosio.system.hpp | 1 + tests/eosio.system_tester.hpp | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index cd968633..ecc8289e 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1428,6 +1428,7 @@ namespace eosiosystem { using buyram_action = eosio::action_wrapper<"buyram"_n, &system_contract::buyram>; using buyrambytes_action = eosio::action_wrapper<"buyrambytes"_n, &system_contract::buyrambytes>; using sellram_action = eosio::action_wrapper<"sellram"_n, &system_contract::sellram>; + using ramtransfer_action = eosio::action_wrapper<"ramtransfer"_n, &system_contract::ramtransfer>; using refund_action = eosio::action_wrapper<"refund"_n, &system_contract::refund>; using regproducer_action = eosio::action_wrapper<"regproducer"_n, &system_contract::regproducer>; using regproducer2_action = eosio::action_wrapper<"regproducer2"_n, &system_contract::regproducer2>; diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index 6eae96d2..dae8212e 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -253,6 +253,13 @@ class eosio_system_tester : public TESTER { return buyram( account_name(payer), account_name(receiver), eosin ); } + action_result ramtransfer( const account_name& from, const account_name& to, uint32_t bytes ) { + return push_action( payer, "ramtransfer"_n, mvo()( "from",from)("to",to)("bytes",bytes) ); + } + action_result ramtransfer( std::string_view from, std::string_view to, uint32_t bytes ) { + return push_action( payer, "ramtransfer"_n, mvo()( "from",from)("to",to)("bytes",bytes) ); + } + action_result buyrambytes( const account_name& payer, account_name receiver, uint32_t numbytes ) { return push_action( payer, "buyrambytes"_n, mvo()( "payer",payer)("receiver",receiver)("bytes",numbytes) ); } @@ -707,7 +714,7 @@ class eosio_system_tester : public TESTER { memcpy( data.data(), itr->value.data(), data.size() ); return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "rex_return_buckets", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } - + void setup_rex_accounts( const std::vector& accounts, const asset& init_balance, const asset& net = core_sym::from_string("80.0000"), From 3c26c765ebd6196d4f6549bd20b4a4eadc80c041 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Sat, 6 Jan 2024 00:08:24 -0500 Subject: [PATCH 69/96] fix tests --- tests/eosio.system_tester.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index dae8212e..371ca02a 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -257,7 +257,7 @@ class eosio_system_tester : public TESTER { return push_action( payer, "ramtransfer"_n, mvo()( "from",from)("to",to)("bytes",bytes) ); } action_result ramtransfer( std::string_view from, std::string_view to, uint32_t bytes ) { - return push_action( payer, "ramtransfer"_n, mvo()( "from",from)("to",to)("bytes",bytes) ); + return ramtransfer( payer, "ramtransfer"_n, mvo()( "from",from)("to",to)("bytes",bytes) ); } action_result buyrambytes( const account_name& payer, account_name receiver, uint32_t numbytes ) { From 693f110f6be41d0dac71f159eed9b3e8b1361468 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Sat, 6 Jan 2024 10:25:17 -0500 Subject: [PATCH 70/96] fix ramtransfer --- tests/eosio.system_tester.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index 371ca02a..65f47279 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -254,10 +254,10 @@ class eosio_system_tester : public TESTER { } action_result ramtransfer( const account_name& from, const account_name& to, uint32_t bytes ) { - return push_action( payer, "ramtransfer"_n, mvo()( "from",from)("to",to)("bytes",bytes) ); + return push_action( from, "ramtransfer"_n, mvo()( "from",from)("to",to)("bytes",bytes) ); } action_result ramtransfer( std::string_view from, std::string_view to, uint32_t bytes ) { - return ramtransfer( payer, "ramtransfer"_n, mvo()( "from",from)("to",to)("bytes",bytes) ); + return ramtransfer( account_name(from), account_name(to), bytes ); } action_result buyrambytes( const account_name& payer, account_name receiver, uint32_t numbytes ) { From c530aa57aa3a6c87f090c1e8c452f76ee6fe7981 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Sat, 6 Jan 2024 15:52:51 -0500 Subject: [PATCH 71/96] add reduce_ram & add_ram helpers --- .../include/eosio.system/eosio.system.hpp | 4 +- .../eosio.system/src/delegate_bandwidth.cpp | 79 +++++++------------ tests/eosio.system_tests.cpp | 14 ++-- 3 files changed, 41 insertions(+), 56 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index ecc8289e..5301a2da 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1507,7 +1507,9 @@ namespace eosiosystem { void changebw( name from, const name& receiver, const asset& stake_net_quantity, const asset& stake_cpu_quantity, bool transfer ); void update_voting_power( const name& voter, const asset& total_update ); - void set_resource_ram_bytes_limits( const name& owner, int64_t new_ram_bytes ); + void set_resource_ram_bytes_limits( const name& owner ); + void reduce_ram( const name& owner, int64_t bytes ); + void add_ram( const name& owner, int64_t bytes ); // defined in voting.cpp void register_producer( const name& producer, const eosio::block_signing_authority& producer_authority, const std::string& url, uint16_t location ); diff --git a/contracts/eosio.system/src/delegate_bandwidth.cpp b/contracts/eosio.system/src/delegate_bandwidth.cpp index ba75ae98..95d55a21 100644 --- a/contracts/eosio.system/src/delegate_bandwidth.cpp +++ b/contracts/eosio.system/src/delegate_bandwidth.cpp @@ -79,22 +79,7 @@ namespace eosiosystem { _gstate.total_ram_bytes_reserved += uint64_t(bytes_out); _gstate.total_ram_stake += quant_after_fee.amount; - user_resources_table userres( get_self(), receiver.value ); - auto res_itr = userres.find( receiver.value ); - if( res_itr == userres.end() ) { - res_itr = userres.emplace( receiver, [&]( auto& res ) { - res.owner = receiver; - res.net_weight = asset( 0, core_symbol() ); - res.cpu_weight = asset( 0, core_symbol() ); - res.ram_bytes = bytes_out; - }); - } else { - userres.modify( res_itr, receiver, [&]( auto& res ) { - res.ram_bytes += bytes_out; - }); - } - - set_resource_ram_bytes_limits( res_itr->owner, res_itr->ram_bytes ); + add_ram( receiver, bytes_out ); } /** @@ -106,13 +91,7 @@ namespace eosiosystem { void system_contract::sellram( const name& account, int64_t bytes ) { require_auth( account ); update_ram_supply(); - - check( bytes > 0, "cannot sell negative byte" ); - - user_resources_table userres( get_self(), account.value ); - auto res_itr = userres.find( account.value ); - check( res_itr != userres.end(), "no resource row" ); - check( res_itr->ram_bytes >= bytes, "insufficient quota" ); + reduce_ram(account, bytes); asset tokens_out; auto itr = _rammarket.find(ramcore_symbol.raw()); @@ -129,12 +108,6 @@ namespace eosiosystem { //// this shouldn't happen, but just in case it does we should prevent it check( _gstate.total_ram_stake >= 0, "error, attempt to unstake more tokens than previously staked" ); - userres.modify( res_itr, account, [&]( auto& res ) { - res.ram_bytes -= bytes; - }); - - set_resource_ram_bytes_limits( res_itr->owner, res_itr->ram_bytes ); - { token::transfer_action transfer_act{ token_account, { {ram_account, active_permission}, {account, active_permission} } }; transfer_act.send( ram_account, account, asset(tokens_out), "sell ram" ); @@ -154,47 +127,53 @@ namespace eosiosystem { void system_contract::ramtransfer( const name& from, const name& to, int64_t bytes ) { require_auth( from ); update_ram_supply(); + reduce_ram( from, bytes ); + add_ram( to, bytes ); require_recipient( to ); + } - check( bytes > 0, "cannot sell negative byte" ); - check(is_account(to), "to account does not exist"); - - user_resources_table userres( get_self(), from.value ); - - // reduce bytes from sender - auto from_itr = userres.find( from.value ); - check( from_itr != userres.end(), "no resource row" ); - check( from_itr->ram_bytes >= bytes, "insufficient quota" ); + void system_contract::reduce_ram( const name& owner, int64_t bytes ) { + check( bytes > 0, "cannot reduce negative byte" ); + user_resources_table userres( get_self(), owner.value ); + auto res_itr = userres.find( owner.value ); + check( res_itr != userres.end(), "no resource row" ); + check( res_itr->ram_bytes >= bytes, "insufficient quota" ); - userres.modify( from_itr, from, [&]( auto& res ) { + userres.modify( res_itr, same_payer, [&]( auto& res ) { res.ram_bytes -= bytes; }); + set_resource_ram_bytes_limits( owner ); + } - // add bytes to receiver - auto to_itr = userres.find( from.value ); - if ( to_itr == userres.end() ) { - to_itr = userres.emplace( from, [&]( auto& res ) { - res.owner = to; + void system_contract::add_ram( const name& owner, int64_t bytes ) { + check( bytes > 0, "cannot add negative byte" ); + check( is_account(owner), "owner=" + owner.to_string() + " account does not exist"); + user_resources_table userres( get_self(), owner.value ); + auto res_itr = userres.find( owner.value ); + if ( res_itr == userres.end() ) { + userres.emplace( owner, [&]( auto& res ) { + res.owner = owner; res.net_weight = asset( 0, core_symbol() ); res.cpu_weight = asset( 0, core_symbol() ); res.ram_bytes = bytes; }); } else { - userres.modify( to_itr, from, [&]( auto& res ) { + userres.modify( res_itr, same_payer, [&]( auto& res ) { res.ram_bytes += bytes; }); } - - set_resource_ram_bytes_limits( from_itr->owner, from_itr->ram_bytes ); - set_resource_ram_bytes_limits( to_itr->owner, to_itr->ram_bytes ); + set_resource_ram_bytes_limits( owner ); } - void system_contract::set_resource_ram_bytes_limits( const name& owner, int64_t new_ram_bytes ) { + void system_contract::set_resource_ram_bytes_limits( const name& owner ) { + user_resources_table userres( get_self(), owner.value ); + auto res_itr = userres.find( owner.value ); + auto voter_itr = _voters.find( owner.value ); if ( voter_itr == _voters.end() || !has_field( voter_itr->flags1, voter_info::flags1_fields::ram_managed ) ) { int64_t ram_bytes, net, cpu; get_resource_limits( owner, ram_bytes, net, cpu ); - set_resource_limits( owner, new_ram_bytes + ram_gift_bytes, net, cpu ); + set_resource_limits( owner, res_itr->ram_bytes + ram_gift_bytes, net, cpu ); } } diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index a7458e75..5796e8fa 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -3929,7 +3929,7 @@ BOOST_FIXTURE_TEST_CASE( rex_rounding_issue, eosio_system_tester ) try { auto rent_and_go = [&] (int cnt) { for(auto& rb : rexborrowers) { BOOST_REQUIRE_EQUAL( success(), - push_action( rb, "rentcpu"_n, + push_action( rb, "rentcpu"_n, mvo() ("from", rb) ("receiver", rb) @@ -4126,11 +4126,15 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_small_rex, eosio_system_tester ) try { // RAM transfer BOOST_FIXTURE_TEST_CASE( ram_transfer, eosio_system_tester ) try { - const name alice = "alice1111111"_n; - const name bob = "bobbyaccount"_n; + const std::vector accounts = { "alice"_n, "bob"_n }; + create_accounts_with_resources( accounts ); + const account_name alice = accounts[0]; + const account_name bob = accounts[1]; transfer( config::system_account_name, alice, core_sym::from_string("100.0000"), config::system_account_name ); - BOOST_REQUIRE_EQUAL( success(), buyrambytes( alice, alice, 1000 ) ); + transfer( config::system_account_name, bob, core_sym::from_string("100.0000"), config::system_account_name ); + BOOST_REQUIRE_EQUAL( success(), buyrambytes( alice, alice, 10000 ) ); + BOOST_REQUIRE_EQUAL( success(), buyrambytes( bob, bob, 10000 ) ); const uint64_t alice_before = get_total_stake( alice )["ram_bytes"].as_uint64(); const uint64_t bob_before = get_total_stake( bob )["ram_bytes"].as_uint64(); @@ -5553,7 +5557,7 @@ BOOST_FIXTURE_TEST_CASE( b1_vesting, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( wasm_assert_msg("b1 can only claim their tokens over 10 years"), unstake( b1, b1, final_amount, final_amount ) ); - BOOST_REQUIRE_EQUAL( wasm_assert_msg("must vote for at least 21 producers or for a proxy before buying REX"), + BOOST_REQUIRE_EQUAL( wasm_assert_msg("must vote for at least 21 producers or for a proxy before buying REX"), unstaketorex( b1, b1, final_amount - small_amount, final_amount - small_amount ) ); BOOST_REQUIRE_EQUAL( error("missing authority of eosio"), vote( b1, { }, "proxyaccount"_n ) ); From 96509e767f2647378ea4a17769601690592bc87b Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Sat, 6 Jan 2024 16:10:08 -0500 Subject: [PATCH 72/96] update tests --- tests/eosio.system_ram_tests.cpp | 42 ++++++++++++++++++++++++++++++++ tests/eosio.system_tests.cpp | 26 -------------------- 2 files changed, 42 insertions(+), 26 deletions(-) create mode 100644 tests/eosio.system_ram_tests.cpp diff --git a/tests/eosio.system_ram_tests.cpp b/tests/eosio.system_ram_tests.cpp new file mode 100644 index 00000000..043d7451 --- /dev/null +++ b/tests/eosio.system_ram_tests.cpp @@ -0,0 +1,42 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "eosio.system_tester.hpp" + +using namespace eosio_system; + +BOOST_AUTO_TEST_SUITE(eosio_system_ram_tests) + +BOOST_FIXTURE_TEST_CASE( ram_transfer, eosio_system_tester ) try { + const std::vector accounts = { "alice"_n, "bob"_n }; + create_accounts_with_resources( accounts ); + const account_name alice = accounts[0]; + const account_name bob = accounts[1]; + + transfer( config::system_account_name, alice, core_sym::from_string("100.0000"), config::system_account_name ); + transfer( config::system_account_name, bob, core_sym::from_string("100.0000"), config::system_account_name ); + BOOST_REQUIRE_EQUAL( success(), buyrambytes( alice, alice, 10000 ) ); + BOOST_REQUIRE_EQUAL( success(), buyrambytes( bob, bob, 10000 ) ); + + const uint64_t alice_before = get_total_stake( alice )["ram_bytes"].as_uint64(); + const uint64_t bob_before = get_total_stake( bob )["ram_bytes"].as_uint64(); + + BOOST_REQUIRE_EQUAL( success(), ramtransfer( alice, bob, 1000 ) ); + + const uint64_t alice_after = get_total_stake( alice )["ram_bytes"].as_uint64(); + const uint64_t bob_after = get_total_stake( bob )["ram_bytes"].as_uint64(); + + BOOST_REQUIRE_EQUAL( alice_before - 1000, alice_after ); + BOOST_REQUIRE_EQUAL( bob_before + 1000, bob_after ); + +} FC_LOG_AND_RETHROW() + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 5796e8fa..37d8e9cf 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -4123,32 +4123,6 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_small_rex, eosio_system_tester ) try { } FC_LOG_AND_RETHROW() - -// RAM transfer -BOOST_FIXTURE_TEST_CASE( ram_transfer, eosio_system_tester ) try { - const std::vector accounts = { "alice"_n, "bob"_n }; - create_accounts_with_resources( accounts ); - const account_name alice = accounts[0]; - const account_name bob = accounts[1]; - - transfer( config::system_account_name, alice, core_sym::from_string("100.0000"), config::system_account_name ); - transfer( config::system_account_name, bob, core_sym::from_string("100.0000"), config::system_account_name ); - BOOST_REQUIRE_EQUAL( success(), buyrambytes( alice, alice, 10000 ) ); - BOOST_REQUIRE_EQUAL( success(), buyrambytes( bob, bob, 10000 ) ); - - const uint64_t alice_before = get_total_stake( alice )["ram_bytes"].as_uint64(); - const uint64_t bob_before = get_total_stake( bob )["ram_bytes"].as_uint64(); - - BOOST_REQUIRE_EQUAL( success(), ramtransfer( alice, bob, 1000 ) ); - - const uint64_t alice_after = get_total_stake( alice )["ram_bytes"].as_uint64(); - const uint64_t bob_after = get_total_stake( bob )["ram_bytes"].as_uint64(); - - BOOST_REQUIRE_EQUAL( alice_before - 1000, alice_after ); - BOOST_REQUIRE_EQUAL( bob_before + 1000, bob_after ); - -} FC_LOG_AND_RETHROW() - BOOST_FIXTURE_TEST_CASE( unstake_buy_rex, eosio_system_tester, * boost::unit_test::tolerance(1e-10) ) try { const int64_t ratio = 10000; From 8bfc7d06b3348fb55a7dc49f9c69265782b00e67 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Sat, 6 Jan 2024 17:19:18 -0500 Subject: [PATCH 73/96] add logbuyram action --- .../include/eosio.system/eosio.system.hpp | 12 ++++++++++++ contracts/eosio.system/src/delegate_bandwidth.cpp | 11 +++++++++++ 2 files changed, 23 insertions(+) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 4c2574fa..c6dd81dc 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1110,6 +1110,17 @@ namespace eosiosystem { [[eosio::action]] void buyrambytes( const name& payer, const name& receiver, uint32_t bytes ); + /** + * Logging for buyram & buyrambytes action + * + * @param payer - the ram buyer, + * @param receiver - the ram receiver, + * @param quant - the quantity of tokens to buy ram with. + * @param bytes - the quantity of ram to buy specified in bytes. + */ + [[eosio::action]] + void logbuyram( const name& payer, const name& receiver, const asset& quant, uint32_t bytes ); + /** * Sell ram action, reduces quota by bytes and then performs an inline transfer of tokens * to receiver based upon the average purchase price of the original quota. @@ -1417,6 +1428,7 @@ namespace eosiosystem { using undelegatebw_action = eosio::action_wrapper<"undelegatebw"_n, &system_contract::undelegatebw>; using buyram_action = eosio::action_wrapper<"buyram"_n, &system_contract::buyram>; using buyrambytes_action = eosio::action_wrapper<"buyrambytes"_n, &system_contract::buyrambytes>; + using logbuyram_action = eosio::action_wrapper<"logbuyram"_n, &system_contract::logbuyram>; using sellram_action = eosio::action_wrapper<"sellram"_n, &system_contract::sellram>; using refund_action = eosio::action_wrapper<"refund"_n, &system_contract::refund>; using regproducer_action = eosio::action_wrapper<"regproducer"_n, &system_contract::regproducer>; diff --git a/contracts/eosio.system/src/delegate_bandwidth.cpp b/contracts/eosio.system/src/delegate_bandwidth.cpp index f8fc6f67..db620f48 100644 --- a/contracts/eosio.system/src/delegate_bandwidth.cpp +++ b/contracts/eosio.system/src/delegate_bandwidth.cpp @@ -44,6 +44,7 @@ namespace eosiosystem { { require_auth( payer ); update_ram_supply(); + require_recipient(receiver); check( quant.symbol == core_symbol(), "must buy ram with core token" ); check( quant.amount > 0, "must purchase a positive amount" ); @@ -100,6 +101,16 @@ namespace eosiosystem { get_resource_limits( res_itr->owner, ram_bytes, net, cpu ); set_resource_limits( res_itr->owner, res_itr->ram_bytes + ram_gift_bytes, net, cpu ); } + + // logging + system_contract::logbuyram_action logbuyram_act{ get_self(), { {get_self(), active_permission} } }; + logbuyram_act.send( payer, receiver, quant, bytes_out ); + } + + void system_contract::logbuyram( const name& payer, const name& receiver, const asset& quant, uint32_t bytes ) { + require_auth( get_self() ); + require_recipient(payer); + require_recipient(receiver); } /** From 03900bc03f49e841d3c1e0824a89efb850fe3f01 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Sun, 7 Jan 2024 13:08:28 -0500 Subject: [PATCH 74/96] Implement `ramburn` action --- .../include/eosio.system/eosio.system.hpp | 10 ++++++++++ .../ricardian/eosio.system.contracts.md.in | 11 +++++++++++ contracts/eosio.system/src/delegate_bandwidth.cpp | 8 ++++++++ tests/eosio.system_ram_tests.cpp | 5 +++++ tests/eosio.system_tester.hpp | 7 +++++++ 5 files changed, 41 insertions(+) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 5301a2da..4a8b72a4 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1130,6 +1130,15 @@ namespace eosiosystem { [[eosio::action]] void ramtransfer( const name& from, const name& to, int64_t bytes ); + /** + * Burn ram action, reduces owner's quota by bytes. + * + * @param owner - the ram owner account, + * @param bytes - the amount of ram to be burned in bytes. + */ + [[eosio::action]] + void ramburn( const name& owner, int64_t bytes ); + /** * Refund action, this action is called after the delegation-period to claim all pending * unstaked tokens belonging to owner. @@ -1429,6 +1438,7 @@ namespace eosiosystem { using buyrambytes_action = eosio::action_wrapper<"buyrambytes"_n, &system_contract::buyrambytes>; using sellram_action = eosio::action_wrapper<"sellram"_n, &system_contract::sellram>; using ramtransfer_action = eosio::action_wrapper<"ramtransfer"_n, &system_contract::ramtransfer>; + using ramburn_action = eosio::action_wrapper<"ramburn"_n, &system_contract::ramburn>; using refund_action = eosio::action_wrapper<"refund"_n, &system_contract::refund>; using regproducer_action = eosio::action_wrapper<"regproducer"_n, &system_contract::regproducer>; using regproducer2_action = eosio::action_wrapper<"regproducer2"_n, &system_contract::regproducer2>; diff --git a/contracts/eosio.system/ricardian/eosio.system.contracts.md.in b/contracts/eosio.system/ricardian/eosio.system.contracts.md.in index 98955037..72a978b6 100644 --- a/contracts/eosio.system/ricardian/eosio.system.contracts.md.in +++ b/contracts/eosio.system/ricardian/eosio.system.contracts.md.in @@ -424,6 +424,17 @@ icon: @ICON_BASE_URL@/@RESOURCE_ICON_URI@ Transfer {{bytes}} bytes of unused RAM from account {{from}} to account {{to}}. +

ramburn

+ +--- +spec_version: "0.2.0" +title: Burn RAM from Account +summary: 'Burn unused RAM from {{nowrap from}}' +icon: @ICON_BASE_URL@/@RESOURCE_ICON_URI@ +--- + +Burn {{bytes}} bytes of unused RAM from account {{from}}. +

sellrex

--- diff --git a/contracts/eosio.system/src/delegate_bandwidth.cpp b/contracts/eosio.system/src/delegate_bandwidth.cpp index 95d55a21..905aa047 100644 --- a/contracts/eosio.system/src/delegate_bandwidth.cpp +++ b/contracts/eosio.system/src/delegate_bandwidth.cpp @@ -132,6 +132,14 @@ namespace eosiosystem { require_recipient( to ); } + /** + * This action will burn RAM bytes from owner account. + */ + void system_contract::ramburn( const name& owner, int64_t bytes ) { + require_auth( owner ); + ramtransfer( owner, null_account, bytes ); + } + void system_contract::reduce_ram( const name& owner, int64_t bytes ) { check( bytes > 0, "cannot reduce negative byte" ); user_resources_table userres( get_self(), owner.value ); diff --git a/tests/eosio.system_ram_tests.cpp b/tests/eosio.system_ram_tests.cpp index 043d7451..1b32eac9 100644 --- a/tests/eosio.system_ram_tests.cpp +++ b/tests/eosio.system_ram_tests.cpp @@ -37,6 +37,11 @@ BOOST_FIXTURE_TEST_CASE( ram_transfer, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( alice_before - 1000, alice_after ); BOOST_REQUIRE_EQUAL( bob_before + 1000, bob_after ); + // RAM burn + BOOST_REQUIRE_EQUAL( success(), ramburn( alice, 1000 ) ); + const uint64_t alice_after_burn = get_total_stake( alice )["ram_bytes"].as_uint64(); + BOOST_REQUIRE_EQUAL( alice_before - 2000, alice_after_burn ); + } FC_LOG_AND_RETHROW() BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index 65f47279..ce6038b1 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -260,6 +260,13 @@ class eosio_system_tester : public TESTER { return ramtransfer( account_name(from), account_name(to), bytes ); } + action_result ramburn( const account_name& owner, const account_name& to, uint32_t bytes ) { + return push_action( owner, "ramburn"_n, mvo()( "owner",owner)("bytes",bytes) ); + } + action_result ramburn( std::string_view owner, uint32_t bytes ) { + return ramburn( account_name(owner), bytes ); + } + action_result buyrambytes( const account_name& payer, account_name receiver, uint32_t numbytes ) { return push_action( payer, "buyrambytes"_n, mvo()( "payer",payer)("receiver",receiver)("bytes",numbytes) ); } From a0ff4e94ac4dd05c4249ba070ff98a23ce9540f9 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Sun, 7 Jan 2024 13:23:59 -0500 Subject: [PATCH 75/96] fix ramburn tests --- tests/eosio.system_tester.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index ce6038b1..7559454e 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -260,7 +260,7 @@ class eosio_system_tester : public TESTER { return ramtransfer( account_name(from), account_name(to), bytes ); } - action_result ramburn( const account_name& owner, const account_name& to, uint32_t bytes ) { + action_result ramburn( const account_name& owner, uint32_t bytes ) { return push_action( owner, "ramburn"_n, mvo()( "owner",owner)("bytes",bytes) ); } action_result ramburn( std::string_view owner, uint32_t bytes ) { From 244768a52314539680e12074751a3de63d01e7de Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Sun, 7 Jan 2024 13:50:51 -0500 Subject: [PATCH 76/96] add memo field to ramtransfer & ramburn --- .../include/eosio.system/eosio.system.hpp | 10 ++++++---- .../ricardian/eosio.system.contracts.md.in | 8 ++++++++ .../eosio.system/src/delegate_bandwidth.cpp | 9 +++++---- tests/eosio.system_ram_tests.cpp | 4 ++-- tests/eosio.system_tester.hpp | 16 ++++++++-------- 5 files changed, 29 insertions(+), 18 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 4a8b72a4..5d6c93fc 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1125,19 +1125,21 @@ namespace eosiosystem { * * @param from - the ram sender account, * @param to - the ram receiver account, - * @param bytes - the amount of ram to transfer in bytes. + * @param bytes - the amount of ram to transfer in bytes, + * @param memo - the memo string to accompany the transaction. */ [[eosio::action]] - void ramtransfer( const name& from, const name& to, int64_t bytes ); + void ramtransfer( const name& from, const name& to, int64_t bytes, const std::string& memo ); /** * Burn ram action, reduces owner's quota by bytes. * * @param owner - the ram owner account, - * @param bytes - the amount of ram to be burned in bytes. + * @param bytes - the amount of ram to be burned in bytes, + * @param memo - the memo string to accompany the transaction. */ [[eosio::action]] - void ramburn( const name& owner, int64_t bytes ); + void ramburn( const name& owner, int64_t bytes, const std::string& memo ); /** * Refund action, this action is called after the delegation-period to claim all pending diff --git a/contracts/eosio.system/ricardian/eosio.system.contracts.md.in b/contracts/eosio.system/ricardian/eosio.system.contracts.md.in index 72a978b6..25ccf839 100644 --- a/contracts/eosio.system/ricardian/eosio.system.contracts.md.in +++ b/contracts/eosio.system/ricardian/eosio.system.contracts.md.in @@ -424,6 +424,10 @@ icon: @ICON_BASE_URL@/@RESOURCE_ICON_URI@ Transfer {{bytes}} bytes of unused RAM from account {{from}} to account {{to}}. +{{#if memo}}There is a memo attached to the transfer stating: +{{memo}} +{{/if}} +

ramburn

--- @@ -435,6 +439,10 @@ icon: @ICON_BASE_URL@/@RESOURCE_ICON_URI@ Burn {{bytes}} bytes of unused RAM from account {{from}}. +{{#if memo}}There is a memo attached to the transfer stating: +{{memo}} +{{/if}} +

sellrex

--- diff --git a/contracts/eosio.system/src/delegate_bandwidth.cpp b/contracts/eosio.system/src/delegate_bandwidth.cpp index 905aa047..bee91f9e 100644 --- a/contracts/eosio.system/src/delegate_bandwidth.cpp +++ b/contracts/eosio.system/src/delegate_bandwidth.cpp @@ -123,10 +123,11 @@ namespace eosiosystem { /** * This action will transfer RAM bytes from one account to another. - */ - void system_contract::ramtransfer( const name& from, const name& to, int64_t bytes ) { + */ + void system_contract::ramtransfer( const name& from, const name& to, int64_t bytes, const std::string& memo ) { require_auth( from ); update_ram_supply(); + check( memo.size() <= 256, "memo has more than 256 bytes" ); reduce_ram( from, bytes ); add_ram( to, bytes ); require_recipient( to ); @@ -135,9 +136,9 @@ namespace eosiosystem { /** * This action will burn RAM bytes from owner account. */ - void system_contract::ramburn( const name& owner, int64_t bytes ) { + void system_contract::ramburn( const name& owner, int64_t bytes, const std::string& memo ) { require_auth( owner ); - ramtransfer( owner, null_account, bytes ); + ramtransfer( owner, null_account, bytes, memo ); } void system_contract::reduce_ram( const name& owner, int64_t bytes ) { diff --git a/tests/eosio.system_ram_tests.cpp b/tests/eosio.system_ram_tests.cpp index 1b32eac9..137a6ba6 100644 --- a/tests/eosio.system_ram_tests.cpp +++ b/tests/eosio.system_ram_tests.cpp @@ -29,7 +29,7 @@ BOOST_FIXTURE_TEST_CASE( ram_transfer, eosio_system_tester ) try { const uint64_t alice_before = get_total_stake( alice )["ram_bytes"].as_uint64(); const uint64_t bob_before = get_total_stake( bob )["ram_bytes"].as_uint64(); - BOOST_REQUIRE_EQUAL( success(), ramtransfer( alice, bob, 1000 ) ); + BOOST_REQUIRE_EQUAL( success(), ramtransfer( alice, bob, 1000, "" ) ); const uint64_t alice_after = get_total_stake( alice )["ram_bytes"].as_uint64(); const uint64_t bob_after = get_total_stake( bob )["ram_bytes"].as_uint64(); @@ -38,7 +38,7 @@ BOOST_FIXTURE_TEST_CASE( ram_transfer, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( bob_before + 1000, bob_after ); // RAM burn - BOOST_REQUIRE_EQUAL( success(), ramburn( alice, 1000 ) ); + BOOST_REQUIRE_EQUAL( success(), ramburn( alice, 1000, "burn RAM memo" ) ); const uint64_t alice_after_burn = get_total_stake( alice )["ram_bytes"].as_uint64(); BOOST_REQUIRE_EQUAL( alice_before - 2000, alice_after_burn ); diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index 7559454e..617d2545 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -253,18 +253,18 @@ class eosio_system_tester : public TESTER { return buyram( account_name(payer), account_name(receiver), eosin ); } - action_result ramtransfer( const account_name& from, const account_name& to, uint32_t bytes ) { - return push_action( from, "ramtransfer"_n, mvo()( "from",from)("to",to)("bytes",bytes) ); + action_result ramtransfer( const account_name& from, const account_name& to, uint32_t bytes, const string& memo ) { + return push_action( from, "ramtransfer"_n, mvo()( "from",from)("to",to)("bytes",bytes)(("memo",memo)) ); } - action_result ramtransfer( std::string_view from, std::string_view to, uint32_t bytes ) { - return ramtransfer( account_name(from), account_name(to), bytes ); + action_result ramtransfer( std::string_view from, std::string_view to, uint32_t bytes, const string& memo ) { + return ramtransfer( account_name(from), account_name(to), bytes, memo ); } - action_result ramburn( const account_name& owner, uint32_t bytes ) { - return push_action( owner, "ramburn"_n, mvo()( "owner",owner)("bytes",bytes) ); + action_result ramburn( const account_name& owner, uint32_t bytes, const string& memo ) { + return push_action( owner, "ramburn"_n, mvo()( "owner",owner)("bytes",bytes)("memo",memo) ); } - action_result ramburn( std::string_view owner, uint32_t bytes ) { - return ramburn( account_name(owner), bytes ); + action_result ramburn( std::string_view owner, uint32_t bytes, const string& memo ) { + return ramburn( account_name(owner), bytes, memo ); } action_result buyrambytes( const account_name& payer, account_name receiver, uint32_t numbytes ) { From f13f15cf31e2242c94531b0b3dec9506db6b21ff Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Sun, 7 Jan 2024 13:54:23 -0500 Subject: [PATCH 77/96] update RC with owner --- .../eosio.system/ricardian/eosio.system.contracts.md.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/eosio.system/ricardian/eosio.system.contracts.md.in b/contracts/eosio.system/ricardian/eosio.system.contracts.md.in index 25ccf839..24e896a6 100644 --- a/contracts/eosio.system/ricardian/eosio.system.contracts.md.in +++ b/contracts/eosio.system/ricardian/eosio.system.contracts.md.in @@ -433,13 +433,13 @@ Transfer {{bytes}} bytes of unused RAM from account {{from}} to account {{to}}. --- spec_version: "0.2.0" title: Burn RAM from Account -summary: 'Burn unused RAM from {{nowrap from}}' +summary: 'Burn unused RAM from {{nowrap owner}}' icon: @ICON_BASE_URL@/@RESOURCE_ICON_URI@ --- -Burn {{bytes}} bytes of unused RAM from account {{from}}. +Burn {{bytes}} bytes of unused RAM from account {{owner}}. -{{#if memo}}There is a memo attached to the transfer stating: +{{#if memo}}There is a memo attached to the burn stating: {{memo}} {{/if}} From f159466c6e53d43fc17985e687fed860df365c9d Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Sun, 7 Jan 2024 14:08:13 -0500 Subject: [PATCH 78/96] update ram tests --- tests/eosio.system_ram_tests.cpp | 4 ++-- tests/eosio.system_tester.hpp | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/eosio.system_ram_tests.cpp b/tests/eosio.system_ram_tests.cpp index 137a6ba6..93a93ddc 100644 --- a/tests/eosio.system_ram_tests.cpp +++ b/tests/eosio.system_ram_tests.cpp @@ -38,9 +38,9 @@ BOOST_FIXTURE_TEST_CASE( ram_transfer, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( bob_before + 1000, bob_after ); // RAM burn - BOOST_REQUIRE_EQUAL( success(), ramburn( alice, 1000, "burn RAM memo" ) ); + BOOST_REQUIRE_EQUAL( success(), ramburn( alice, 3000, "burn RAM memo" ) ); const uint64_t alice_after_burn = get_total_stake( alice )["ram_bytes"].as_uint64(); - BOOST_REQUIRE_EQUAL( alice_before - 2000, alice_after_burn ); + BOOST_REQUIRE_EQUAL( alice_before - 4000, alice_after_burn ); } FC_LOG_AND_RETHROW() diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index 617d2545..a3a3e853 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -253,17 +253,17 @@ class eosio_system_tester : public TESTER { return buyram( account_name(payer), account_name(receiver), eosin ); } - action_result ramtransfer( const account_name& from, const account_name& to, uint32_t bytes, const string& memo ) { - return push_action( from, "ramtransfer"_n, mvo()( "from",from)("to",to)("bytes",bytes)(("memo",memo)) ); + action_result ramtransfer( const account_name& from, const account_name& to, uint32_t bytes, const std::string& memo ) { + return push_action( from, "ramtransfer"_n, mvo()( "from",from)("to",to)("bytes",bytes)("memo",memo)); } - action_result ramtransfer( std::string_view from, std::string_view to, uint32_t bytes, const string& memo ) { + action_result ramtransfer( std::string_view from, std::string_view to, uint32_t bytes, const std::string& memo ) { return ramtransfer( account_name(from), account_name(to), bytes, memo ); } - action_result ramburn( const account_name& owner, uint32_t bytes, const string& memo ) { + action_result ramburn( const account_name& owner, uint32_t bytes, const std::string& memo ) { return push_action( owner, "ramburn"_n, mvo()( "owner",owner)("bytes",bytes)("memo",memo) ); } - action_result ramburn( std::string_view owner, uint32_t bytes, const string& memo ) { + action_result ramburn( std::string_view owner, uint32_t bytes, const std::string& memo ) { return ramburn( account_name(owner), bytes, memo ); } From 4d4c2bde3cf4713477bbdee16713419aed4aba20 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Tue, 9 Jan 2024 16:11:48 -0500 Subject: [PATCH 79/96] add require recipient from --- contracts/eosio.system/src/delegate_bandwidth.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/eosio.system/src/delegate_bandwidth.cpp b/contracts/eosio.system/src/delegate_bandwidth.cpp index 95d55a21..8c70547d 100644 --- a/contracts/eosio.system/src/delegate_bandwidth.cpp +++ b/contracts/eosio.system/src/delegate_bandwidth.cpp @@ -129,6 +129,7 @@ namespace eosiosystem { update_ram_supply(); reduce_ram( from, bytes ); add_ram( to, bytes ); + require_recipient( from ); require_recipient( to ); } From 0703ea2ff416e22e5f2ea8bcdaedaf5eee791800 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Tue, 9 Jan 2024 16:48:53 -0500 Subject: [PATCH 80/96] add logsellram --- .../include/eosio.system/eosio.system.hpp | 17 +++++++++++++++-- .../eosio.system/src/delegate_bandwidth.cpp | 15 +++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index c6dd81dc..384de4c2 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1115,11 +1115,12 @@ namespace eosiosystem { * * @param payer - the ram buyer, * @param receiver - the ram receiver, - * @param quant - the quantity of tokens to buy ram with. + * @param quantity - the quantity of tokens to buy ram with. * @param bytes - the quantity of ram to buy specified in bytes. + * @param ram_bytes - the ram bytes held by receiver after the action. */ [[eosio::action]] - void logbuyram( const name& payer, const name& receiver, const asset& quant, uint32_t bytes ); + void logbuyram( const name& payer, const name& receiver, const asset& quantity, int64_t bytes, int64_t ram_bytes ); /** * Sell ram action, reduces quota by bytes and then performs an inline transfer of tokens @@ -1131,6 +1132,17 @@ namespace eosiosystem { [[eosio::action]] void sellram( const name& account, int64_t bytes ); + /** + * Logging for sellram action + * + * @param account - the ram seller, + * @param quantity - the quantity of tokens to sell ram with. + * @param bytes - the quantity of ram to sell specified in bytes. + * @param ram_bytes - the ram bytes held by account after the action. + */ + [[eosio::action]] + void logsellram( const name& account, const asset& quantity, int64_t bytes, int64_t ram_bytes ); + /** * Refund action, this action is called after the delegation-period to claim all pending * unstaked tokens belonging to owner. @@ -1430,6 +1442,7 @@ namespace eosiosystem { using buyrambytes_action = eosio::action_wrapper<"buyrambytes"_n, &system_contract::buyrambytes>; using logbuyram_action = eosio::action_wrapper<"logbuyram"_n, &system_contract::logbuyram>; using sellram_action = eosio::action_wrapper<"sellram"_n, &system_contract::sellram>; + using logsellram_action = eosio::action_wrapper<"logsellram"_n, &system_contract::logsellram>; using refund_action = eosio::action_wrapper<"refund"_n, &system_contract::refund>; using regproducer_action = eosio::action_wrapper<"regproducer"_n, &system_contract::regproducer>; using regproducer2_action = eosio::action_wrapper<"regproducer2"_n, &system_contract::regproducer2>; diff --git a/contracts/eosio.system/src/delegate_bandwidth.cpp b/contracts/eosio.system/src/delegate_bandwidth.cpp index db620f48..4088b97a 100644 --- a/contracts/eosio.system/src/delegate_bandwidth.cpp +++ b/contracts/eosio.system/src/delegate_bandwidth.cpp @@ -44,6 +44,7 @@ namespace eosiosystem { { require_auth( payer ); update_ram_supply(); + require_recipient(payer); require_recipient(receiver); check( quant.symbol == core_symbol(), "must buy ram with core token" ); @@ -104,10 +105,10 @@ namespace eosiosystem { // logging system_contract::logbuyram_action logbuyram_act{ get_self(), { {get_self(), active_permission} } }; - logbuyram_act.send( payer, receiver, quant, bytes_out ); + logbuyram_act.send( payer, receiver, quant, bytes_out, res_itr->ram_bytes ); } - void system_contract::logbuyram( const name& payer, const name& receiver, const asset& quant, uint32_t bytes ) { + void system_contract::logbuyram( const name& payer, const name& receiver, const asset& quantity, int64_t bytes, int64_t ram_bytes ) { require_auth( get_self() ); require_recipient(payer); require_recipient(receiver); @@ -122,6 +123,7 @@ namespace eosiosystem { void system_contract::sellram( const name& account, int64_t bytes ) { require_auth( account ); update_ram_supply(); + require_recipient(account); check( bytes > 0, "cannot sell negative byte" ); @@ -167,6 +169,15 @@ namespace eosiosystem { transfer_act.send( account, ramfee_account, asset(fee, core_symbol()), "sell ram fee" ); channel_to_rex( ramfee_account, asset(fee, core_symbol() )); } + + // logging + system_contract::logsellram_action logsellram_act{ get_self(), { {get_self(), active_permission} } }; + logsellram_act.send( account, tokens_out, bytes, res_itr->ram_bytes ); + } + + void system_contract::logsellram( const name& account, const asset& quantity, int64_t bytes, int64_t ram_bytes ) { + require_auth( get_self() ); + require_recipient(account); } void validate_b1_vesting( int64_t stake ) { From d1e6d97e67d8921068512617fede520b34917639 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Tue, 9 Jan 2024 17:54:52 -0500 Subject: [PATCH 81/96] add `logramchange` action --- .../include/eosio.system/eosio.system.hpp | 11 +++++++++++ contracts/eosio.system/src/delegate_bandwidth.cpp | 15 +++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 5301a2da..079bf1fe 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1130,6 +1130,16 @@ namespace eosiosystem { [[eosio::action]] void ramtransfer( const name& from, const name& to, int64_t bytes ); + /** + * Logging for ram changes + * + * @param owner - the ram owner account, + * @param bytes - the bytes balance change, + * @param ram_bytes - the ram bytes held by owner after the action. + */ + [[eosio::action]] + void logramchange( const name& owner, int64_t bytes, int64_t ram_bytes ); + /** * Refund action, this action is called after the delegation-period to claim all pending * unstaked tokens belonging to owner. @@ -1429,6 +1439,7 @@ namespace eosiosystem { using buyrambytes_action = eosio::action_wrapper<"buyrambytes"_n, &system_contract::buyrambytes>; using sellram_action = eosio::action_wrapper<"sellram"_n, &system_contract::sellram>; using ramtransfer_action = eosio::action_wrapper<"ramtransfer"_n, &system_contract::ramtransfer>; + using logramchange_action = eosio::action_wrapper<"logramchange"_n, &system_contract::logramchange>; using refund_action = eosio::action_wrapper<"refund"_n, &system_contract::refund>; using regproducer_action = eosio::action_wrapper<"regproducer"_n, &system_contract::regproducer>; using regproducer2_action = eosio::action_wrapper<"regproducer2"_n, &system_contract::regproducer2>; diff --git a/contracts/eosio.system/src/delegate_bandwidth.cpp b/contracts/eosio.system/src/delegate_bandwidth.cpp index 8c70547d..c5cae4af 100644 --- a/contracts/eosio.system/src/delegate_bandwidth.cpp +++ b/contracts/eosio.system/src/delegate_bandwidth.cpp @@ -133,6 +133,13 @@ namespace eosiosystem { require_recipient( to ); } + [[eosio::action]] + void system_contract::logramchange( const name& owner, int64_t bytes, int64_t ram_bytes ) + { + require_auth( get_self() ); + require_recipient( owner ); + } + void system_contract::reduce_ram( const name& owner, int64_t bytes ) { check( bytes > 0, "cannot reduce negative byte" ); user_resources_table userres( get_self(), owner.value ); @@ -144,6 +151,10 @@ namespace eosiosystem { res.ram_bytes -= bytes; }); set_resource_ram_bytes_limits( owner ); + + // logging + system_contract::logramchange_action logramchange_act{ get_self(), { {get_self(), active_permission} }}; + logramchange_act.send( owner, -bytes, res_itr->ram_bytes ); } void system_contract::add_ram( const name& owner, int64_t bytes ) { @@ -164,6 +175,10 @@ namespace eosiosystem { }); } set_resource_ram_bytes_limits( owner ); + + // logging + system_contract::logramchange_action logramchange_act{ get_self(), { {get_self(), active_permission} } }; + logramchange_act.send( owner, bytes, res_itr->ram_bytes ); } void system_contract::set_resource_ram_bytes_limits( const name& owner ) { From b21165791801f2d2a8b5ef82d86bae16e0ca3e2e Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Tue, 16 Jan 2024 14:39:28 -0500 Subject: [PATCH 82/96] return ram_bytes --- .../include/eosio.system/eosio.system.hpp | 4 ++-- contracts/eosio.system/src/delegate_bandwidth.cpp | 14 ++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index d280c7c9..5f7176f8 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1544,8 +1544,8 @@ namespace eosiosystem { const asset& stake_net_quantity, const asset& stake_cpu_quantity, bool transfer ); void update_voting_power( const name& voter, const asset& total_update ); void set_resource_ram_bytes_limits( const name& owner ); - void reduce_ram( const name& owner, int64_t bytes ); - void add_ram( const name& owner, int64_t bytes ); + int64_t reduce_ram( const name& owner, int64_t bytes ); + int64_t add_ram( const name& owner, int64_t bytes ); // defined in voting.cpp void register_producer( const name& producer, const eosio::block_signing_authority& producer_authority, const std::string& url, uint16_t location ); diff --git a/contracts/eosio.system/src/delegate_bandwidth.cpp b/contracts/eosio.system/src/delegate_bandwidth.cpp index 61cc335b..3cf04021 100644 --- a/contracts/eosio.system/src/delegate_bandwidth.cpp +++ b/contracts/eosio.system/src/delegate_bandwidth.cpp @@ -81,11 +81,11 @@ namespace eosiosystem { _gstate.total_ram_bytes_reserved += uint64_t(bytes_out); _gstate.total_ram_stake += quant_after_fee.amount; - add_ram( receiver, bytes_out ); + const int64_t ram_bytes = add_ram( receiver, bytes_out ); // logging system_contract::logbuyram_action logbuyram_act{ get_self(), { {get_self(), active_permission} } }; - logbuyram_act.send( payer, receiver, quant, bytes_out, res_itr->ram_bytes ); + logbuyram_act.send( payer, receiver, quant, bytes_out, ram_bytes ); } void system_contract::logbuyram( const name& payer, const name& receiver, const asset& quantity, int64_t bytes, int64_t ram_bytes ) { @@ -104,7 +104,7 @@ namespace eosiosystem { require_auth( account ); update_ram_supply(); require_recipient(account); - reduce_ram(account, bytes); + const int64_t ram_bytes = reduce_ram(account, bytes); asset tokens_out; auto itr = _rammarket.find(ramcore_symbol.raw()); @@ -135,7 +135,7 @@ namespace eosiosystem { // logging system_contract::logsellram_action logsellram_act{ get_self(), { {get_self(), active_permission} } }; - logsellram_act.send( account, tokens_out, bytes, res_itr->ram_bytes ); + logsellram_act.send( account, tokens_out, bytes, ram_bytes ); } void system_contract::logsellram( const name& account, const asset& quantity, int64_t bytes, int64_t ram_bytes ) { @@ -162,7 +162,7 @@ namespace eosiosystem { require_recipient( owner ); } - void system_contract::reduce_ram( const name& owner, int64_t bytes ) { + int64_t system_contract::reduce_ram( const name& owner, int64_t bytes ) { check( bytes > 0, "cannot reduce negative byte" ); user_resources_table userres( get_self(), owner.value ); auto res_itr = userres.find( owner.value ); @@ -177,9 +177,10 @@ namespace eosiosystem { // logging system_contract::logramchange_action logramchange_act{ get_self(), { {get_self(), active_permission} }}; logramchange_act.send( owner, -bytes, res_itr->ram_bytes ); + return res_itr->ram_bytes; } - void system_contract::add_ram( const name& owner, int64_t bytes ) { + int64_t system_contract::add_ram( const name& owner, int64_t bytes ) { check( bytes > 0, "cannot add negative byte" ); check( is_account(owner), "owner=" + owner.to_string() + " account does not exist"); user_resources_table userres( get_self(), owner.value ); @@ -201,6 +202,7 @@ namespace eosiosystem { // logging system_contract::logramchange_action logramchange_act{ get_self(), { {get_self(), active_permission} } }; logramchange_act.send( owner, bytes, res_itr->ram_bytes ); + return res_itr->ram_bytes; } void system_contract::set_resource_ram_bytes_limits( const name& owner ) { From 4e1eed950dd0791af36f9a560163ee7ed361e96e Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Wed, 24 Jan 2024 12:23:37 -0500 Subject: [PATCH 83/96] add null account burn tests --- tests/eosio.system_ram_tests.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/eosio.system_ram_tests.cpp b/tests/eosio.system_ram_tests.cpp index 93a93ddc..a99cbcf6 100644 --- a/tests/eosio.system_ram_tests.cpp +++ b/tests/eosio.system_ram_tests.cpp @@ -20,11 +20,13 @@ BOOST_FIXTURE_TEST_CASE( ram_transfer, eosio_system_tester ) try { create_accounts_with_resources( accounts ); const account_name alice = accounts[0]; const account_name bob = accounts[1]; + const account_name null_account = "eosio.null"_n; transfer( config::system_account_name, alice, core_sym::from_string("100.0000"), config::system_account_name ); transfer( config::system_account_name, bob, core_sym::from_string("100.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), buyrambytes( alice, alice, 10000 ) ); BOOST_REQUIRE_EQUAL( success(), buyrambytes( bob, bob, 10000 ) ); + BOOST_REQUIRE_EQUAL( success(), buyrambytes( alice, null_account, 10000 ) ); const uint64_t alice_before = get_total_stake( alice )["ram_bytes"].as_uint64(); const uint64_t bob_before = get_total_stake( bob )["ram_bytes"].as_uint64(); @@ -38,9 +40,13 @@ BOOST_FIXTURE_TEST_CASE( ram_transfer, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( bob_before + 1000, bob_after ); // RAM burn + const uint64_t null_before_burn = get_total_stake( null_account )["ram_bytes"].as_uint64(); + const uint64_t alice_before_burn = get_total_stake( alice )["ram_bytes"].as_uint64(); BOOST_REQUIRE_EQUAL( success(), ramburn( alice, 3000, "burn RAM memo" ) ); const uint64_t alice_after_burn = get_total_stake( alice )["ram_bytes"].as_uint64(); - BOOST_REQUIRE_EQUAL( alice_before - 4000, alice_after_burn ); + const uint64_t null_after_burn = get_total_stake( null_account )["ram_bytes"].as_uint64(); + BOOST_REQUIRE_EQUAL( alice_before_burn - 3000, alice_after_burn ); + BOOST_REQUIRE_EQUAL( null_before_burn + 3000, null_after_burn ); } FC_LOG_AND_RETHROW() From 83f4a1e946be7121c0a256d60bcf6476b60b45aa Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Thu, 25 Jan 2024 15:57:07 -0500 Subject: [PATCH 84/96] split ram burn tests --- tests/eosio.system_ram_tests.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/tests/eosio.system_ram_tests.cpp b/tests/eosio.system_ram_tests.cpp index a99cbcf6..df0948ef 100644 --- a/tests/eosio.system_ram_tests.cpp +++ b/tests/eosio.system_ram_tests.cpp @@ -15,18 +15,17 @@ using namespace eosio_system; BOOST_AUTO_TEST_SUITE(eosio_system_ram_tests) +// ramtransfer BOOST_FIXTURE_TEST_CASE( ram_transfer, eosio_system_tester ) try { const std::vector accounts = { "alice"_n, "bob"_n }; create_accounts_with_resources( accounts ); const account_name alice = accounts[0]; const account_name bob = accounts[1]; - const account_name null_account = "eosio.null"_n; transfer( config::system_account_name, alice, core_sym::from_string("100.0000"), config::system_account_name ); transfer( config::system_account_name, bob, core_sym::from_string("100.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), buyrambytes( alice, alice, 10000 ) ); BOOST_REQUIRE_EQUAL( success(), buyrambytes( bob, bob, 10000 ) ); - BOOST_REQUIRE_EQUAL( success(), buyrambytes( alice, null_account, 10000 ) ); const uint64_t alice_before = get_total_stake( alice )["ram_bytes"].as_uint64(); const uint64_t bob_before = get_total_stake( bob )["ram_bytes"].as_uint64(); @@ -39,9 +38,23 @@ BOOST_FIXTURE_TEST_CASE( ram_transfer, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( alice_before - 1000, alice_after ); BOOST_REQUIRE_EQUAL( bob_before + 1000, bob_after ); - // RAM burn +} FC_LOG_AND_RETHROW() + +// ramburn +BOOST_FIXTURE_TEST_CASE( ram_burn, eosio_system_tester ) try { + const std::vector accounts = { "alice"_n }; + create_accounts_with_resources( accounts ); + const account_name alice = accounts[0]; + const account_name null_account = "eosio.null"_n; + + transfer( config::system_account_name, alice, core_sym::from_string("100.0000"), config::system_account_name ); + BOOST_REQUIRE_EQUAL( success(), buyrambytes( alice, alice, 10000 ) ); + BOOST_REQUIRE_EQUAL( success(), buyrambytes( alice, null_account, 10000 ) ); + const uint64_t null_before_burn = get_total_stake( null_account )["ram_bytes"].as_uint64(); const uint64_t alice_before_burn = get_total_stake( alice )["ram_bytes"].as_uint64(); + + // burn action BOOST_REQUIRE_EQUAL( success(), ramburn( alice, 3000, "burn RAM memo" ) ); const uint64_t alice_after_burn = get_total_stake( alice )["ram_bytes"].as_uint64(); const uint64_t null_after_burn = get_total_stake( null_account )["ram_bytes"].as_uint64(); From 9dd2717699b8dc822e6874538431074dae863769 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Thu, 25 Jan 2024 17:16:21 -0500 Subject: [PATCH 85/96] Implement `buyramself` action ref: https://github.com/eosnetworkfoundation/eos-system-contracts/issues/105 --- .../include/eosio.system/eosio.system.hpp | 11 +++++++++++ .../ricardian/eosio.system.contracts.md.in | 11 +++++++++++ .../eosio.system/src/delegate_bandwidth.cpp | 6 ++++++ tests/eosio.system_ram_tests.cpp | 16 ++++++++++++++++ tests/eosio.system_tester.hpp | 4 ++++ 5 files changed, 48 insertions(+) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 887a899b..be88f739 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1110,6 +1110,17 @@ namespace eosiosystem { [[eosio::action]] void buyrambytes( const name& payer, const name& receiver, uint32_t bytes ); + /** + * The buyramself action is designed to enhance the permission security by allowing an account to purchase RAM exclusively for itself. + * This action prevents the potential risk associated with standard actions like buyram and buyrambytes, + * which can transfer EOS tokens out of the account, acting as a proxy for eosio.token::transfer. + * + * @param account - the ram buyer and receiver, + * @param quant - the quantity of tokens to buy ram with. + */ + [[eosio::action]] + void buyramself( const name& account, const asset& quant ); + /** * Logging for buyram & buyrambytes action * diff --git a/contracts/eosio.system/ricardian/eosio.system.contracts.md.in b/contracts/eosio.system/ricardian/eosio.system.contracts.md.in index 24e896a6..d82a209b 100644 --- a/contracts/eosio.system/ricardian/eosio.system.contracts.md.in +++ b/contracts/eosio.system/ricardian/eosio.system.contracts.md.in @@ -59,6 +59,17 @@ icon: @ICON_BASE_URL@/@RESOURCE_ICON_URI@ {{payer}} buys RAM on behalf of {{receiver}} by paying {{quant}}. This transaction will incur a 0.5% fee out of {{quant}} and the amount of RAM delivered will depend on market rates. +

buyramself

+ +--- +spec_version: "0.2.0" +title: Buy RAM self +summary: '{{nowrap account}} buys RAM to self by paying {{nowrap quant}}' +icon: @ICON_BASE_URL@/@RESOURCE_ICON_URI@ +--- + +{{account}} buys RAM to self by paying {{quant}}. This transaction will incur a 0.5% fee out of {{quant}} and the amount of RAM delivered will depend on market rates. +

buyrambytes

--- diff --git a/contracts/eosio.system/src/delegate_bandwidth.cpp b/contracts/eosio.system/src/delegate_bandwidth.cpp index d21a9650..86533822 100644 --- a/contracts/eosio.system/src/delegate_bandwidth.cpp +++ b/contracts/eosio.system/src/delegate_bandwidth.cpp @@ -31,6 +31,12 @@ namespace eosiosystem { buyram( payer, receiver, asset{ cost_plus_fee, core_symbol() } ); } + /** + * Buy self ram action, ram can only be purchased to itself. + */ + void system_contract::buyramself( const name& account, const asset& quant ) { + buyram( account, account, quant ); + } /** * When buying ram the payer irreversibly transfers quant to system contract and only diff --git a/tests/eosio.system_ram_tests.cpp b/tests/eosio.system_ram_tests.cpp index df0948ef..984394f6 100644 --- a/tests/eosio.system_ram_tests.cpp +++ b/tests/eosio.system_ram_tests.cpp @@ -63,4 +63,20 @@ BOOST_FIXTURE_TEST_CASE( ram_burn, eosio_system_tester ) try { } FC_LOG_AND_RETHROW() + +// buyramself +BOOST_FIXTURE_TEST_CASE( buy_ram_self, eosio_system_tester ) try { + const std::vector accounts = { "alice"_n }; + create_accounts_with_resources( accounts ); + const account_name alice = accounts[0]; + + transfer( config::system_account_name, alice, core_sym::from_string("100.0000"), config::system_account_name ); + const uint64_t alice_before = get_total_stake( alice )["ram_bytes"].as_uint64(); + BOOST_REQUIRE_EQUAL( success(), buyramself( alice, core_sym::from_string("1.0000")) ); + const uint64_t alice_after = get_total_stake( alice )["ram_bytes"].as_uint64(); + BOOST_REQUIRE_EQUAL( alice_before + 68375, alice_after ); + +} FC_LOG_AND_RETHROW() + + BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index a3a3e853..c839e2fb 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -281,6 +281,10 @@ class eosio_system_tester : public TESTER { return sellram( account_name(account), numbytes ); } + action_result buyramself( const account_name& account, const asset& quant ) { + return push_action( account, "buyramself"_n, mvo()( "account",account)("quant",quant) ); + } + action_result push_action( const account_name& signer, const action_name &name, const variant_object &data, bool auth = true ) { string action_type_name = abi_ser.get_action_type(name); From 4a365bd0350f55f15394c5b2b4dbea8f443b6e7c Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Thu, 25 Jan 2024 17:44:04 -0500 Subject: [PATCH 86/96] Add action return values ref: https://github.com/eosnetworkfoundation/eos-system-contracts/issues/106 --- .../include/eosio.system/eosio.system.hpp | 35 +++++++++++++++---- .../eosio.system/src/delegate_bandwidth.cpp | 31 ++++++++++------ 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index be88f739..2faf9269 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -545,6 +545,29 @@ namespace eosiosystem { asset stake_change; }; + struct action_return_sellram { + name account; + asset quantity; + int64_t bytes; + int64_t ram_bytes; + }; + + struct action_return_buyram { + name payer; + name receiver; + asset quantity; + int64_t bytes; + int64_t ram_bytes; + }; + + struct action_return_ramtransfer { + name from; + name to; + int64_t bytes; + int64_t from_ram_bytes; + int64_t to_ram_bytes; + }; + struct powerup_config_resource { std::optional current_weight_ratio; // Immediately set weight_ratio to this amount. 1x = 10^15. 0.01x = 10^13. // Do not specify to preserve the existing setting or use the default; @@ -1097,7 +1120,7 @@ namespace eosiosystem { * @param quant - the quantity of tokens to buy ram with. */ [[eosio::action]] - void buyram( const name& payer, const name& receiver, const asset& quant ); + action_return_buyram buyram( const name& payer, const name& receiver, const asset& quant ); /** * Buy a specific amount of ram bytes action. Increases receiver's ram in quantity of bytes provided. @@ -1108,7 +1131,7 @@ namespace eosiosystem { * @param bytes - the quantity of ram to buy specified in bytes. */ [[eosio::action]] - void buyrambytes( const name& payer, const name& receiver, uint32_t bytes ); + action_return_buyram buyrambytes( const name& payer, const name& receiver, uint32_t bytes ); /** * The buyramself action is designed to enhance the permission security by allowing an account to purchase RAM exclusively for itself. @@ -1119,7 +1142,7 @@ namespace eosiosystem { * @param quant - the quantity of tokens to buy ram with. */ [[eosio::action]] - void buyramself( const name& account, const asset& quant ); + action_return_buyram buyramself( const name& account, const asset& quant ); /** * Logging for buyram & buyrambytes action @@ -1141,7 +1164,7 @@ namespace eosiosystem { * @param bytes - the amount of ram to sell in bytes. */ [[eosio::action]] - void sellram( const name& account, int64_t bytes ); + action_return_sellram sellram( const name& account, int64_t bytes ); /** * Logging for sellram action @@ -1163,7 +1186,7 @@ namespace eosiosystem { * @param memo - the memo string to accompany the transaction. */ [[eosio::action]] - void ramtransfer( const name& from, const name& to, int64_t bytes, const std::string& memo ); + action_return_ramtransfer ramtransfer( const name& from, const name& to, int64_t bytes, const std::string& memo ); /** * Burn ram action, reduces owner's quota by bytes. @@ -1173,7 +1196,7 @@ namespace eosiosystem { * @param memo - the memo string to accompany the transaction. */ [[eosio::action]] - void ramburn( const name& owner, int64_t bytes, const std::string& memo ); + action_return_ramtransfer ramburn( const name& owner, int64_t bytes, const std::string& memo ); /** * Logging for ram changes diff --git a/contracts/eosio.system/src/delegate_bandwidth.cpp b/contracts/eosio.system/src/delegate_bandwidth.cpp index 86533822..f9696edc 100644 --- a/contracts/eosio.system/src/delegate_bandwidth.cpp +++ b/contracts/eosio.system/src/delegate_bandwidth.cpp @@ -22,20 +22,20 @@ namespace eosiosystem { /** * This action will buy an exact amount of ram and bill the payer the current market price. */ - void system_contract::buyrambytes( const name& payer, const name& receiver, uint32_t bytes ) { + action_return_buyram system_contract::buyrambytes( const name& payer, const name& receiver, uint32_t bytes ) { auto itr = _rammarket.find(ramcore_symbol.raw()); const int64_t ram_reserve = itr->base.balance.amount; const int64_t eos_reserve = itr->quote.balance.amount; const int64_t cost = exchange_state::get_bancor_input( ram_reserve, eos_reserve, bytes ); const int64_t cost_plus_fee = cost / double(0.995); - buyram( payer, receiver, asset{ cost_plus_fee, core_symbol() } ); + return buyram( payer, receiver, asset{ cost_plus_fee, core_symbol() } ); } /** * Buy self ram action, ram can only be purchased to itself. */ - void system_contract::buyramself( const name& account, const asset& quant ) { - buyram( account, account, quant ); + action_return_buyram system_contract::buyramself( const name& account, const asset& quant ) { + return buyram( account, account, quant ); } /** @@ -46,7 +46,7 @@ namespace eosiosystem { * RAM is a scarce resource whose supply is defined by global properties max_ram_size. RAM is * priced using the bancor algorithm such that price-per-byte with a constant reserve ratio of 100:1. */ - void system_contract::buyram( const name& payer, const name& receiver, const asset& quant ) + action_return_buyram system_contract::buyram( const name& payer, const name& receiver, const asset& quant ) { require_auth( payer ); update_ram_supply(); @@ -92,6 +92,9 @@ namespace eosiosystem { // logging system_contract::logbuyram_action logbuyram_act{ get_self(), { {get_self(), active_permission} } }; logbuyram_act.send( payer, receiver, quant, bytes_out, ram_bytes ); + + // action return value + return action_return_buyram{ payer, receiver, quant, bytes_out, ram_bytes }; } void system_contract::logbuyram( const name& payer, const name& receiver, const asset& quantity, int64_t bytes, int64_t ram_bytes ) { @@ -106,7 +109,7 @@ namespace eosiosystem { * tomorrow. Overall this will result in the market balancing the supply and demand * for RAM over time. */ - void system_contract::sellram( const name& account, int64_t bytes ) { + action_return_sellram system_contract::sellram( const name& account, int64_t bytes ) { require_auth( account ); update_ram_supply(); require_recipient(account); @@ -142,6 +145,9 @@ namespace eosiosystem { // logging system_contract::logsellram_action logsellram_act{ get_self(), { {get_self(), active_permission} } }; logsellram_act.send( account, tokens_out, bytes, ram_bytes ); + + // action return value + return action_return_sellram{ account, tokens_out, bytes, ram_bytes }; } void system_contract::logsellram( const name& account, const asset& quantity, int64_t bytes, int64_t ram_bytes ) { @@ -152,22 +158,25 @@ namespace eosiosystem { /** * This action will transfer RAM bytes from one account to another. */ - void system_contract::ramtransfer( const name& from, const name& to, int64_t bytes, const std::string& memo ) { + action_return_ramtransfer system_contract::ramtransfer( const name& from, const name& to, int64_t bytes, const std::string& memo ) { require_auth( from ); update_ram_supply(); check( memo.size() <= 256, "memo has more than 256 bytes" ); - reduce_ram( from, bytes ); - add_ram( to, bytes ); + const int64_t from_ram_bytes = reduce_ram( from, bytes ); + const int64_t to_ram_bytes = add_ram( to, bytes ); require_recipient( from ); require_recipient( to ); + + // action return value + return action_return_ramtransfer{ from, to, bytes, from_ram_bytes, to_ram_bytes }; } /** * This action will burn RAM bytes from owner account. */ - void system_contract::ramburn( const name& owner, int64_t bytes, const std::string& memo ) { + action_return_ramtransfer system_contract::ramburn( const name& owner, int64_t bytes, const std::string& memo ) { require_auth( owner ); - ramtransfer( owner, null_account, bytes, memo ); + return ramtransfer( owner, null_account, bytes, memo ); } [[eosio::action]] From 0251690333ddeeca2abb9c272148cd4c35818983 Mon Sep 17 00:00:00 2001 From: Eric Passmore Date: Fri, 26 Jan 2024 09:57:50 -0800 Subject: [PATCH 87/96] ramtransfer: action trace to capture return struct --- tests/eosio.system_ram_tests.cpp | 4 ++-- tests/eosio.system_tester.hpp | 26 +++++++++++++++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/tests/eosio.system_ram_tests.cpp b/tests/eosio.system_ram_tests.cpp index 984394f6..95e95648 100644 --- a/tests/eosio.system_ram_tests.cpp +++ b/tests/eosio.system_ram_tests.cpp @@ -13,7 +13,7 @@ using namespace eosio_system; -BOOST_AUTO_TEST_SUITE(eosio_system_ram_tests) +BOOST_AUTO_TEST_SUITE(eosio_system_ram_tests); // ramtransfer BOOST_FIXTURE_TEST_CASE( ram_transfer, eosio_system_tester ) try { @@ -30,7 +30,7 @@ BOOST_FIXTURE_TEST_CASE( ram_transfer, eosio_system_tester ) try { const uint64_t alice_before = get_total_stake( alice )["ram_bytes"].as_uint64(); const uint64_t bob_before = get_total_stake( bob )["ram_bytes"].as_uint64(); - BOOST_REQUIRE_EQUAL( success(), ramtransfer( alice, bob, 1000, "" ) ); + ramtransfer( alice, bob, 1000, "" ); const uint64_t alice_after = get_total_stake( alice )["ram_bytes"].as_uint64(); const uint64_t bob_after = get_total_stake( bob )["ram_bytes"].as_uint64(); diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index c839e2fb..ee566024 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -253,11 +253,27 @@ class eosio_system_tester : public TESTER { return buyram( account_name(payer), account_name(receiver), eosin ); } - action_result ramtransfer( const account_name& from, const account_name& to, uint32_t bytes, const std::string& memo ) { - return push_action( from, "ramtransfer"_n, mvo()( "from",from)("to",to)("bytes",bytes)("memo",memo)); - } - action_result ramtransfer( std::string_view from, std::string_view to, uint32_t bytes, const std::string& memo ) { - return ramtransfer( account_name(from), account_name(to), bytes, memo ); + void ramtransfer( const account_name& from, const account_name& to, uint32_t bytes, const std::string& memo ) { + struct action_return_ramtransfer { + name from; + name to; + int64_t bytes; + int64_t from_ram_bytes; + int64_t to_ram_bytes; + }; + + auto trace = base_tester::push_action( config::system_account_name, "ramtransfer"_n, from, mvo()( "from",from)("to",to)("bytes",bytes)("memo",memo)); + produce_block(); + BOOST_REQUIRE_EQUAL( true, chain_has_transaction(trace->id) ); + int64_t r_bytes = 0; + for ( size_t i = 0; i < trace->action_traces.size(); ++i ) { + if ( trace->action_traces[i].act.name == "bytes"_n ) { + fc::raw::unpack( trace->action_traces[i].act.data.data(), + trace->action_traces[i].act.data.size(), + r_bytes); + } + } + BOOST_REQUIRE_EQUAL(r_bytes, bytes); } action_result ramburn( const account_name& owner, uint32_t bytes, const std::string& memo ) { From 3fc1b47aa2fa39b4fca1f39b5ba27dc159ea5ce2 Mon Sep 17 00:00:00 2001 From: Eric Passmore Date: Fri, 26 Jan 2024 10:42:06 -0800 Subject: [PATCH 88/96] ramtransfer trace filter on act name and account --- tests/eosio.system_tester.hpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index ee566024..3fba239f 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -265,15 +265,17 @@ class eosio_system_tester : public TESTER { auto trace = base_tester::push_action( config::system_account_name, "ramtransfer"_n, from, mvo()( "from",from)("to",to)("bytes",bytes)("memo",memo)); produce_block(); BOOST_REQUIRE_EQUAL( true, chain_has_transaction(trace->id) ); - int64_t r_bytes = 0; + int64_t ramtransfer_return; + idump((trace->action_traces)); for ( size_t i = 0; i < trace->action_traces.size(); ++i ) { - if ( trace->action_traces[i].act.name == "bytes"_n ) { - fc::raw::unpack( trace->action_traces[i].act.data.data(), - trace->action_traces[i].act.data.size(), - r_bytes); + if ( trace->action_traces[i].act.name == "ramtransfer"_n && + trace->action_traces[i].act.account == "eosio"_n ) { + fc::raw::unpack( trace->action_traces[i].return_value.data(), + trace->action_traces[i].return_value.size(), + ramtransfer_return); } } - BOOST_REQUIRE_EQUAL(r_bytes, bytes); + //BOOST_REQUIRE_EQUAL(ramtransfer_return.bytes, bytes); } action_result ramburn( const account_name& owner, uint32_t bytes, const std::string& memo ) { From 1a75d4dcd5f5f55da7bcbedf196f478e31dfdbd2 Mon Sep 17 00:00:00 2001 From: Eric Passmore Date: Sun, 28 Jan 2024 20:53:33 -0800 Subject: [PATCH 89/96] streamlined code to support return struct in ram_actions --- tests/eosio.system_tester.hpp | 148 ++++++++++++++++++++-------------- 1 file changed, 87 insertions(+), 61 deletions(-) diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index 3fba239f..e008a8fc 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -1,10 +1,10 @@ #pragma once -#include -#include -#include #include "contracts.hpp" #include "test_symbol.hpp" +#include +#include +#include #include #include @@ -25,7 +25,6 @@ using mvo = fc::mutable_variant_object; namespace eosio_system { - class eosio_system_tester : public TESTER { public: @@ -202,6 +201,90 @@ class eosio_system_tester : public TESTER { trx.sign( get_private_key( creator, "active" ), control->get_chain_id() ); return push_transaction( trx ); } + action_result buyram( const account_name& payer, account_name receiver, const asset& eosin ) { + return push_action( payer, "buyram"_n, mvo()( "payer",payer)("receiver",receiver)("quant",eosin) ); + } + action_result buyram( std::string_view payer, std::string_view receiver, const asset& eosin ) { + return buyram( account_name(payer), account_name(receiver), eosin ); + } + + void ramtransfer(const account_name& from, const account_name& to, uint32_t bytes, const std::string& memo) + { + struct action_return_ramtransfer + { + name from; + name to; + int64_t bytes; + int64_t from_ram_bytes; + int64_t to_ram_bytes; + }; + // hold bytes from return data + // multiple records with 8 bytes in each record + // initialize up front to ensure clean data + uint8_t number_of_fields = 5; + uint8_t field_size = 8; + char ramtransfer_record[number_of_fields][field_size]; + for (int i = 0; i < number_of_fields; ++i) { + memset(ramtransfer_record[i], '\0', field_size); + } + + // execute transaction and get traces + auto trace = base_tester::push_action(config::system_account_name, "ramtransfer"_n, from, + mvo()("from", from)("to", to)("bytes", bytes)("memo", memo)); + produce_block(); + + // confirm we have trances and find the right one (should be trace idx == 0) + BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trace->id)); + for (size_t i = 0; i < trace->action_traces.size(); ++i) { + if (trace->action_traces[i].act.name == "ramtransfer"_n && trace->action_traces[i].act.account == "eosio"_n) { + + // debugging check return values, will be hex encoded + idump((trace->action_traces[i].return_value)); + + // pull out bytes from return_value in chunks by field_size, 8 bytes + // iterative over each record, then assign char by char for record + if ( trace->action_traces[i].return_value.size() >= (number_of_fields * field_size)) { + for (int rec_idx = 0; rec_idx < number_of_fields; ++rec_idx) { + std::memcpy(ramtransfer_record[rec_idx], + &trace->action_traces[i].return_value[rec_idx * field_size], + field_size); + } + } + // debugged check expect different values + idump((ramtransfer_record[0]));idump((ramtransfer_record[1]));idump((ramtransfer_record[2]));idump((ramtransfer_record[3])); + // TODO: convert from hex, populate struct action_return_ramtransfer, and return with function + } + } + } + + action_result ramburn(const account_name& owner, uint32_t bytes, const std::string& memo) + { + return push_action(owner, "ramburn"_n, mvo()("owner", owner)("bytes", bytes)("memo", memo)); + } + action_result ramburn(std::string_view owner, uint32_t bytes, const std::string& memo) + { + return ramburn(account_name(owner), bytes, memo); + } + + action_result buyrambytes(const account_name& payer, account_name receiver, uint32_t numbytes) + { + return push_action(payer, "buyrambytes"_n, mvo()("payer", payer)("receiver", receiver)("bytes", numbytes)); + } + action_result buyrambytes(std::string_view payer, std::string_view receiver, uint32_t numbytes) + { + return buyrambytes(account_name(payer), account_name(receiver), numbytes); + } + + action_result sellram(const account_name& account, uint64_t numbytes) + { + return push_action(account, "sellram"_n, mvo()("account", account)("bytes", numbytes)); + } + action_result sellram(std::string_view account, uint64_t numbytes) { return sellram(account_name(account), numbytes); } + + action_result buyramself(const account_name& account, const asset& quant) + { + return push_action(account, "buyramself"_n, mvo()("account", account)("quant", quant)); + } transaction_trace_ptr setup_producer_accounts( const std::vector& accounts, asset ram = core_sym::from_string("1.0000"), @@ -246,63 +329,6 @@ class eosio_system_tester : public TESTER { return push_transaction( trx ); } - action_result buyram( const account_name& payer, account_name receiver, const asset& eosin ) { - return push_action( payer, "buyram"_n, mvo()( "payer",payer)("receiver",receiver)("quant",eosin) ); - } - action_result buyram( std::string_view payer, std::string_view receiver, const asset& eosin ) { - return buyram( account_name(payer), account_name(receiver), eosin ); - } - - void ramtransfer( const account_name& from, const account_name& to, uint32_t bytes, const std::string& memo ) { - struct action_return_ramtransfer { - name from; - name to; - int64_t bytes; - int64_t from_ram_bytes; - int64_t to_ram_bytes; - }; - - auto trace = base_tester::push_action( config::system_account_name, "ramtransfer"_n, from, mvo()( "from",from)("to",to)("bytes",bytes)("memo",memo)); - produce_block(); - BOOST_REQUIRE_EQUAL( true, chain_has_transaction(trace->id) ); - int64_t ramtransfer_return; - idump((trace->action_traces)); - for ( size_t i = 0; i < trace->action_traces.size(); ++i ) { - if ( trace->action_traces[i].act.name == "ramtransfer"_n && - trace->action_traces[i].act.account == "eosio"_n ) { - fc::raw::unpack( trace->action_traces[i].return_value.data(), - trace->action_traces[i].return_value.size(), - ramtransfer_return); - } - } - //BOOST_REQUIRE_EQUAL(ramtransfer_return.bytes, bytes); - } - - action_result ramburn( const account_name& owner, uint32_t bytes, const std::string& memo ) { - return push_action( owner, "ramburn"_n, mvo()( "owner",owner)("bytes",bytes)("memo",memo) ); - } - action_result ramburn( std::string_view owner, uint32_t bytes, const std::string& memo ) { - return ramburn( account_name(owner), bytes, memo ); - } - - action_result buyrambytes( const account_name& payer, account_name receiver, uint32_t numbytes ) { - return push_action( payer, "buyrambytes"_n, mvo()( "payer",payer)("receiver",receiver)("bytes",numbytes) ); - } - action_result buyrambytes( std::string_view payer, std::string_view receiver, uint32_t numbytes ) { - return buyrambytes( account_name(payer), account_name(receiver), numbytes ); - } - - action_result sellram( const account_name& account, uint64_t numbytes ) { - return push_action( account, "sellram"_n, mvo()( "account", account)("bytes",numbytes) ); - } - action_result sellram( std::string_view account, uint64_t numbytes ) { - return sellram( account_name(account), numbytes ); - } - - action_result buyramself( const account_name& account, const asset& quant ) { - return push_action( account, "buyramself"_n, mvo()( "account",account)("quant",quant) ); - } - action_result push_action( const account_name& signer, const action_name &name, const variant_object &data, bool auth = true ) { string action_type_name = abi_ser.get_action_type(name); From e4a98d79861527721b282bbe6ebe0da8f1d48dfa Mon Sep 17 00:00:00 2001 From: Eric Passmore Date: Thu, 1 Feb 2024 09:07:06 -0800 Subject: [PATCH 90/96] Added tests for ram_actions Created method to compute hex from provided JSON, this can be used as the expected return code Created method to extract trace->act and return data Commits fail as return data does not survive outside for-loop and is empty when compared to expected value --- tests/eosio.system_ram_tests.cpp | 11 ++++ tests/eosio.system_tester.hpp | 110 +++++++++++++++++++++---------- 2 files changed, 87 insertions(+), 34 deletions(-) diff --git a/tests/eosio.system_ram_tests.cpp b/tests/eosio.system_ram_tests.cpp index 95e95648..053583a5 100644 --- a/tests/eosio.system_ram_tests.cpp +++ b/tests/eosio.system_ram_tests.cpp @@ -38,6 +38,17 @@ BOOST_FIXTURE_TEST_CASE( ram_transfer, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( alice_before - 1000, alice_after ); BOOST_REQUIRE_EQUAL( bob_before + 1000, bob_after ); + const char* expected_return_data = R"=====( +{ + "from": "alice", + "to": "bob", + "bytes": 1, + "from_ram_bytes": 16982, + "to_ram_bytes": 18984 +} +)====="; + validate_ramtransfer_return(alice, bob, 1, "", "action_return_ramtransfer", expected_return_data ); + } FC_LOG_AND_RETHROW() // ramburn diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index e008a8fc..fcc51b10 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -201,6 +201,7 @@ class eosio_system_tester : public TESTER { trx.sign( get_private_key( creator, "active" ), control->get_chain_id() ); return push_transaction( trx ); } + action_result buyram( const account_name& payer, account_name receiver, const asset& eosin ) { return push_action( payer, "buyram"_n, mvo()( "payer",payer)("receiver",receiver)("quant",eosin) ); } @@ -208,53 +209,94 @@ class eosio_system_tester : public TESTER { return buyram( account_name(payer), account_name(receiver), eosin ); } - void ramtransfer(const account_name& from, const account_name& to, uint32_t bytes, const std::string& memo) + std::string convert_json_to_hex(const type_name& type, const std::string& json) { + // ABI for our return struct + const char* ramtransfer_return_abi = R"=====( { - struct action_return_ramtransfer - { - name from; - name to; - int64_t bytes; - int64_t from_ram_bytes; - int64_t to_ram_bytes; - }; - // hold bytes from return data - // multiple records with 8 bytes in each record - // initialize up front to ensure clean data - uint8_t number_of_fields = 5; - uint8_t field_size = 8; - char ramtransfer_record[number_of_fields][field_size]; - for (int i = 0; i < number_of_fields; ++i) { - memset(ramtransfer_record[i], '\0', field_size); - } + "version": "eosio::abi/1.2", + "types": [], + "structs": [{ + "name": "action_return_ramtransfer", + "base": "", + "fields": [ + { + "name": "from", + "type": "name" + }, + { + "name": "to", + "type": "name" + }, + { + "name": "bytes", + "type": "int64" + }, + { + "name": "from_ram_bytes", + "type": "int64" + }, + { + "name": "to_ram_bytes", + "type": "int64" + } + ] + }], + "actions": [], + "tables": [], + "ricardian_clauses": [], + "variants": [], + "action_results": [ + { + "name": "ramtransfer", + "result_type": "action_return_ramtransfer" + } + ] + } + )====="; - // execute transaction and get traces + // create abi to parse return values + auto abi = fc::json::from_string(ramtransfer_return_abi).as(); + abi_serializer ramtransfer_return_serializer = abi_serializer{std::move(abi), abi_serializer::create_yield_function( abi_serializer_max_time )}; + + auto return_json = fc::json::from_string(json); + auto serialized_bytes = ramtransfer_return_serializer.variant_to_binary(type, return_json, abi_serializer::create_yield_function( abi_serializer_max_time )); + return fc::to_hex(serialized_bytes); + } + + action_result ramtransfer(const account_name& from, const account_name& to, uint32_t bytes, const std::string& memo) { + return push_action(from, "ramtransfer"_n, + mvo()("from", from)("to", to)("bytes", bytes)("memo", memo)); + } + + std::vector validate_ramtransfer_return(const account_name& from, const account_name& to, uint32_t bytes, const std::string& memo, + const type_name& type, const std::string& json) { + // create hex return from provided json + std::string expected_hex = convert_json_to_hex(type, json); + // initialize string that will hold actual return + std::string actual_hex; + + // execute transaction and get traces must use base_tester auto trace = base_tester::push_action(config::system_account_name, "ramtransfer"_n, from, mvo()("from", from)("to", to)("bytes", bytes)("memo", memo)); produce_block(); // confirm we have trances and find the right one (should be trace idx == 0) BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trace->id)); + for (size_t i = 0; i < trace->action_traces.size(); ++i) { if (trace->action_traces[i].act.name == "ramtransfer"_n && trace->action_traces[i].act.account == "eosio"_n) { - - // debugging check return values, will be hex encoded + /* + * This is assignment is giving me grief, value does not survive outside for loop, is empty + * Doing an idump((trace->action_traces[i].return_value)) will show the full hex + * Things I have tried full mem-copy, mem-copy by 8 bytes segments, iterating and copy char by char + * Return from here will return a weird 3 chars (dereference pointer). + */ idump((trace->action_traces[i].return_value)); - - // pull out bytes from return_value in chunks by field_size, 8 bytes - // iterative over each record, then assign char by char for record - if ( trace->action_traces[i].return_value.size() >= (number_of_fields * field_size)) { - for (int rec_idx = 0; rec_idx < number_of_fields; ++rec_idx) { - std::memcpy(ramtransfer_record[rec_idx], - &trace->action_traces[i].return_value[rec_idx * field_size], - field_size); - } - } - // debugged check expect different values - idump((ramtransfer_record[0]));idump((ramtransfer_record[1]));idump((ramtransfer_record[2]));idump((ramtransfer_record[3])); - // TODO: convert from hex, populate struct action_return_ramtransfer, and return with function + actual_hex = std::string(trace->action_traces[i].return_value.begin(), trace->action_traces[i].return_value.end()); } } + // test fails here actual_hex is empty + BOOST_REQUIRE_EQUAL(expected_hex,actual_hex); } action_result ramburn(const account_name& owner, uint32_t bytes, const std::string& memo) From 1e6065db0d2bc1773f37907260d335537a297924 Mon Sep 17 00:00:00 2001 From: Eric Passmore Date: Thu, 1 Feb 2024 16:46:46 -0800 Subject: [PATCH 91/96] added return struct tests for buyrambytes and sellram --- tests/eosio.system_ram_tests.cpp | 30 +++++ tests/eosio.system_tester.hpp | 212 +++++++++++++++++++++++++------ 2 files changed, 204 insertions(+), 38 deletions(-) diff --git a/tests/eosio.system_ram_tests.cpp b/tests/eosio.system_ram_tests.cpp index 053583a5..729032ca 100644 --- a/tests/eosio.system_ram_tests.cpp +++ b/tests/eosio.system_ram_tests.cpp @@ -51,6 +51,36 @@ BOOST_FIXTURE_TEST_CASE( ram_transfer, eosio_system_tester ) try { } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE( buy_sell_ram_validate, eosio_system_tester ) try { + const std::vector accounts = { "alice"_n }; + create_accounts_with_resources( accounts ); + const account_name alice = accounts[0]; + + transfer( config::system_account_name, alice, core_sym::from_string("100.0000"), config::system_account_name ); + + const char* expected_buyrambytes_return_data = R"=====( +{ + "payer": "alice", + "receiver": "alice", + "quantity": "0.1462 TST", + "bytes": 9991, + "ram_bytes": 17983 +} +)====="; + validate_buyrambytes_return(alice, alice, 10000, "action_return_buyram", expected_buyrambytes_return_data ); + +const char* expected_sellram_return_data = R"=====( +{ + "account": "alice", + "quantity": "0.1455 TST", + "bytes": 10000, + "ram_bytes": 7983 +} +)====="; + validate_sellram_return(alice, 10000, "action_return_sellram", expected_sellram_return_data ); + +} FC_LOG_AND_RETHROW() + // ramburn BOOST_FIXTURE_TEST_CASE( ram_burn, eosio_system_tester ) try { const std::vector accounts = { "alice"_n }; diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index fcc51b10..ee84ae0d 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -202,6 +202,27 @@ class eosio_system_tester : public TESTER { return push_transaction( trx ); } + std::string convertOrdinalsToHex(const std::string& ordinals) { + // helper to convert to hex, 2 chars for hex, 3 char null terminator + char hex_temp[3]; + // return string + std::string hex_as_chars; + + for (unsigned char c : ordinals) { + // convert to hex from ordinal + sprintf(hex_temp, "%x", (int)c); + if (hex_temp[1] == '\0') { + hex_temp[1] = hex_temp[0]; + hex_temp[0] = '0'; + // null terminate + hex_temp[2] = '\0'; + } + hex_as_chars += hex_temp[0]; + hex_as_chars += hex_temp[1]; + } + return hex_as_chars; + } + action_result buyram( const account_name& payer, account_name receiver, const asset& eosin ) { return push_action( payer, "buyram"_n, mvo()( "payer",payer)("receiver",receiver)("quant",eosin) ); } @@ -215,41 +236,111 @@ class eosio_system_tester : public TESTER { { "version": "eosio::abi/1.2", "types": [], - "structs": [{ - "name": "action_return_ramtransfer", - "base": "", - "fields": [ - { - "name": "from", - "type": "name" - }, + "structs": [ { - "name": "to", - "type": "name" + "name": "action_return_buyram", + "base": "", + "fields": [ + { + "name": "payer", + "type": "name" + }, + { + "name": "receiver", + "type": "name" + }, + { + "name": "quantity", + "type": "asset" + }, + { + "name": "bytes", + "type": "int64" + }, + { + "name": "ram_bytes", + "type": "int64" + } + ] }, { - "name": "bytes", - "type": "int64" + "name": "action_return_ramtransfer", + "base": "", + "fields": [ + { + "name": "from", + "type": "name" + }, + { + "name": "to", + "type": "name" + }, + { + "name": "bytes", + "type": "int64" + }, + { + "name": "from_ram_bytes", + "type": "int64" + }, + { + "name": "to_ram_bytes", + "type": "int64" + } + ] }, { - "name": "from_ram_bytes", - "type": "int64" + "name": "action_return_sellram", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "quantity", + "type": "asset" + }, + { + "name": "bytes", + "type": "int64" + }, + { + "name": "ram_bytes", + "type": "int64" + } + ] }, - { - "name": "to_ram_bytes", - "type": "int64" - } - ] - }], + ], "actions": [], "tables": [], "ricardian_clauses": [], "variants": [], "action_results": [ - { - "name": "ramtransfer", - "result_type": "action_return_ramtransfer" - } + { + "name": "buyram", + "result_type": "action_return_buyram" + }, + { + "name": "buyrambytes", + "result_type": "action_return_buyram" + }, + { + "name": "buyramself", + "result_type": "action_return_buyram" + }, + { + "name": "ramburn", + "result_type": "action_return_ramtransfer" + }, + { + "name": "ramtransfer", + "result_type": "action_return_ramtransfer" + }, + { + "name": "sellram", + "result_type": "action_return_sellram" + } ] } )====="; @@ -268,7 +359,7 @@ class eosio_system_tester : public TESTER { mvo()("from", from)("to", to)("bytes", bytes)("memo", memo)); } - std::vector validate_ramtransfer_return(const account_name& from, const account_name& to, uint32_t bytes, const std::string& memo, + void validate_ramtransfer_return(const account_name& from, const account_name& to, uint32_t bytes, const std::string& memo, const type_name& type, const std::string& json) { // create hex return from provided json std::string expected_hex = convert_json_to_hex(type, json); @@ -283,19 +374,41 @@ class eosio_system_tester : public TESTER { // confirm we have trances and find the right one (should be trace idx == 0) BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trace->id)); - for (size_t i = 0; i < trace->action_traces.size(); ++i) { - if (trace->action_traces[i].act.name == "ramtransfer"_n && trace->action_traces[i].act.account == "eosio"_n) { - /* - * This is assignment is giving me grief, value does not survive outside for loop, is empty - * Doing an idump((trace->action_traces[i].return_value)) will show the full hex - * Things I have tried full mem-copy, mem-copy by 8 bytes segments, iterating and copy char by char - * Return from here will return a weird 3 chars (dereference pointer). - */ - idump((trace->action_traces[i].return_value)); - actual_hex = std::string(trace->action_traces[i].return_value.begin(), trace->action_traces[i].return_value.end()); - } - } - // test fails here actual_hex is empty + /* + * This is assignment is giving me grief + * Doing an idump((trace->action_traces[i].return_value)) will show the full hex + * Inspecting trace->action_traces[i].return_value shows the hex have been converted to ordinals + * Couldn't find a method to convert so wrote my own. + */ + // the first trace always has the return value + int i = 0; + std::string copy_trace = std::string(trace->action_traces[i].return_value.begin(), trace->action_traces[i].return_value.end()); + actual_hex = convertOrdinalsToHex(copy_trace); + + // test fails here actual_hex is + BOOST_REQUIRE_EQUAL(expected_hex,actual_hex); + } + + void validate_buyrambytes_return(const account_name& payer, account_name receiver, uint32_t numbytes, + const type_name& type, const std::string& json) { + // create hex return from provided json + std::string expected_hex = convert_json_to_hex(type, json); + // initialize string that will hold actual return + std::string actual_hex; + + auto trace = base_tester::push_action(config::system_account_name, "buyrambytes"_n, payer, mvo()("payer", payer)("receiver", receiver)("bytes", numbytes)); + produce_block(); + + // confirm we have trances and find the right one (should be trace idx == 0) + BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trace->id)); + + // the first trace always has the return value + int i = 0; + std::string copy_trace = std::string(trace->action_traces[i].return_value.begin(), trace->action_traces[i].return_value.end()); + // convert from string of ordinals to char representation of hex + actual_hex = convertOrdinalsToHex(copy_trace); + + // test fails here actual_hex is BOOST_REQUIRE_EQUAL(expected_hex,actual_hex); } @@ -317,6 +430,29 @@ class eosio_system_tester : public TESTER { return buyrambytes(account_name(payer), account_name(receiver), numbytes); } + void validate_sellram_return(const account_name& account, uint32_t numbytes, + const type_name& type, const std::string& json) { + // create hex return from provided json + std::string expected_hex = convert_json_to_hex(type, json); + // initialize string that will hold actual return + std::string actual_hex; + + auto trace = base_tester::push_action(config::system_account_name, "sellram"_n, account, mvo()("account", account)("bytes", numbytes)); + produce_block(); + + // confirm we have trances and find the right one (should be trace idx == 0) + BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trace->id)); + + // the first trace always has the return value + int i = 0; + std::string copy_trace = std::string(trace->action_traces[i].return_value.begin(), trace->action_traces[i].return_value.end()); + // convert from string of ordinals to char representation of hex + actual_hex = convertOrdinalsToHex(copy_trace); + + // test fails here actual_hex is + BOOST_REQUIRE_EQUAL(expected_hex,actual_hex); + } + action_result sellram(const account_name& account, uint64_t numbytes) { return push_action(account, "sellram"_n, mvo()("account", account)("bytes", numbytes)); From 9bce1992ddf393979d2b2b706ff6cb07d2bd4c9a Mon Sep 17 00:00:00 2001 From: Eric Passmore Date: Fri, 2 Feb 2024 09:14:50 -0800 Subject: [PATCH 92/96] test coverage ram actions return values --- tests/eosio.system_ram_tests.cpp | 67 +++++++++++++++-- tests/eosio.system_tester.hpp | 119 +++++++++++++++++++++++++------ 2 files changed, 159 insertions(+), 27 deletions(-) diff --git a/tests/eosio.system_ram_tests.cpp b/tests/eosio.system_ram_tests.cpp index 729032ca..fdfd8a6f 100644 --- a/tests/eosio.system_ram_tests.cpp +++ b/tests/eosio.system_ram_tests.cpp @@ -47,16 +47,20 @@ BOOST_FIXTURE_TEST_CASE( ram_transfer, eosio_system_tester ) try { "to_ram_bytes": 18984 } )====="; - validate_ramtransfer_return(alice, bob, 1, "", "action_return_ramtransfer", expected_return_data ); + validate_ramtransfer_return(alice, bob, 1, "", + "action_return_ramtransfer", expected_return_data ); } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE( buy_sell_ram_validate, eosio_system_tester ) try { - const std::vector accounts = { "alice"_n }; + const std::vector accounts = { "alice"_n, "bob"_n }; create_accounts_with_resources( accounts ); const account_name alice = accounts[0]; + const account_name bob = accounts[1]; transfer( config::system_account_name, alice, core_sym::from_string("100.0000"), config::system_account_name ); + transfer( config::system_account_name, bob, core_sym::from_string("100.0000"), config::system_account_name ); + BOOST_REQUIRE_EQUAL( success(), buyrambytes( bob, bob, 10000 ) ); const char* expected_buyrambytes_return_data = R"=====( { @@ -67,9 +71,10 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_ram_validate, eosio_system_tester ) try { "ram_bytes": 17983 } )====="; - validate_buyrambytes_return(alice, alice, 10000, "action_return_buyram", expected_buyrambytes_return_data ); + validate_buyrambytes_return(alice, alice, 10000, + "action_return_buyram", expected_buyrambytes_return_data ); -const char* expected_sellram_return_data = R"=====( + const char* expected_sellram_return_data = R"=====( { "account": "alice", "quantity": "0.1455 TST", @@ -77,21 +82,47 @@ const char* expected_sellram_return_data = R"=====( "ram_bytes": 7983 } )====="; - validate_sellram_return(alice, 10000, "action_return_sellram", expected_sellram_return_data ); + validate_sellram_return(alice, 10000, + "action_return_sellram", expected_sellram_return_data ); + const char* expected_buyram_return_data = R"=====( +{ + "payer": "bob", + "receiver": "alice", + "quantity": "2.0000 TST", + "bytes": 136750, + "ram_bytes": 144733 +} +)====="; + validate_buyram_return(bob, alice, core_sym::from_string("2.0000"), + "action_return_buyram", expected_buyram_return_data ); } FC_LOG_AND_RETHROW() // ramburn BOOST_FIXTURE_TEST_CASE( ram_burn, eosio_system_tester ) try { - const std::vector accounts = { "alice"_n }; + const std::vector accounts = { "alice"_n, "bob"_n }; create_accounts_with_resources( accounts ); const account_name alice = accounts[0]; + const account_name bob = accounts[1]; const account_name null_account = "eosio.null"_n; transfer( config::system_account_name, alice, core_sym::from_string("100.0000"), config::system_account_name ); + transfer( config::system_account_name, bob, core_sym::from_string("100.0000"), config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), buyrambytes( alice, alice, 10000 ) ); BOOST_REQUIRE_EQUAL( success(), buyrambytes( alice, null_account, 10000 ) ); + const char* expected_buyramself_return_data = R"=====( +{ + "payer": "bob", + "receiver": "bob", + "quantity": "10.0000 TST", + "bytes": 683747, + "ram_bytes": 691739 +} +)====="; + validate_buyramself_return(bob, core_sym::from_string("10.0000"), + "action_return_buyram", expected_buyramself_return_data ) ; + const uint64_t null_before_burn = get_total_stake( null_account )["ram_bytes"].as_uint64(); const uint64_t alice_before_burn = get_total_stake( alice )["ram_bytes"].as_uint64(); @@ -102,6 +133,18 @@ BOOST_FIXTURE_TEST_CASE( ram_burn, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( alice_before_burn - 3000, alice_after_burn ); BOOST_REQUIRE_EQUAL( null_before_burn + 3000, null_after_burn ); + const char* expected_ramburn_return_data = R"=====( +{ + "from": "bob", + "to": "eosio.null", + "bytes": 1, + "from_ram_bytes": 691738, + "to_ram_bytes": 12992 +} +)====="; + validate_ramburn_return(bob, 1, "burn RAM memo", + "action_return_ramtransfer", expected_ramburn_return_data ); + } FC_LOG_AND_RETHROW() @@ -117,6 +160,18 @@ BOOST_FIXTURE_TEST_CASE( buy_ram_self, eosio_system_tester ) try { const uint64_t alice_after = get_total_stake( alice )["ram_bytes"].as_uint64(); BOOST_REQUIRE_EQUAL( alice_before + 68375, alice_after ); + const char* expected_buyramself_return_data = R"=====( +{ + "payer": "alice", + "receiver": "alice", + "quantity": "2.0000 TST", + "bytes": 136750, + "ram_bytes": 213117 +} +)====="; + + validate_buyramself_return(alice, core_sym::from_string("2.0000"), + "action_return_buyram", expected_buyramself_return_data ); } FC_LOG_AND_RETHROW() diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index ee84ae0d..7f622e00 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -223,13 +223,6 @@ class eosio_system_tester : public TESTER { return hex_as_chars; } - action_result buyram( const account_name& payer, account_name receiver, const asset& eosin ) { - return push_action( payer, "buyram"_n, mvo()( "payer",payer)("receiver",receiver)("quant",eosin) ); - } - action_result buyram( std::string_view payer, std::string_view receiver, const asset& eosin ) { - return buyram( account_name(payer), account_name(receiver), eosin ); - } - std::string convert_json_to_hex(const type_name& type, const std::string& json) { // ABI for our return struct const char* ramtransfer_return_abi = R"=====( @@ -354,21 +347,23 @@ class eosio_system_tester : public TESTER { return fc::to_hex(serialized_bytes); } - action_result ramtransfer(const account_name& from, const account_name& to, uint32_t bytes, const std::string& memo) { - return push_action(from, "ramtransfer"_n, - mvo()("from", from)("to", to)("bytes", bytes)("memo", memo)); + action_result buyram( const account_name& payer, account_name receiver, const asset& eosin ) { + return push_action( payer, "buyram"_n, mvo()( "payer",payer)("receiver",receiver)("quant",eosin) ); + } + action_result buyram( std::string_view payer, std::string_view receiver, const asset& eosin ) { + return buyram( account_name(payer), account_name(receiver), eosin ); } - void validate_ramtransfer_return(const account_name& from, const account_name& to, uint32_t bytes, const std::string& memo, - const type_name& type, const std::string& json) { + void validate_buyram_return(const account_name& payer, account_name receiver, const asset& eosin, + const type_name& type, const std::string& json) { // create hex return from provided json std::string expected_hex = convert_json_to_hex(type, json); // initialize string that will hold actual return std::string actual_hex; // execute transaction and get traces must use base_tester - auto trace = base_tester::push_action(config::system_account_name, "ramtransfer"_n, from, - mvo()("from", from)("to", to)("bytes", bytes)("memo", memo)); + auto trace = base_tester::push_action(config::system_account_name, "buyram"_n, payer, + mvo()("payer",payer)("receiver",receiver)("quant",eosin)); produce_block(); // confirm we have trances and find the right one (should be trace idx == 0) @@ -389,23 +384,35 @@ class eosio_system_tester : public TESTER { BOOST_REQUIRE_EQUAL(expected_hex,actual_hex); } - void validate_buyrambytes_return(const account_name& payer, account_name receiver, uint32_t numbytes, - const type_name& type, const std::string& json) { + action_result ramtransfer(const account_name& from, const account_name& to, uint32_t bytes, const std::string& memo) { + return push_action(from, "ramtransfer"_n, + mvo()("from", from)("to", to)("bytes", bytes)("memo", memo)); + } + + void validate_ramtransfer_return(const account_name& from, const account_name& to, uint32_t bytes, const std::string& memo, + const type_name& type, const std::string& json) { // create hex return from provided json std::string expected_hex = convert_json_to_hex(type, json); // initialize string that will hold actual return std::string actual_hex; - auto trace = base_tester::push_action(config::system_account_name, "buyrambytes"_n, payer, mvo()("payer", payer)("receiver", receiver)("bytes", numbytes)); + // execute transaction and get traces must use base_tester + auto trace = base_tester::push_action(config::system_account_name, "ramtransfer"_n, from, + mvo()("from", from)("to", to)("bytes", bytes)("memo", memo)); produce_block(); // confirm we have trances and find the right one (should be trace idx == 0) BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trace->id)); + /* + * This is assignment is giving me grief + * Doing an idump((trace->action_traces[i].return_value)) will show the full hex + * Inspecting trace->action_traces[i].return_value shows the hex have been converted to ordinals + * Couldn't find a method to convert so wrote my own. + */ // the first trace always has the return value int i = 0; std::string copy_trace = std::string(trace->action_traces[i].return_value.begin(), trace->action_traces[i].return_value.end()); - // convert from string of ordinals to char representation of hex actual_hex = convertOrdinalsToHex(copy_trace); // test fails here actual_hex is @@ -421,6 +428,29 @@ class eosio_system_tester : public TESTER { return ramburn(account_name(owner), bytes, memo); } + void validate_ramburn_return(const account_name& owner, uint32_t bytes, const std::string& memo, + const type_name& type, const std::string& json) { + // create hex return from provided json + std::string expected_hex = convert_json_to_hex(type, json); + // initialize string that will hold actual return + std::string actual_hex; + + auto trace = base_tester::push_action(config::system_account_name, "ramburn"_n, owner, mvo()("owner", owner)("bytes", bytes)("memo", memo)); + produce_block(); + + // confirm we have trances and find the right one (should be trace idx == 0) + BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trace->id)); + + // the first trace always has the return value + int i = 0; + std::string copy_trace = std::string(trace->action_traces[i].return_value.begin(), trace->action_traces[i].return_value.end()); + // convert from string of ordinals to char representation of hex + actual_hex = convertOrdinalsToHex(copy_trace); + + // test fails here actual_hex is + BOOST_REQUIRE_EQUAL(expected_hex,actual_hex); + } + action_result buyrambytes(const account_name& payer, account_name receiver, uint32_t numbytes) { return push_action(payer, "buyrambytes"_n, mvo()("payer", payer)("receiver", receiver)("bytes", numbytes)); @@ -430,14 +460,15 @@ class eosio_system_tester : public TESTER { return buyrambytes(account_name(payer), account_name(receiver), numbytes); } - void validate_sellram_return(const account_name& account, uint32_t numbytes, - const type_name& type, const std::string& json) { + void validate_buyrambytes_return(const account_name& payer, account_name receiver, uint32_t numbytes, + const type_name& type, const std::string& json) { // create hex return from provided json std::string expected_hex = convert_json_to_hex(type, json); // initialize string that will hold actual return std::string actual_hex; - auto trace = base_tester::push_action(config::system_account_name, "sellram"_n, account, mvo()("account", account)("bytes", numbytes)); + auto trace = base_tester::push_action(config::system_account_name, "buyrambytes"_n, payer, + mvo()("payer", payer)("receiver", receiver)("bytes", numbytes)); produce_block(); // confirm we have trances and find the right one (should be trace idx == 0) @@ -459,11 +490,57 @@ class eosio_system_tester : public TESTER { } action_result sellram(std::string_view account, uint64_t numbytes) { return sellram(account_name(account), numbytes); } + void validate_sellram_return(const account_name& account, uint32_t numbytes, + const type_name& type, const std::string& json) { + // create hex return from provided json + std::string expected_hex = convert_json_to_hex(type, json); + // initialize string that will hold actual return + std::string actual_hex; + + auto trace = base_tester::push_action(config::system_account_name, "sellram"_n, account, mvo()("account", account)("bytes", numbytes)); + produce_block(); + + // confirm we have trances and find the right one (should be trace idx == 0) + BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trace->id)); + + // the first trace always has the return value + int i = 0; + std::string copy_trace = std::string(trace->action_traces[i].return_value.begin(), trace->action_traces[i].return_value.end()); + // convert from string of ordinals to char representation of hex + actual_hex = convertOrdinalsToHex(copy_trace); + + // test fails here actual_hex is + BOOST_REQUIRE_EQUAL(expected_hex,actual_hex); + } + action_result buyramself(const account_name& account, const asset& quant) { return push_action(account, "buyramself"_n, mvo()("account", account)("quant", quant)); } + void validate_buyramself_return(const account_name& account, const asset& quant, + const type_name& type, const std::string& json) { + // create hex return from provided json + std::string expected_hex = convert_json_to_hex(type, json); + // initialize string that will hold actual return + std::string actual_hex; + + auto trace = base_tester::push_action(config::system_account_name, "buyramself"_n, account, mvo()("account", account)("quant", quant)); + produce_block(); + + // confirm we have trances and find the right one (should be trace idx == 0) + BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trace->id)); + + // the first trace always has the return value + int i = 0; + std::string copy_trace = std::string(trace->action_traces[i].return_value.begin(), trace->action_traces[i].return_value.end()); + // convert from string of ordinals to char representation of hex + actual_hex = convertOrdinalsToHex(copy_trace); + + // test fails here actual_hex is + BOOST_REQUIRE_EQUAL(expected_hex,actual_hex); + } + transaction_trace_ptr setup_producer_accounts( const std::vector& accounts, asset ram = core_sym::from_string("1.0000"), asset cpu = core_sym::from_string("80.0000"), From 36d2964833a867137817b796a1061684a23a1ea6 Mon Sep 17 00:00:00 2001 From: Eric Passmore Date: Fri, 2 Feb 2024 13:30:49 -0800 Subject: [PATCH 93/96] update method name convert_ordinals_to_hex to match standards --- tests/eosio.system_tester.hpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index 7f622e00..37421e31 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -202,7 +202,13 @@ class eosio_system_tester : public TESTER { return push_transaction( trx ); } - std::string convertOrdinalsToHex(const std::string& ordinals) { + /* + * Doing an idump((trace->action_traces[i].return_value)) will show the full hex + * Converting return_value to a string will transform it into a series of ordianl values represented by chars + * fc::to_hex() did not work. + * Couldn't find a method to convert so wrote my own. + */ + std::string convert_ordinals_to_hex(const std::string& ordinals) { // helper to convert to hex, 2 chars for hex, 3 char null terminator char hex_temp[3]; // return string @@ -378,7 +384,7 @@ class eosio_system_tester : public TESTER { // the first trace always has the return value int i = 0; std::string copy_trace = std::string(trace->action_traces[i].return_value.begin(), trace->action_traces[i].return_value.end()); - actual_hex = convertOrdinalsToHex(copy_trace); + actual_hex = convert_ordinals_to_hex(copy_trace); // test fails here actual_hex is BOOST_REQUIRE_EQUAL(expected_hex,actual_hex); @@ -404,16 +410,10 @@ class eosio_system_tester : public TESTER { // confirm we have trances and find the right one (should be trace idx == 0) BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trace->id)); - /* - * This is assignment is giving me grief - * Doing an idump((trace->action_traces[i].return_value)) will show the full hex - * Inspecting trace->action_traces[i].return_value shows the hex have been converted to ordinals - * Couldn't find a method to convert so wrote my own. - */ // the first trace always has the return value int i = 0; std::string copy_trace = std::string(trace->action_traces[i].return_value.begin(), trace->action_traces[i].return_value.end()); - actual_hex = convertOrdinalsToHex(copy_trace); + actual_hex = convert_ordinals_to_hex(copy_trace); // test fails here actual_hex is BOOST_REQUIRE_EQUAL(expected_hex,actual_hex); @@ -445,7 +445,7 @@ class eosio_system_tester : public TESTER { int i = 0; std::string copy_trace = std::string(trace->action_traces[i].return_value.begin(), trace->action_traces[i].return_value.end()); // convert from string of ordinals to char representation of hex - actual_hex = convertOrdinalsToHex(copy_trace); + actual_hex = convert_ordinals_to_hex(copy_trace); // test fails here actual_hex is BOOST_REQUIRE_EQUAL(expected_hex,actual_hex); @@ -478,7 +478,7 @@ class eosio_system_tester : public TESTER { int i = 0; std::string copy_trace = std::string(trace->action_traces[i].return_value.begin(), trace->action_traces[i].return_value.end()); // convert from string of ordinals to char representation of hex - actual_hex = convertOrdinalsToHex(copy_trace); + actual_hex = convert_ordinals_to_hex(copy_trace); // test fails here actual_hex is BOOST_REQUIRE_EQUAL(expected_hex,actual_hex); @@ -507,7 +507,7 @@ class eosio_system_tester : public TESTER { int i = 0; std::string copy_trace = std::string(trace->action_traces[i].return_value.begin(), trace->action_traces[i].return_value.end()); // convert from string of ordinals to char representation of hex - actual_hex = convertOrdinalsToHex(copy_trace); + actual_hex = convert_ordinals_to_hex(copy_trace); // test fails here actual_hex is BOOST_REQUIRE_EQUAL(expected_hex,actual_hex); @@ -535,7 +535,7 @@ class eosio_system_tester : public TESTER { int i = 0; std::string copy_trace = std::string(trace->action_traces[i].return_value.begin(), trace->action_traces[i].return_value.end()); // convert from string of ordinals to char representation of hex - actual_hex = convertOrdinalsToHex(copy_trace); + actual_hex = convert_ordinals_to_hex(copy_trace); // test fails here actual_hex is BOOST_REQUIRE_EQUAL(expected_hex,actual_hex); From 2f575e8cab825d263cfde3ebe5d9da6c06a9aa71 Mon Sep 17 00:00:00 2001 From: Eric Passmore Date: Tue, 6 Feb 2024 13:49:15 -0800 Subject: [PATCH 94/96] explanation of how to computed expected values for --- tests/eosio.system_ram_tests.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/eosio.system_ram_tests.cpp b/tests/eosio.system_ram_tests.cpp index fdfd8a6f..58e2146b 100644 --- a/tests/eosio.system_ram_tests.cpp +++ b/tests/eosio.system_ram_tests.cpp @@ -38,6 +38,20 @@ BOOST_FIXTURE_TEST_CASE( ram_transfer, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( alice_before - 1000, alice_after ); BOOST_REQUIRE_EQUAL( bob_before + 1000, bob_after ); + /* + * The from_ram_bytes is alice's ram byte total + * The to_ram_bytes is bob's ram byte total + * Accounts start with 8,000 ram bytes + * this is via create_accounts_with_resources() + * Next buyram on each account purchases 10,000 additional ram bytes + * minus fees of 17 ram bytes + * + * Before ram transfer the totals for each account are 17,983 ram bytes + * After transfer of 1,000 bytes + * bob and alice respective totals are 16,983 and 18,983 + * After the validate ram transfer below of 1 ram byte + * bob and alices respective totals are 16,982 and 18,984 + */ const char* expected_return_data = R"=====( { "from": "alice", From ef2bb7bc37065febfcc56d42a26d1c783de21c47 Mon Sep 17 00:00:00 2001 From: Eric Passmore Date: Tue, 6 Feb 2024 13:53:59 -0800 Subject: [PATCH 95/96] whoops, reversed bob and alice example amounts --- tests/eosio.system_ram_tests.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/eosio.system_ram_tests.cpp b/tests/eosio.system_ram_tests.cpp index 58e2146b..6d790025 100644 --- a/tests/eosio.system_ram_tests.cpp +++ b/tests/eosio.system_ram_tests.cpp @@ -45,12 +45,12 @@ BOOST_FIXTURE_TEST_CASE( ram_transfer, eosio_system_tester ) try { * this is via create_accounts_with_resources() * Next buyram on each account purchases 10,000 additional ram bytes * minus fees of 17 ram bytes - * + * * Before ram transfer the totals for each account are 17,983 ram bytes * After transfer of 1,000 bytes - * bob and alice respective totals are 16,983 and 18,983 + * bob and alice respective totals are 18,983 and 16,983 * After the validate ram transfer below of 1 ram byte - * bob and alices respective totals are 16,982 and 18,984 + * bob and alices respective totals are 18,984 and 16,982 */ const char* expected_return_data = R"=====( { From ab0858b518ca0faa955ff39311d90a466efbe8c2 Mon Sep 17 00:00:00 2001 From: Eric Passmore Date: Tue, 6 Feb 2024 14:47:24 -0800 Subject: [PATCH 96/96] updated to bytes_sold and bytes_purchased --- .../eosio.system/include/eosio.system/eosio.system.hpp | 4 ++-- tests/eosio.system_ram_tests.cpp | 10 +++++----- tests/eosio.system_tester.hpp | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 2faf9269..d3dfc4b7 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -548,7 +548,7 @@ namespace eosiosystem { struct action_return_sellram { name account; asset quantity; - int64_t bytes; + int64_t bytes_sold; int64_t ram_bytes; }; @@ -556,7 +556,7 @@ namespace eosiosystem { name payer; name receiver; asset quantity; - int64_t bytes; + int64_t bytes_purchased; int64_t ram_bytes; }; diff --git a/tests/eosio.system_ram_tests.cpp b/tests/eosio.system_ram_tests.cpp index 6d790025..b5b3e298 100644 --- a/tests/eosio.system_ram_tests.cpp +++ b/tests/eosio.system_ram_tests.cpp @@ -81,7 +81,7 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_ram_validate, eosio_system_tester ) try { "payer": "alice", "receiver": "alice", "quantity": "0.1462 TST", - "bytes": 9991, + "bytes_purchased": 9991, "ram_bytes": 17983 } )====="; @@ -92,7 +92,7 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_ram_validate, eosio_system_tester ) try { { "account": "alice", "quantity": "0.1455 TST", - "bytes": 10000, + "bytes_sold": 10000, "ram_bytes": 7983 } )====="; @@ -104,7 +104,7 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_ram_validate, eosio_system_tester ) try { "payer": "bob", "receiver": "alice", "quantity": "2.0000 TST", - "bytes": 136750, + "bytes_purchased": 136750, "ram_bytes": 144733 } )====="; @@ -130,7 +130,7 @@ BOOST_FIXTURE_TEST_CASE( ram_burn, eosio_system_tester ) try { "payer": "bob", "receiver": "bob", "quantity": "10.0000 TST", - "bytes": 683747, + "bytes_purchased": 683747, "ram_bytes": 691739 } )====="; @@ -179,7 +179,7 @@ BOOST_FIXTURE_TEST_CASE( buy_ram_self, eosio_system_tester ) try { "payer": "alice", "receiver": "alice", "quantity": "2.0000 TST", - "bytes": 136750, + "bytes_purchased": 136750, "ram_bytes": 213117 } )====="; diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index 37421e31..93a8eb24 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -253,7 +253,7 @@ class eosio_system_tester : public TESTER { "type": "asset" }, { - "name": "bytes", + "name": "bytes_purchased", "type": "int64" }, { @@ -301,7 +301,7 @@ class eosio_system_tester : public TESTER { "type": "asset" }, { - "name": "bytes", + "name": "bytes_sold", "type": "int64" }, {