Merge branch 'master' into permission-cache-impl

# Conflicts:
#	core/types/permissions_cache_test.go
#	params/quorum.go
#	permission/api.go
#	permission/permission.go
#	permission/permission_test.go
This commit is contained in:
vsmk98 2020-05-14 10:52:49 +08:00
commit 72a4cf87b3
86 changed files with 1476 additions and 606 deletions

View File

@ -7,9 +7,25 @@ on:
- .gitignore
env:
GO_VERSION: 1.13
GOPATH: ${{ github.workspace }}/go
WORKING_DIR: ${{ github.workspace }}/go/src/github.com/ethereum/go-ethereum
jobs:
lint:
name: 'Code linters'
runs-on: ubuntu-latest
steps:
- name: 'Setup Go ${{ env.GO_VERSION }}'
uses: actions/setup-go@v1
with:
go-version: ${{ env.GO_VERSION }}
- name: 'Check out project files'
uses: actions/checkout@v2
with:
submodules: false
- name: 'Prepare environment'
run: |
echo "::add-path::$(go env GOPATH)/bin"
- name: 'Run code linters'
run: |
GO111MODULE=off make lint
unit-tests:
name: 'Unit tests in ${{ matrix.os }}'
strategy:
@ -25,10 +41,9 @@ jobs:
with:
go-version: ${{ env.GO_VERSION }}
- name: 'Check out project files'
uses: actions/checkout@574281d
uses: actions/checkout@v2
with:
submodules: recursive
path: ${{ env.WORKING_DIR }}
- name: 'Prepare environment'
run: |
# https://github.com/actions/virtual-environments/issues/798
@ -36,7 +51,6 @@ jobs:
echo "::add-path::$(go env GOPATH)/bin"
- name: 'Run unit tests'
working-directory: ${{ env.WORKING_DIR }}
run: |
make test
docker-build:

342
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,342 @@
name: Release
on:
push:
tags:
- 'v*'
env:
GO_VERSION: 1.13
GOPATH: ${{ github.workspace }}/go
WORKING_DIR: ${{ github.workspace }}/go/src/github.com/ethereum/go-ethereum
jobs:
build:
name: 'Build binary for ${{ matrix.os }}'
strategy:
fail-fast: false
matrix:
os: ["ubuntu-latest", "macos-latest"]
runs-on: ${{ matrix.os }}
steps:
- name: 'Setup Go ${{ env.GO_VERSION }}'
uses: actions/setup-go@v1
with:
go-version: ${{ env.GO_VERSION }}
- name: 'Prepare environment'
id: env
run: |
echo "::add-path::$(go env GOPATH)/bin"
echo "::set-output name=key::$(go env GOOS)_$(go env GOARCH)"
echo "::set-output name=version::${GITHUB_REF##*/}"
- name: 'Check out project files'
uses: actions/checkout@574281d
with:
submodules: recursive
path: ${{ env.WORKING_DIR }}
- name: 'Build geth'
working-directory: ${{ env.WORKING_DIR }}
run: |
make geth
mkdir -p build/artifact
tar cfvz build/artifact/geth_${{ steps.env.outputs.version }}_${{ steps.env.outputs.key }}.tar.gz -C build/bin geth
- name: 'Upload artifact'
uses: actions/upload-artifact@v2
with:
path: ${{ env.WORKING_DIR }}/build/artifact
name: ${{ steps.env.outputs.key }}
prepare-bintray:
name: 'Prepare Bintray'
runs-on: ubuntu-latest
steps:
- name: 'Setup jfrog CLI'
uses: jfrog/setup-jfrog-cli@v1
- name: 'Create new version in Bintray'
id: prepare_bintray
run: |
TAG="${GITHUB_REF##*/}"
PACKAGE="${{ secrets.BINTRAY_PACKAGE }}" # e.g.: quorumengineering/quorum/geth
VERSION="$PACKAGE/$TAG"
jfrog bt package-show --key ${{ secrets.BINTRAY_API_KEY }} --user ${{ secrets.BINTRAY_USER }} $PACKAGE
echo "Checking $VERSION"
jfrog bt version-show --key ${{ secrets.BINTRAY_API_KEY }} --user ${{ secrets.BINTRAY_USER }} $VERSION && x=0 || x=1
if [ $x -eq 0 ]; then
echo "$VERSION already exists"
else
jfrog bt version-create --key ${{ secrets.BINTRAY_API_KEY }} --user ${{ secrets.BINTRAY_USER }} \
--vcs-tag $TAG --released $(date -u +"%Y-%m-%dT%H:%M:%SZ") \
$VERSION
fi
deploy-bintray:
name: 'Deploy binaries to Bintray'
needs:
- build
- prepare-bintray
runs-on: ubuntu-latest
steps:
- name: 'Setup jfrog CLI'
uses: jfrog/setup-jfrog-cli@v1
- name: 'Download artifacts'
uses: actions/download-artifact@v2
with:
path: artifact
- name: 'Upload artifacts to Bintray'
run: |
TAG="${GITHUB_REF##*/}"
jfrog bt upload --key ${{ secrets.BINTRAY_API_KEY }} --user ${{ secrets.BINTRAY_USER }} --publish --override \
"artifact/*/*.*" \
${{ secrets.BINTRAY_PACKAGE }}/$TAG \
$TAG/
draft-release:
name: 'Draft Github release'
needs:
- deploy-bintray
runs-on: ubuntu-latest
steps:
- name: 'Check out project files'
uses: actions/checkout@v2
- name: 'Generate release notes'
id: release_notes
run: |
git fetch --depth=1 origin +refs/tags/*:refs/tags/*
package="${{ secrets.BINTRAY_PACKAGE }}"
repo="${package%/*}"
file="generated-release-notes.md"
current_version="${GITHUB_REF##*/}"
last_version=$(git describe --abbrev=0 --tags `git rev-list --tags --skip=1 --max-count=1`)
last_release_date=$(git log -1 --format=%cd --date=short $last_version)
echo "Last version: $last_version on $last_release_date"
# pulling from git logs
curl -q -s -H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/search/issues?q=repo:jpmorganchase/quorum+is:pr+is:merged+merged%3A>=$last_release_date+sort%3Aupdated-desc" | jq -r '"* " + (.items[]|.title + " #" + (.number|tostring))' \
>> $file
# pulling file hashes from Bintray
echo "" >> $file
echo "| Filename | SHA256 Hash |" >> $file
echo "|:---------|:------------|" >> $file
curl -q -s -u ${{ secrets.BINTRAY_USER }}:${{ secrets.BINTRAY_API_KEY}} "https://api.bintray.com/packages/$package/versions/$current_version/files" \
| jq '.[] | select(.name | endswith(".asc") | not) | "|[\(.name)](https://bintray.com/$repo/download_file?file_path=\(.path))|`\(.sha256)`|"' -r \
>> $file
content=$(cat $file)
# escape newline
content="${content//'%'/'%25'}"
content="${content//$'\n'/'%0A'}"
content="${content//$'\r'/'%0D'}"
echo "::set-output name=content::$content"
- name: 'Create Github draft release'
uses: actions/create-release@v1
env:
# This token is provided by Actions, you do not need to create your own token
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
body: |
${{ steps.release_notes.outputs.content }}
draft: true
prerelease: false
notify:
if: always()
name: 'Notify'
needs:
- build
- deploy-bintray
- draft-release
runs-on: ubuntu-latest
steps:
- name: 'Setup metadata'
id: setup
run: |
gitref_path="${{ github.ref }}"
gitref_path=${gitref_path/refs\/heads/tree} # for refs/heads/my-branch
gitref_path=${gitref_path/refs\/tags/tree} # for refs/tags/v1.0.0
gitref_path=${gitref_path#refs\/} # for refs/pull/123/merge
gitref_path=${gitref_path%/merge} # for refs/pull/123/merge
echo "::set-output name=gitref-path::$gitref_path"
echo "::set-output name=version::${GITHUB_REF##*/}"
- name: 'Prepare Slack message with full info'
id: status
uses: actions/github-script@0.8.0
with:
script: |
var gitref_path = "${{ steps.setup.outputs.gitref-path }}"
////////////////////////////////////
// retrieve workflow run data
////////////////////////////////////
console.log("get workflow run")
const wf_run = await github.actions.getWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.run_id }}
})
console.log(wf_run.data)
console.log("get jobs for workflow run:", wf_run.data.jobs_url)
const jobs_response = await github.request(wf_run.data.jobs_url)
////////////////////////////////////
// build slack notification message
////////////////////////////////////
// some utility functions
var date_diff_func = function(start, end) {
var duration = end - start
// format the duration
var delta = duration / 1000
var days = Math.floor(delta / 86400)
delta -= days * 86400
var hours = Math.floor(delta / 3600) % 24
delta -= hours * 3600
var minutes = Math.floor(delta / 60) % 60
delta -= minutes * 60
var seconds = Math.floor(delta % 60)
var format_func = function(v, text, check) {
if (v <= 0 && check) {
return ""
} else {
return v + text
}
}
return format_func(days, "d", true) + format_func(hours, "h", true) + format_func(minutes, "m", true) + format_func(seconds, "s", false)
}
var status_icon_func = function(s) {
switch (s) {
case "w_success":
return ":white_check_mark:"
case "w_failure":
return ":no_entry:"
case "w_cancelled":
return ":warning:"
case "success":
return "\u2713"
case "failure":
return "\u2717"
default:
return "\u20e0"
}
}
// build the message
var job_blocks = []
var is_wf_success = true
var is_wf_failure = false
for (j of jobs_response.data.jobs) {
console.log(j.name, ":", j.status, j.conclusion, j.started_at, j.completed_at)
// ignore the current job running this script
if (j.status != "completed") {
continue
}
if (j.conclusion != "success") {
is_wf_success = false
}
if (j.conclusion == "failure") {
is_wf_failure = true
}
job_blocks.push({
type: "section",
text: {
type: "mrkdwn",
text: `${status_icon_func(j.conclusion)} <${j.html_url}|${j.name}> took ${date_diff_func(new Date(j.started_at), new Date(j.completed_at))}`
}
})
}
var workflow_status = "w_cancelled"
if (is_wf_success) {
workflow_status = "w_success"
} else if (is_wf_failure) {
workflow_status = "w_failure"
}
var context_elements = [
{
"type": "mrkdwn",
"text": "*Repo:* <https://github.com/${{ github.repository }}|${{ github.repository }}>"
},
{
"type": "mrkdwn",
"text": `*Branch:* <https://github.com/${{ github.repository }}/${gitref_path}|${{ github.ref }}>`
},
{
"type": "mrkdwn",
"text": `*Event:* ${wf_run.data.event}`
},
{
"type": "mrkdwn",
"text": `*Commit:* <https://github.com/${{ github.repository }}/commit/${wf_run.data.head_commit.id}|${wf_run.data.head_commit.id.substr(0, 8)}>`
},
{
"type": "mrkdwn",
"text": `*Author:* ${wf_run.data.head_commit.author.name}`
}
]
var header_blocks = [
{
type: "section",
text: {
type: "mrkdwn",
text: `${status_icon_func(workflow_status)} *${{ github.workflow }} ${{ steps.setup.outputs.version }}* <${wf_run.data.html_url}|#${{ github.run_number }}> took ${date_diff_func(new Date(wf_run.data.created_at), new Date(wf_run.data.updated_at))}`
}
},
{
type: "context",
elements: context_elements,
},
{
type: "divider"
}
]
var slack_msg = {
blocks: [].concat(header_blocks, job_blocks)
}
return slack_msg
- name: 'Prepare Slack message with partial info'
id: short_status
if: failure()
uses: actions/github-script@0.8.0
with:
script: |
////////////////////////////////////
// retrieve workflow run data
////////////////////////////////////
const wf_run = await github.actions.getWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.run_id }}
})
var date_diff_func = function(start, end) {
var duration = end - start
// format the duration
var delta = duration / 1000
var days = Math.floor(delta / 86400)
delta -= days * 86400
var hours = Math.floor(delta / 3600) % 24
delta -= hours * 3600
var minutes = Math.floor(delta / 60) % 60
delta -= minutes * 60
var seconds = Math.floor(delta % 60)
var format_func = function(v, text, check) {
if (v <= 0 && check) {
return ""
} else {
return v + text
}
}
return format_func(days, "d", true) + format_func(hours, "h", true) + format_func(minutes, "m", true) + format_func(seconds, "s", false)
}
var slack_msg = {
blocks: [
{
type: "section",
text: {
type: "mrkdwn",
text: `:skull_and_crossbones: *${{ github.workflow }}* <${wf_run.data.html_url}|#${{ github.run_number }}> (took ${date_diff_func(new Date(wf_run.data.created_at), new Date(wf_run.data.updated_at))})`
}
}
]
}
return slack_msg
- name: 'Send to Slack'
if: always()
run: |
cat <<JSON > long_message.json
${{ steps.status.outputs.result }}
JSON
cat <<JSON > short_message.json
${{ steps.short_status.outputs.result }}
JSON
_post() {
curl -X POST ${{ secrets.SLACK_WEBHOOK_URL }} -H "Content-type: application/json" --data "@${1}"
}
_post "long_message.json" || _post "short_message.json"

View File

@ -1,79 +1,228 @@
# simplified version of the upstream travis configuration with additional features
# 1. Distribute binaries to bintray from Tag
language: go
go_import_path: github.com/ethereum/go-ethereum
go: 1.13.x
sudo: true
branches:
only:
- /.*/ # everything including tags
env:
global:
- BINTRAY_ORGANIZATION=quorumengineering
- BINTRAY_USER=quorumbot
# Bintray API Key
- secure: "QHiPcd3zQoJEsT3VSpxoLVTYwbiYzS8H18EpY7Tk0EqCIfswS2AvRlyRXUxNvCf9ktzpaeXV4b5cPYJ67dwdp5V/O/ARaK5AL6ZjjrTPR1avPnmz/X2VeQEP0aWk1UGMs1nBUj5rzMbIIxlVhpbiITTLAI4Ao0+xRcBi215mDbv271Z7mACEZfXxjaoJA0/3IkbKz9pu1nC7bTjaaExCDAeLp2p8fHi2YQPnBll/7dkn/m1rnsIY9M3KWNCx6xBmQOr1hulrrB6tZoHwFBoDsVTFJFLckPfrWUZsYUgtfWJMQWc6ntv1gFl0f9x6s5fYEphCU2m1JYjEczlQ03B5ro9EyPGKjO7vQxAaFd5nVd2Xf34ZbssEIyXxlSnP/4Gv1GXl9L9aU1Hth9ckYvT5gYP5t/Nw3CDbKD0HelPBvkf8jZwfdlotzFPS2bOZNdl/rJLWgQrX18a/mC3BH9l4TSRz13tbRfo6YcC3Y/uOvG1n4GxzcVaWojAxn86SkknOczPTf2pk9F3JOcGVSYA2R4kGQAe+ErJH2X5g2sh1D5cCYDjQyl5rzWg6P3eK//HYW+mg2+TQ8k2iQVVSwFwrR0Yn4P+5cRDCW9mjtktgq1rTtslj41gSH49Avqr9oXGM2rqdcJPdN8dnmLMrAtmeSUNMMoexiRMmlF2OQKLrW3k="
matrix:
sudo: false
jobs:
include:
- if: tag IS present
# This builder only tests code linters on latest version of Go
- stage: lint
os: linux
dist: xenial
env: OUTPUT_FILE=geth_${TRAVIS_TAG}_linux_amd64.tar.gz
go: 1.13.x
env:
- lint
git:
submodules: false # avoid cloning ethereum/tests
script:
- build/env.sh go run build/ci.go install ./cmd/geth
- sudo mkdir -p /dist
- cd build/bin
- sudo tar cfvz /dist/${OUTPUT_FILE} geth
- go run build/ci.go lint
- if: tag IS present
- stage: build
os: linux
dist: xenial
go: 1.11.x
script:
- go run build/ci.go install
- go run build/ci.go test -coverage $TEST_PACKAGES
- stage: build
os: linux
dist: xenial
go: 1.12.x
script:
- go run build/ci.go install
- go run build/ci.go test -coverage $TEST_PACKAGES
# These are the latest Go versions.
- stage: build
os: linux
dist: xenial
go: 1.13.x
script:
- go run build/ci.go install
- go run build/ci.go test -coverage $TEST_PACKAGES
- stage: build
os: osx
env: OUTPUT_FILE=geth_${TRAVIS_TAG}_darwin_amd64.tar.gz
go: 1.13.x
script:
- build/env.sh go run build/ci.go install ./cmd/geth
- sudo mkdir -p /dist
- cd build/bin
- sudo tar cfvz /dist/${OUTPUT_FILE} geth
- echo "Increase the maximum number of open file descriptors on macOS"
- NOFILE=20480
- sudo sysctl -w kern.maxfiles=$NOFILE
- sudo sysctl -w kern.maxfilesperproc=$NOFILE
- sudo launchctl limit maxfiles $NOFILE $NOFILE
- sudo launchctl limit maxfiles
- ulimit -S -n $NOFILE
- ulimit -n
- unset -f cd # workaround for https://github.com/travis-ci/travis-ci/issues/8703
- go run build/ci.go install
- go run build/ci.go test -coverage $TEST_PACKAGES
before_deploy:
- |
echo "Prepare Bintray descriptor"
export GETH_VERSION=$(cat ${TRAVIS_BUILD_DIR}/VERSION)
export RELEASED_DATE=$(date +'%Y-%m-%d')
sed -e "s/_TRAVIS_TAG_/${TRAVIS_TAG}/g" \
-e "s/_TRAVIS_BUILD_NUMBER_/${TRAVIS_BUILD_NUMBER}/g" \
-e "s/_GETH_VERSION_/${GETH_VERSION}/g" \
-e "s/_RELEASED_DATE_/${RELEASED_DATE}/g" \
-e "s/_TRAVIS_COMMIT_/${TRAVIS_COMMIT}/g" \
-e "s/_TRAVIS_JOB_WEB_URL_/${TRAVIS_JOB_WEB_URL//\//\\/}/g" \
-e "s/_ORGANIZATION_/${BINTRAY_ORGANIZATION}/g" \
${TRAVIS_BUILD_DIR}/.bintray.json > /tmp/bintray.json
after_deploy:
- |
published=""
while [ "$published" == "" ]; do
echo "Sleep 5s to wait until ${OUTPUT_FILE} is published"
sleep 5
result=$(curl -u ${BINTRAY_USER}:${BINTRAY_API_KEY} "https://api.bintray.com/packages/${BINTRAY_ORGANIZATION}/quorum/geth/versions/${TRAVIS_TAG}/files")
echo "$result"
if [[ "$result" == *"${OUTPUT_FILE}"* ]]; then
published="done"
fi
done
- |
echo "Add ${OUTPUT_FILE} to Download List"
curl -u ${BINTRAY_USER}:${BINTRAY_API_KEY} \
-H "Content-type: application/json" \
-X PUT \
--data "{\"list_in_downloads\": true}" \
https://api.bintray.com/file_metadata/${BINTRAY_ORGANIZATION}/quorum/${TRAVIS_TAG}/${OUTPUT_FILE}
deploy:
provider: bintray
file: /tmp/bintray.json
user: ${BINTRAY_USER}
key: ${BINTRAY_API_KEY}
skip_cleanup: true
on:
tags: true
# This builder does the Ubuntu PPA upload
- stage: build
if: type = push
os: linux
dist: xenial
go: 1.13.x
env:
- ubuntu-ppa
git:
submodules: false # avoid cloning ethereum/tests
addons:
apt:
packages:
- devscripts
- debhelper
- dput
- fakeroot
- python-bzrlib
- python-paramiko
cache:
directories:
- $HOME/.gobundle
script:
- echo '|1|7SiYPr9xl3uctzovOTj4gMwAC1M=|t6ReES75Bo/PxlOPJ6/GsGbTrM0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0aKz5UTUndYgIGG7dQBV+HaeuEZJ2xPHo2DS2iSKvUL4xNMSAY4UguNW+pX56nAQmZKIZZ8MaEvSj6zMEDiq6HFfn5JcTlM80UwlnyKe8B8p7Nk06PPQLrnmQt5fh0HmEcZx+JU9TZsfCHPnX7MNz4ELfZE6cFsclClrKim3BHUIGq//t93DllB+h4O9LHjEUsQ1Sr63irDLSutkLJD6RXchjROXkNirlcNVHH/jwLWR5RcYilNX7S5bIkK8NlWPjsn/8Ua5O7I9/YoE97PpO6i73DTGLh5H9JN/SITwCKBkgSDWUt61uPK3Y11Gty7o2lWsBjhBUm2Y38CBsoGmBw==' >> ~/.ssh/known_hosts
- go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user geth-ci -signer "Go Ethereum Linux Builder <geth-ci@ethereum.org>" -goversion 1.13.4 -gohash 95dbeab442ee2746b9acf0934c8e2fc26414a0565c008631b04addb8c02e7624 -gobundle $HOME/.gobundle/go.tar.gz
# This builder does the Linux Azure uploads
- stage: build
if: type = push
os: linux
dist: xenial
sudo: required
go: 1.13.x
env:
- azure-linux
git:
submodules: false # avoid cloning ethereum/tests
addons:
apt:
packages:
- gcc-multilib
script:
# Build for the primary platforms that Trusty can manage
- go run build/ci.go install
- go run build/ci.go archive -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- go run build/ci.go install -arch 386
- go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
# Switch over GCC to cross compilation (breaks 386, hence why do it here only)
- sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install gcc-arm-linux-gnueabi libc6-dev-armel-cross gcc-arm-linux-gnueabihf libc6-dev-armhf-cross gcc-aarch64-linux-gnu libc6-dev-arm64-cross
- sudo ln -s /usr/include/asm-generic /usr/include/asm
- GOARM=5 go run build/ci.go install -arch arm -cc arm-linux-gnueabi-gcc
- GOARM=5 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- GOARM=6 go run build/ci.go install -arch arm -cc arm-linux-gnueabi-gcc
- GOARM=6 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- GOARM=7 go run build/ci.go install -arch arm -cc arm-linux-gnueabihf-gcc
- GOARM=7 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- go run build/ci.go install -arch arm64 -cc aarch64-linux-gnu-gcc
- go run build/ci.go archive -arch arm64 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
# This builder does the Linux Azure MIPS xgo uploads
- stage: build
if: type = push
os: linux
dist: xenial
services:
- docker
go: 1.13.x
env:
- azure-linux-mips
git:
submodules: false # avoid cloning ethereum/tests
script:
- go run build/ci.go xgo --alltools -- --targets=linux/mips --ldflags '-extldflags "-static"' -v
- for bin in build/bin/*-linux-mips; do mv -f "${bin}" "${bin/-linux-mips/}"; done
- go run build/ci.go archive -arch mips -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- go run build/ci.go xgo --alltools -- --targets=linux/mipsle --ldflags '-extldflags "-static"' -v
- for bin in build/bin/*-linux-mipsle; do mv -f "${bin}" "${bin/-linux-mipsle/}"; done
- go run build/ci.go archive -arch mipsle -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- go run build/ci.go xgo --alltools -- --targets=linux/mips64 --ldflags '-extldflags "-static"' -v
- for bin in build/bin/*-linux-mips64; do mv -f "${bin}" "${bin/-linux-mips64/}"; done
- go run build/ci.go archive -arch mips64 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
- go run build/ci.go xgo --alltools -- --targets=linux/mips64le --ldflags '-extldflags "-static"' -v
- for bin in build/bin/*-linux-mips64le; do mv -f "${bin}" "${bin/-linux-mips64le/}"; done
- go run build/ci.go archive -arch mips64le -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
# This builder does the Android Maven and Azure uploads
- stage: build
if: type = push
os: linux
dist: xenial
addons:
apt:
packages:
- oracle-java8-installer
- oracle-java8-set-default
language: android
android:
components:
- platform-tools
- tools
- android-15
- android-19
- android-24
env:
- azure-android
- maven-android
git:
submodules: false # avoid cloning ethereum/tests
before_install:
- curl https://dl.google.com/go/go1.13.linux-amd64.tar.gz | tar -xz
- export PATH=`pwd`/go/bin:$PATH
- export GOROOT=`pwd`/go
- export GOPATH=$HOME/go
script:
# Build the Android archive and upload it to Maven Central and Azure
- curl https://dl.google.com/android/repository/android-ndk-r19b-linux-x86_64.zip -o android-ndk-r19b.zip
- unzip -q android-ndk-r19b.zip && rm android-ndk-r19b.zip
- mv android-ndk-r19b $ANDROID_HOME/ndk-bundle
- mkdir -p $GOPATH/src/github.com/ethereum
- ln -s `pwd` $GOPATH/src/github.com/ethereum/go-ethereum
- go run build/ci.go aar -signer ANDROID_SIGNING_KEY -deploy https://oss.sonatype.org -upload gethstore/builds
# This builder does the OSX Azure, iOS CocoaPods and iOS Azure uploads
- stage: build
if: type = push
os: osx
go: 1.13.x
env:
- azure-osx
- azure-ios
- cocoapods-ios
git:
submodules: false # avoid cloning ethereum/tests
script:
- go run build/ci.go install
- go run build/ci.go archive -type tar -signer OSX_SIGNING_KEY -upload gethstore/builds
# Build the iOS framework and upload it to CocoaPods and Azure
- gem uninstall cocoapods -a -x
- gem install cocoapods
- mv ~/.cocoapods/repos/master ~/.cocoapods/repos/master.bak
- sed -i '.bak' 's/repo.join/!repo.join/g' $(dirname `gem which cocoapods`)/cocoapods/sources_manager.rb
- if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then git clone --depth=1 https://github.com/CocoaPods/Specs.git ~/.cocoapods/repos/master && pod setup --verbose; fi
- xctool -version
- xcrun simctl list
# Workaround for https://github.com/golang/go/issues/23749
- export CGO_CFLAGS_ALLOW='-fmodules|-fblocks|-fobjc-arc'
- go run build/ci.go xcode -signer IOS_SIGNING_KEY -deploy trunk -upload gethstore/builds
# This builder does the Azure archive purges to avoid accumulating junk
- stage: build
if: type = cron
os: linux
dist: xenial
go: 1.13.x
env:
- azure-purge
git:
submodules: false # avoid cloning ethereum/tests
script:
- go run build/ci.go purge -store gethstore/builds -days 14

View File

@ -147,44 +147,3 @@ geth-windows-amd64:
build/env.sh go run build/ci.go xgo -- --go=$(GO) --targets=windows/amd64 -v ./cmd/geth
@echo "Windows amd64 cross compilation done:"
@ls -ld $(GOBIN)/geth-windows-* | grep amd64
# QUORUM - BEGIN
RELEASE_NOTES_FILE := generated-release-notes.md
LAST_RELEASE_VERSION := $(shell git describe --tags --abbrev=0 @^)
REQUIRED_ENV_VARS := QUORUM_RELEASE BINTRAY_USER BINTRAY_API_KEY GITHUB_TOKEN
release-prepare: release-tools
@[ "${QUORUM_RELEASE}" ] || (echo "Please provide QUORUM_RELEASE env variable" ; exit 1)
@rm -f $(RELEASE_NOTES_FILE)
@echo "Last release: $(LAST_RELEASE_VERSION)"
@echo "This release: ${QUORUM_RELEASE}"
@echo "${QUORUM_RELEASE}\n\n" > $(RELEASE_NOTES_FILE)
@git log --pretty=format:%s $(LAST_RELEASE_VERSION)..@ >> $(RELEASE_NOTES_FILE)
@echo "$(RELEASE_NOTES_FILE) has been created"
release: release-tools check-release-env
@jfrog bt version-show quorumengineering/quorum/geth/${QUORUM_RELEASE} --key ${BINTRAY_API_KEY} --user ${BINTRAY_USER}
@echo "\n\n| Filename | SHA256 Hash |" >> $(RELEASE_NOTES_FILE)
@echo "|:---------|:------------|" >> $(RELEASE_NOTES_FILE)
@curl -s -u ${BINTRAY_USER}:${BINTRAY_API_KEY} https://api.bintray.com/packages/quorumengineering/quorum/geth/versions/${QUORUM_RELEASE}/files \
| jq '.[] | select(.name | endswith(".asc") | not) | "|[\(.name)](https://bintray.com/quorumengineering/quorum/download_file?file_path=\(.path))|`\(.sha256)`|"' -r \
>> $(RELEASE_NOTES_FILE)
@hub release create -d -F $(RELEASE_NOTES_FILE) ${QUORUM_RELEASE}
# make sure all API Keys are set
check-release-env: $(REQUIRED_ENV_VARS)
@[ -f "$(RELEASE_NOTES_FILE)" ] || (echo "Please run 'make release-prepare' and edit the release notes"; exit 1)
$(REQUIRED_ENV_VARS):
@[ "${$@}" ] || (echo "Please provide $@ env variable" ; exit 1)
release-tools:
ifeq (, $(shell which hub))
@echo "Please install Github CLI from https://hub.github.com"
endif
ifeq (, $(shell which jfrog))
@echo "Please install JFrog CLI from https://jfrog.com/getcli"
endif
ifeq (, $(shell which jq))
@echo "Please install jq from https://stedolan.github.io/jq/download"
endif
# QUORUM - END

View File

@ -1,7 +1,7 @@
# <img src="https://raw.githubusercontent.com/jpmorganchase/quorum/master/logo.png" width="200" height="200"/>
<a href="https://www.goquorum.com/slack-inviter" target="_blank" rel="noopener"><img title="Quorum Slack" src="https://93ecjxb0d3.execute-api.us-east-1.amazonaws.com/Express/badge.svg" alt="Quorum Slack" /></a>
[![Build Status](https://travis-ci.org/jpmorganchase/quorum.svg?branch=master)](https://travis-ci.org/jpmorganchase/quorum)
![Build Check](https://github.com/jpmorganchase/quorum/workflows/Build%20Check/badge.svg?branch=master)
[![Docker Cloud Build Status](https://img.shields.io/docker/cloud/build/quorumengineering/quorum)](https://hub.docker.com/r/quorumengineering/quorum/builds)
[![Documentation Status](https://readthedocs.org/projects/goquorum/badge/?version=latest)](http://docs.goquorum.com/en/latest/?badge=latest)
[![Download](https://api.bintray.com/packages/quorumengineering/quorum/geth/images/download.svg)](https://bintray.com/quorumengineering/quorum/geth/_latestVersion)
@ -13,49 +13,44 @@ Quorum is a fork of [go-ethereum](https://github.com/ethereum/go-ethereum) and i
Key enhancements over go-ethereum:
* __Privacy__ - Quorum supports private transactions and private contracts through public/private state separation, and utilises peer-to-peer encrypted message exchanges (see [Constellation](https://github.com/jpmorganchase/constellation) and [Tessera](https://github.com/jpmorganchase/tessera)) for directed transfer of private data to network participants
* __Alternative Consensus Mechanisms__ - with no need for POW/POS in a permissioned network, Quorum instead offers multiple consensus mechanisms that are more appropriate for consortium chains:
* __Raft-based Consensus__ - a consensus model for faster blocktimes, transaction finality, and on-demand block creation
* __Istanbul BFT__ - a PBFT-inspired consensus algorithm with transaction finality, by AMIS.
* __Peer Permissioning__ - node/peer permissioning using smart contracts, ensuring only known parties can join the network
* __Higher Performance__ - Quorum offers significantly higher performance than public geth
* [__Privacy__](http://docs.goquorum.com/en/latest/Privacy/Overview/) - Quorum supports private transactions and private contracts through public/private state separation, and utilises peer-to-peer encrypted message exchanges (see [Constellation](https://github.com/jpmorganchase/constellation) and [Tessera](https://github.com/jpmorganchase/tessera)) for directed transfer of private data to network participants
* [__Alternative Consensus Mechanisms__](http://docs.goquorum.com/en/latest/Consensus/Consensus/) - with no need for POW/POS in a permissioned network, Quorum instead offers multiple consensus mechanisms that are more appropriate for consortium chains:
* [__Raft-based Consensus__](http://docs.goquorum.com/en/latest/Consensus/raft/raft/) - a consensus model for faster blocktimes, transaction finality, and on-demand block creation
* [__Istanbul BFT__](http://docs.goquorum.com/en/latest/Consensus/ibft/ibft/) - a PBFT-inspired consensus algorithm with transaction finality, by AMIS.
* [__Clique POA Consensus__](https://github.com/ethereum/EIPs/issues/225) - a default POA consensus algorithm bundled with Go Ethereum.
* [__Peer Permissioning__](http://docs.goquorum.com/en/latest/Permissioning/Permissions%20Overview/) - node/peer permissioning, ensuring only known parties can join the network
* [__Pluggable architecture__](http://docs.goquorum.com/en/latest/PluggableArchitecture/Overview/) - allows adding additional features as plugins to the core `geth`, providing extensibility, flexibility, and distinct isolation of Quorum features.
* __Higher Performance__ - Quorum offers significantly higher performance throughput than public geth
## Architecture
![Quorum Tessera Privacy Flow](https://raw.githubusercontent.com/jpmorganchase/quorum-docs/master/images/QuorumTransactionProcessing.JPG)
![Quorum Tessera Privacy Flow](https://github.com/jpmorganchase/quorum/blob/master/docs/Quorum%20Design.png)
The above diagram is a high-level overview of the privacy architecture used by Quorum. For more in-depth discussion of the components, refer to the [documentation site](https://docs.goquorum.com).
The above diagram is very high-level overview of component architecture used by Quorum. For more in-depth discussion of the components and how they interact, please refer to [lifecycle of a private transaction](http://docs.goquorum.com/en/latest/Privacy/Lifecycle-of-a-private-transaction/).
## Quickstart
The quickest way to get started with Quorum is by following instructions in the [Quorum Examples](https://github.com/jpmorganchase/quorum-examples) repository. This allows you to quickly create a network of Quorum nodes, and includes a step-by-step demonstration of the privacy features of Quorum.
There are [several ways](https://docs.goquorum.com/en/latest/Getting%20Started/Getting%20Started%20Overview/) to quickly get up and running with Quorum. One of the easiest is to use [Quorum Wizard](https://docs.goquorum.com/en/latest/Getting%20Started/Getting%20Started%20Overview/#quickstart-with-quorum-wizard) - a command line tool that allows users to set up a development Quorum network on their local machine in less than *2 minutes*.
## Quorum Projects
Check out some of the interesting projects we are actively working on:
* [quorum-wizard](http://docs.goquorum.com/en/latest/Wizard/GettingStarted/): Setup a Quorum network in 2 minutes!
* [quorum-remix-plugin](http://docs.goquorum.com/en/latest/RemixPlugin/Overview/): The Quorum plugin for Ethereum's Remix IDE adds support for creating and interacting with private contracts on a Quorum network.
* [Cakeshop](http://docs.goquorum.com/en/latest/Cakeshop/Overview/): An integrated development environment and SDK for Quorum
* [quorum-examples](http://docs.goquorum.com/en/latest/Getting%20Started/Quorum-Examples/): Quorum demonstration examples
* <img src="docs/images/qubernetes/k8s-logo.png" width="15"/> [qubernetes](http://docs.goquorum.com/en/latest/Getting%20Started/Getting%20Started%20Overview/#quorum-on-kubernetes): Deploy Quorum on Kubernetes
* [quorum-cloud](http://docs.goquorum.com/en/latest/Getting%20Started/Getting%20Started%20Overview/#creating-a-network-deployed-in-the-cloud): Tools to help deploy Quorum network in a cloud provider of choice
* [quorum.js](http://docs.goquorum.com/en/latest/quorum.js/Overview/): Extends web3.js to support Quorum-specific APIs
* Zero Knowledge on Quorum
* [ZSL](https://github.com/jpmorganchase/quorum/wiki/ZSL) POC and [ZSL on Quorum](https://github.com/jpmorganchase/zsl-q/blob/master/README.md)
* [Anonymous Zether](https://github.com/jpmorganchase/anonymous-zether) implementation
## Further Reading
Further documentation can be found in the [docs](docs/) folder and on the [documentation site](https://docs.goquorum.com).
## Official Docker Containers
The official docker containers can be found under https://hub.docker.com/u/quorumengineering/
## See also
* [Quorum](https://github.com/jpmorganchase/quorum): this repository
* [Quorum Documentation](https://docs.goquorum.com)
* [quorum-examples](https://github.com/jpmorganchase/quorum-examples): Quorum demonstration examples
* <img src="docs/images/qubernetes/k8s-logo.png" width="15"/> [qubernetes](https://github.com/jpmorganchase/qubernetes): Deploy Quorum on Kubernetes
* [Quorum Community Slack Inviter](https://www.goquorum.com/slack-inviter): Quorum Slack community entry point
* Quorum Transaction Managers
* [Constellation](https://github.com/jpmorganchase/constellation): Haskell implementation of peer-to-peer encrypted message exchange for transaction privacy
* [Tessera](https://github.com/jpmorganchase/tessera): Java implementation of peer-to-peer encrypted message exchange for transaction privacy
* Quorum supported consensuses
* [Raft Consensus Documentation](https://docs.goquorum.com/en/latest/Consensus/raft/)
* [Istanbul BFT Consensus Documentation](https://github.com/ethereum/EIPs/issues/650): [RPC API](https://docs.goquorum.com/en/latest/Consensus/ibft/istanbul-rpc-api.md) and [technical article](https://medium.com/getamis/istanbul-bft-ibft-c2758b7fe6ff). __Please note__ that updated istanbul-tools is now hosted in [this](https://github.com/jpmorganchase/istanbul-tools/) repository
* [Clique POA Consensus Documentation](https://github.com/ethereum/EIPs/issues/225) and a [guide to setup clique json](https://modalduality.org/posts/puppeth/) with [puppeth](https://blog.ethereum.org/2017/04/14/geth-1-6-puppeth-master/)
* Zero Knowledge on Quorum
* [ZSL](https://github.com/jpmorganchase/quorum/wiki/ZSL) wiki page and [documentation](https://github.com/jpmorganchase/zsl-q/blob/master/README.md)
* [Anonymous Zether](https://github.com/jpmorganchase/anonymous-zether) implementation
* [quorum-cloud](https://github.com/jpmorganchase/quorum-cloud): Tools to help deploy Quorum network in a cloud provider of choice
* [Cakeshop](https://github.com/jpmorganchase/cakeshop): An integrated development environment and SDK for Quorum
## Third Party Tools/Libraries
The following Quorum-related libraries/applications have been created by Third Parties and as such are not specifically endorsed by J.P. Morgan. A big thanks to the developers for improving the tooling around Quorum!

View File

@ -927,7 +927,7 @@ func GenDoc(ctx *cli.Context) {
if data, err := json.MarshalIndent(v, "", " "); err == nil {
output = append(output, fmt.Sprintf("### %s\n\n%s\n\nExample:\n```json\n%s\n```", name, desc, data))
} else {
log.Error("Error generating output", err)
log.Error("Error generating output", "err", err)
}
}
)

View File

@ -176,7 +176,7 @@ func TestGethDoesntStartWithoutPrivateTransactionManagerVariableSet(t *testing.T
expectedText := "the PRIVATE_CONFIG environment variable must be specified for Quorum"
result := strings.TrimSpace(geth.StderrText())
if strings.Index(result, expectedText) == -1 {
if !strings.Contains(result, expectedText) {
geth.Fatalf("bad stderr text. want '%s', got '%s'", expectedText, result)
}
}

View File

@ -244,4 +244,4 @@ func SetResetPrivateConfig(value string) func() {
return func() {
os.Setenv("PRIVATE_CONFIG", existingValue)
}
}
}

View File

@ -29,8 +29,8 @@ import (
// Tests the go-ethereum to Aleth chainspec conversion for the Stureby testnet.
func TestAlethSturebyConverter(t *testing.T) {
// //Quorum - skip this test as MinGasLimit and GasLimitBoundDivisor has been overriden for quorum
t.Skipf("skipping this test as MinGasLimit and GasLimitBoundDivisor has been overriden for quorum")
// //Quorum - skip this test as MinGasLimit and GasLimitBoundDivisor has been overridden for quorum
t.Skipf("skipping this test as MinGasLimit and GasLimitBoundDivisor has been overridden for quorum")
// /Quorum
blob, err := ioutil.ReadFile("testdata/stureby_geth.json")
@ -72,8 +72,8 @@ func TestAlethSturebyConverter(t *testing.T) {
// Tests the go-ethereum to Parity chainspec conversion for the Stureby testnet.
func TestParitySturebyConverter(t *testing.T) {
// //Quorum - skip this test as MinGasLimit and GasLimitBoundDivisor has been overriden for quorum
t.Skipf("skipping this test as MinGasLimit and GasLimitBoundDivisor has been overriden for quorum")
// //Quorum - skip this test as MinGasLimit and GasLimitBoundDivisor has been overridden for quorum
t.Skipf("skipping this test as MinGasLimit and GasLimitBoundDivisor has been overridden for quorum")
// /Quorum
blob, err := ioutil.ReadFile("testdata/stureby_geth.json")

View File

@ -179,7 +179,7 @@ func (w *wizard) importGenesis() {
// Parse the genesis file and inject it successful
var genesis core.Genesis
if err := json.NewDecoder(reader).Decode(&genesis); err != nil {
log.Error("Invalid genesis spec: %v", err)
log.Error("Invalid genesis spec", "err", err)
return
}
log.Info("Imported genesis block")

View File

@ -74,8 +74,8 @@ func TestSetImmutabilityThreshold(t *testing.T) {
fs.Int(QuorumImmutabilityThreshold.Name, 0, "")
arbitraryCLIContext := cli.NewContext(nil, fs, nil)
assert.NoError(t, arbitraryCLIContext.GlobalSet(QuorumImmutabilityThreshold.Name, strconv.Itoa(100000)))
assert.True(t, arbitraryCLIContext.GlobalIsSet(QuorumImmutabilityThreshold.Name) == true, "immutability threshold flag not set")
assert.True(t, arbitraryCLIContext.GlobalInt(QuorumImmutabilityThreshold.Name) == 100000, "immutability threshold value not set")
assert.True(t, arbitraryCLIContext.GlobalIsSet(QuorumImmutabilityThreshold.Name), "immutability threshold flag not set")
assert.Equal(t, 100000, arbitraryCLIContext.GlobalInt(QuorumImmutabilityThreshold.Name), "immutability threshold value not set")
}
func TestSetPlugins_whenTypical(t *testing.T) {

View File

@ -242,7 +242,7 @@ func (sb *backend) Verify(proposal istanbul.Proposal) (time.Duration, error) {
// Sign implements istanbul.Backend.Sign
func (sb *backend) Sign(data []byte) ([]byte, error) {
hashData := crypto.Keccak256([]byte(data))
hashData := crypto.Keccak256(data)
return crypto.Sign(hashData, sb.privateKey)
}

View File

@ -148,11 +148,8 @@ func TestCommit(t *testing.T) {
for _, test := range testCases {
expBlock := test.expectedBlock()
go func() {
select {
case result := <-backend.commitCh:
commitCh <- result
return
}
result := <-backend.commitCh
commitCh <- result
}()
backend.proposedBlockHash = expBlock.Hash()

View File

@ -19,7 +19,6 @@ package backend
import (
"bytes"
"errors"
"golang.org/x/crypto/sha3"
"math/big"
"math/rand"
"time"
@ -36,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
lru "github.com/hashicorp/golang-lru"
"golang.org/x/crypto/sha3"
)
const (
@ -67,7 +67,7 @@ var (
// errInvalidUncleHash is returned if a block contains an non-empty uncle list.
errInvalidUncleHash = errors.New("non empty uncle hash")
// errInconsistentValidatorSet is returned if the validator set is inconsistent
errInconsistentValidatorSet = errors.New("non empty uncle hash")
// errInconsistentValidatorSet = errors.New("non empty uncle hash")
// errInvalidTimestamp is returned if the timestamp of a block is lower than the previous block's timestamp + the minimum block period.
errInvalidTimestamp = errors.New("invalid timestamp")
// errInvalidVotingChain is returned if an authorization list is attempted to
@ -81,7 +81,7 @@ var (
// errEmptyCommittedSeals is returned if the field of committed seals is zero.
errEmptyCommittedSeals = errors.New("zero committed seals")
// errMismatchTxhashes is returned if the TxHash in header is mismatch.
errMismatchTxhashes = errors.New("mismatch transcations hashes")
errMismatchTxhashes = errors.New("mismatch transactions hashes")
)
var (
defaultDifficulty = big.NewInt(1)
@ -195,7 +195,7 @@ func (sb *backend) verifyCascadingFields(chain consensus.ChainReader, header *ty
if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash {
return consensus.ErrUnknownAncestor
}
if uint64(parent.Time)+sb.config.BlockPeriod > header.Time {
if parent.Time+sb.config.BlockPeriod > header.Time {
return errInvalidTimestamp
}
// Verify validators in extraData. Validators in snapshot and extraData should be the same.

View File

@ -19,7 +19,6 @@ package backend
import (
"bytes"
"crypto/ecdsa"
"github.com/ethereum/go-ethereum/core/rawdb"
"math/big"
"reflect"
"testing"
@ -30,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/istanbul"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
@ -167,14 +167,12 @@ func TestSealStopChannel(t *testing.T) {
stop := make(chan struct{}, 1)
eventSub := engine.EventMux().Subscribe(istanbul.RequestEvent{})
eventLoop := func() {
select {
case ev := <-eventSub.Chan():
_, ok := ev.Data.(istanbul.RequestEvent)
if !ok {
t.Errorf("unexpected event comes: %v", reflect.TypeOf(ev.Data))
}
stop <- struct{}{}
ev := <-eventSub.Chan()
_, ok := ev.Data.(istanbul.RequestEvent)
if !ok {
t.Errorf("unexpected event comes: %v", reflect.TypeOf(ev.Data))
}
stop <- struct{}{}
eventSub.Unsubscribe()
}
go eventLoop()
@ -203,14 +201,12 @@ func TestSealCommittedOtherHash(t *testing.T) {
stopChannel := make(chan struct{})
go func() {
select {
case ev := <-eventSub.Chan():
if _, ok := ev.Data.(istanbul.RequestEvent); !ok {
t.Errorf("unexpected event comes: %v", reflect.TypeOf(ev.Data))
}
if err := engine.Commit(otherBlock, [][]byte{expectedCommittedSeal}); err != nil {
t.Error(err.Error())
}
ev := <-eventSub.Chan()
if _, ok := ev.Data.(istanbul.RequestEvent); !ok {
t.Errorf("unexpected event comes: %v", reflect.TypeOf(ev.Data))
}
if err := engine.Commit(otherBlock, [][]byte{expectedCommittedSeal}); err != nil {
t.Error(err.Error())
}
eventSub.Unsubscribe()
}()
@ -229,11 +225,9 @@ func TestSealCommittedOtherHash(t *testing.T) {
close(stopChannel)
}
select {
case output := <-blockOutputChannel:
if output != nil {
t.Error("Block not nil!")
}
output := <-blockOutputChannel
if output != nil {
t.Error("Block not nil!")
}
}

View File

@ -23,14 +23,13 @@ import (
"math/big"
"reflect"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/istanbul"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
"github.com/hashicorp/golang-lru"
lru "github.com/hashicorp/golang-lru"
)
const (

View File

@ -22,13 +22,12 @@ import (
"math/big"
"testing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/istanbul"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rlp"
"github.com/hashicorp/golang-lru"
lru "github.com/hashicorp/golang-lru"
)
func TestIstanbulMessage(t *testing.T) {
@ -147,10 +146,8 @@ func postAndWait(backend *backend, block *types.Block, t *testing.T) {
defer eventSub.Unsubscribe()
stop := make(chan struct{}, 1)
eventLoop := func() {
select {
case <-eventSub.Chan():
stop <- struct{}{}
}
<-eventSub.Chan()
stop <- struct{}{}
}
go eventLoop()
if err := backend.EventMux().Post(istanbul.RequestEvent{

View File

@ -207,9 +207,9 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
// Tally up the new vote from the validator
var authorize bool
switch {
case bytes.Compare(header.Nonce[:], nonceAuthVote) == 0:
case bytes.Equal(header.Nonce[:], nonceAuthVote):
authorize = true
case bytes.Compare(header.Nonce[:], nonceDropVote) == 0:
case bytes.Equal(header.Nonce[:], nonceDropVote):
authorize = false
default:
return nil, errInvalidVote

View File

@ -19,7 +19,6 @@ package backend
import (
"bytes"
"crypto/ecdsa"
"github.com/ethereum/go-ethereum/core/rawdb"
"math/big"
"reflect"
"testing"
@ -28,6 +27,7 @@ import (
"github.com/ethereum/go-ethereum/consensus/istanbul"
"github.com/ethereum/go-ethereum/consensus/istanbul/validator"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
@ -417,7 +417,7 @@ func TestSaveAndLoad(t *testing.T) {
},
},
Tally: map[common.Address]Tally{
common.StringToAddress("1234567893"): Tally{
common.StringToAddress("1234567893"): {
Authorize: false,
Votes: 20,
},

View File

@ -300,19 +300,19 @@ func TestProcessBacklog(t *testing.T) {
subjectPayload, _ := Encode(subject)
msgs := []*message{
&message{
{
Code: msgPreprepare,
Msg: prepreparePayload,
},
&message{
{
Code: msgPrepare,
Msg: subjectPayload,
},
&message{
{
Code: msgCommit,
Msg: subjectPayload,
},
&message{
{
Code: msgRoundChange,
Msg: subjectPayload,
},

View File

@ -210,7 +210,7 @@ OUTER:
committedSeals := v0.committedMsgs[0].committedSeals
for _, validator := range r0.valSet.List() {
for _, seal := range committedSeals {
if bytes.Compare(validator.Address().Bytes(), seal[:common.AddressLength]) == 0 {
if bytes.Equal(validator.Address().Bytes(), seal[:common.AddressLength]) {
signedCount++
break
}

View File

@ -17,12 +17,12 @@
package core
import (
"github.com/ethereum/go-ethereum/common"
"math/big"
"reflect"
"testing"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/istanbul"
"github.com/ethereum/go-ethereum/core/types"
elog "github.com/ethereum/go-ethereum/log"
@ -58,16 +58,12 @@ func TestNewRequest(t *testing.T) {
request1 := makeBlock(1)
sys.backends[0].NewRequest(request1)
select {
case <-time.After(1 * time.Second):
}
<-time.After(1 * time.Second)
request2 := makeBlock(2)
sys.backends[0].NewRequest(request2)
select {
case <-time.After(1 * time.Second):
}
<-time.After(1 * time.Second)
for _, backend := range sys.backends {
if len(backend.committedMsgs) != 2 {

View File

@ -42,7 +42,7 @@ var (
// errFailedDecodeCommit is returned when the COMMIT message is malformed.
errFailedDecodeCommit = errors.New("failed to decode COMMIT")
// errFailedDecodeMessageSet is returned when the message set is malformed.
errFailedDecodeMessageSet = errors.New("failed to decode message set")
// errFailedDecodeMessageSet = errors.New("failed to decode message set")
// errInvalidSigner is returned when the message is signed by a validator different than message sender
errInvalidSigner = errors.New("message not signed by the sender")
)

View File

@ -93,7 +93,7 @@ func (c *core) handleRoundChange(msg *message, src istanbul.Validator) error {
// Once we received f+1 ROUND CHANGE messages, those messages form a weak certificate.
// If our round number is smaller than the certificate's round number, we would
// try to catch up the round number.
if c.waitingForRoundChange && num == int(c.valSet.F()+1) {
if c.waitingForRoundChange && num == c.valSet.F()+1 {
if cv.Round.Cmp(roundView.Round) < 0 {
c.sendRoundChange(roundView.Round)
}

View File

@ -18,13 +18,13 @@ package core
import (
"crypto/ecdsa"
"github.com/ethereum/go-ethereum/core/rawdb"
"math/big"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/istanbul"
"github.com/ethereum/go-ethereum/consensus/istanbul/validator"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"

View File

@ -82,7 +82,7 @@ const (
msgPrepare
msgCommit
msgRoundChange
msgAll
// msgAll
)
type message struct {
@ -142,7 +142,7 @@ func (m *message) FromPayload(b []byte, validateFn func([]byte, []byte) (common.
if err != nil {
return err
}
if bytes.Compare(signerAdd.Bytes(), m.Address.Bytes()) != 0 {
if !bytes.Equal(signerAdd.Bytes(), m.Address.Bytes()) {
return errInvalidSigner
}
}

View File

@ -34,7 +34,7 @@ func RLPHash(v interface{}) (h common.Hash) {
// GetSignatureAddress gets the signer address from the signature
func GetSignatureAddress(data []byte, sig []byte) (common.Address, error) {
// 1. Keccak data
hashData := crypto.Keccak256([]byte(data))
hashData := crypto.Keccak256(data)
// 2. Recover public key
pubkey, err := crypto.SigToPub(hashData, sig)
if err != nil {

View File

@ -94,7 +94,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
var (
ringKeys = make([]*ecdsa.PrivateKey, 1000)
ringAddrs = make([]common.Address, len(ringKeys))
bigTxGas = new(big.Int).SetUint64(params.TxGas)
// bigTxGas = new(big.Int).SetUint64(params.TxGas)
)
func init() {

View File

@ -43,7 +43,7 @@ import (
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
"github.com/hashicorp/golang-lru"
lru "github.com/hashicorp/golang-lru"
)
var (
@ -1295,7 +1295,7 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
// QUORUM
// checks if the consensus engine is Rfat
func(bc *BlockChain) isRaft() bool{
func (bc *BlockChain) isRaft() bool {
return bc.chainConfig.IsQuorum && bc.chainConfig.Istanbul == nil && bc.chainConfig.Clique == nil
}
@ -1318,6 +1318,7 @@ func (bc *BlockChain) CommitBlockWithState(deleteEmptyObjects bool, state, priva
}
return nil
}
// END QUORUM
// writeBlockWithState writes the block and all associated state to the database,
@ -1366,7 +1367,6 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
}
triedb := bc.stateCache.TrieDB()
// If we're running an archive node, always flush
if bc.cacheConfig.TrieDirtyDisabled {
if err := triedb.Commit(root, false); err != nil {
@ -1557,6 +1557,12 @@ func mergeReceipts(pub, priv types.Receipts) types.Receipts {
func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, []interface{}, []*types.Log, error) {
// If the chain is terminating, don't even bother starting up
if atomic.LoadInt32(&bc.procInterrupt) == 1 {
log.Debug("Premature abort during blocks processing")
// QUORUM
if bc.isRaft() {
// Only returns an error for raft mode
return 0, nil, nil, ErrAbortBlocksProcessing
}
return 0, nil, nil, nil
}
// Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss)

View File

@ -73,10 +73,7 @@ func (cg *callHelper) MakeCall(private bool, key *ecdsa.PrivateKey, to common.Ad
vmenv := vm.NewEVM(context, publicState, privateState, params.QuorumTestChainConfig, vm.Config{})
sender := vm.AccountRef(msg.From())
vmenv.Call(sender, to, msg.Data(), 100000000, new(big.Int))
if err != nil {
return err
}
return nil
return err
}
// MakeCallHelper returns a new callHelper

View File

@ -2,17 +2,15 @@ package core
import (
"fmt"
"github.com/ethereum/go-ethereum/core/rawdb"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/private"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/private"
testifyassert "github.com/stretchr/testify/assert"
)

View File

@ -29,7 +29,7 @@ func TestSetSyncStatus(t *testing.T) {
// check if the value is set properly by calling Get
syncStatus := GetSyncStatus()
assert.True(syncStatus == true, fmt.Sprintf("Expected syncstatus %v . Got %v ", true, syncStatus))
assert.True(syncStatus, fmt.Sprintf("Expected syncstatus %v . Got %v ", true, syncStatus))
}
func TestSetDefaults(t *testing.T) {
@ -135,7 +135,7 @@ func TestRoleCache_UpsertRole(t *testing.T) {
roleInfo, err = RoleInfoMap.GetRole(ORGADMIN, ORGADMIN)
assert.True(err == nil, "errors encountered")
assert.True(roleInfo.Active == false, fmt.Sprintf("Expected role active status to be %v, got %v", true, roleInfo.Active))
assert.True(!roleInfo.Active, fmt.Sprintf("Expected role active status to be %v, got %v", true, roleInfo.Active))
}
func TestAcctCache_UpsertAccount(t *testing.T) {
@ -211,32 +211,32 @@ func TestValidateNodeForTxn(t *testing.T) {
assert := testifyassert.New(t)
// pass the enode as null and the response should be true
txnAllowed := ValidateNodeForTxn("", Acct1)
assert.True(txnAllowed == true, "Expected access %v, got %v", true, txnAllowed)
assert.True(txnAllowed, "Expected access %v, got %v", true, txnAllowed)
SetDefaultAccess()
// if a proper enode id is not passed, return should be false
txnAllowed = ValidateNodeForTxn("ABCDE", Acct1)
assert.True(txnAllowed == false, "Expected access %v, got %v", true, txnAllowed)
assert.True(!txnAllowed, "Expected access %v, got %v", true, txnAllowed)
// if cache is not populated but the enode and account details are proper,
// should return true
txnAllowed = ValidateNodeForTxn(NODE1, Acct1)
assert.True(txnAllowed == true, "Expected access %v, got %v", true, txnAllowed)
assert.True(txnAllowed, "Expected access %v, got %v", true, txnAllowed)
// populate an org, account and node. validate access
OrgInfoMap.UpsertOrg(NETWORKADMIN, "", NETWORKADMIN, big.NewInt(1), OrgApproved)
NodeInfoMap.UpsertNode(NETWORKADMIN, NODE1, NodeApproved)
AcctInfoMap.UpsertAccount(NETWORKADMIN, NETWORKADMIN, Acct1, true, AcctActive)
txnAllowed = ValidateNodeForTxn(NODE1, Acct1)
assert.True(txnAllowed == true, "Expected access %v, got %v", true, txnAllowed)
assert.True(txnAllowed, "Expected access %v, got %v", true, txnAllowed)
// test access from a node not linked to the org. should return false
OrgInfoMap.UpsertOrg(ORGADMIN, "", ORGADMIN, big.NewInt(1), OrgApproved)
NodeInfoMap.UpsertNode(ORGADMIN, NODE2, NodeApproved)
AcctInfoMap.UpsertAccount(ORGADMIN, ORGADMIN, Acct2, true, AcctActive)
txnAllowed = ValidateNodeForTxn(NODE1, Acct2)
assert.True(txnAllowed == false, "Expected access %v, got %v", true, txnAllowed)
assert.True(!txnAllowed, "Expected access %v, got %v", true, txnAllowed)
}
// This is to make sure enode.ParseV4() honors single hexNodeId value eventhough it does follow enode URI scheme

View File

@ -60,4 +60,3 @@ func TestQuorumSignPrivateQuorum(t *testing.T) {
}
}

View File

@ -20,12 +20,12 @@ import (
"crypto/ecdsa"
"crypto/elliptic"
"fmt"
testifyassert "github.com/stretchr/testify/assert"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
testifyassert "github.com/stretchr/testify/assert"
)
// run all the tests in this file
@ -115,8 +115,7 @@ func TestSignQuorumEIP155Public(t *testing.T) {
k1, _ := createKey(crypto.S256(), k1v)
// chainId 1 even EIP155Signer should be 37 conflicts with private transaction
var chainId int64
chainId = 2 // 7 2 10
var chainId int64 = 2 // 7 2 10
v0 := chainId*2 + 35 // sig[64] + 35 .. where sig[64] == 0
v1 := chainId*2 + 36 // sig[64] + 35 .. where sig[64] == 1
@ -139,7 +138,7 @@ func TestSignQuorumEIP155Public(t *testing.T) {
assert.True(from == addr, fmt.Sprintf("Expected from and address to be equal. Got %x want %x", from, addr))
// chainId 1 even EIP155Signer should be 38 conflicts with private transaction
assert.False(signedTx.IsPrivate(), fmt.Sprintf("Public transaction is set to a private transation v == [%v]", signedTx.data.V))
assert.False(signedTx.IsPrivate(), fmt.Sprintf("Public transaction is set to a private transition v == [%v]", signedTx.data.V))
signedTx, addr, _ = signTx(k1, EIPsigner)
@ -166,8 +165,7 @@ func TestSignQuorumEIP155FailPublicChain1(t *testing.T) {
k1, _ := createKey(crypto.S256(), k1v)
// chainId 1 even EIP155Signer should be 37.38 which conflicts with private transaction
var chainId int64
chainId = 1
var chainId int64 = 1
v0 := chainId*2 + 35 // sig[64] + 35 .. where sig[64] == 0
v1 := chainId*2 + 36 // sig[64] + 35 .. where sig[64] == 1

View File

@ -0,0 +1,24 @@
# Basic Network Permissioning
Basic Network Permissioning is a feature that controls which nodes can connect to a given node and also to which nodes the given node can dial out to. It is managed at the individual node level by providing the `--permissioned` command line flag when starting the node.
If the `--permissioned` flag is set, the node looks for a file named `<data-dir>/permissioned-nodes.json` . This file contains the whitelist of enodes that this node can connect to and accept connections from. Therefore, with permissioning enabled, only the nodes that are listed in the `permissioned-nodes.json` file become part of the network. If the `--permissioned` flag is specified but no nodes are added to the `permissioned-nodes.json` file then this node can neither connect to any node nor accept any incoming connections.
The `permissioned-nodes.json` file follows the below pattern, which is similar to the `<data-dir>/static-nodes.json` file that is used to specify the list of static nodes a given node always connects to:
``` json
[
"enode://remoteky1@ip1:port1",
"enode://remoteky1@ip2:port2",
"enode://remoteky1@ip3:port3",
]
```
Sample file: (node id truncated for clarity)
``` json
[
"enode://6598638ac5b15ee386210156a43f565fa8c485924894e2f3a967207c047470@127.0.0.1:30300",
]
```
!!! warning
Every node has its own copy of the `permissioned-nodes.json` file. If different nodes have different lists of remote keys, then each node may have a different list of permissioned nodes which may have an adverse effect on the network.

View File

@ -1,6 +1,6 @@
# Smart Contract design for permissions
The permissions model is completely built on smart contracts. The smart contract design is as below:
![contract design](images/ContractDesign.png)
![contract design](./images/ContractDesign.png)
The permissions smart contract design follows the Proxy-Implementation-Storage pattern which allows the implementation logic to change without changing the storage or interface layer. A brief description of the smart contracts is below:

View File

@ -1,6 +1,9 @@
# Introduction
The [current permission model](../Old%20Permissioning) within Quorum is limited to node level permissions only and allows a set of nodes which are part of `permissioned-nodes.json` to join the network. The model has been enhanced to cater for enterprise level needs to have a **smart contract based permission model**; this has the flexibility to manage nodes, accounts and account level access controls. The overview of the model is as depicted below:
![permissions mode](images/PermissionsModel.png)
# Enhanced Permissions Model
The Enhanced Permissions Model caters for enterprise-level needs by having a **smart contract-based permissioning model**. This allows for significant flexibility to manage nodes, accounts, and account-level access controls.
An overview of the model is as depicted below:
![permissions mode](./images/PermissionsModel.png)
### Key Definitions
* Network - A set of interconnected nodes representing an enterprise blockchain which contains organizations
* Organization - A set of roles, Ethereum accounts and nodes having a variety of permissions to interact with the network
@ -13,4 +16,4 @@ The [current permission model](../Old%20Permissioning) within Quorum is limited
As depicted above, in the enhanced permissions model, the network comprises a group of organizations. The network admin accounts defined at network level can propose and approve new organizations to join the network, and can assign an account as the organization administration account. The organization admin account can create roles, create sub organizations, assign roles to its accounts, and add any other node which is part of the organization. A sub organization can have its own set of roles, accounts and sub organizations. The organization administration account manages and controls all activities at the organization level. The organization administrator can create an admin role and assign the same to a different account to manage the administration of a sub organization. The access rights of an account are derived based on the role assigned to it. The account will be able to transact via any node linked to the sub org or at overall organizations level.
A sample network view is as depicted below:
![sample mode](images/sampleNetwork.png)
![sample mode](./images/sampleNetwork.png)

View File

@ -315,7 +315,9 @@ curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPer
> quorumPermission.addOrg("ABC", "enode://3d9ca5956b38557aba991e31cf510d4df641dce9cc26bfeb7de082f0c07abb6ede3a58410c8f249dabeecee4ad3979929ac4c7c496ad20b8cfdd061b7401b4f5@127.0.0.1:21003?discport=0&raftport=50404", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", {from: eth.accounts[0]})
"Action completed successfully"
```
If there are any pending items for approval, proposal of any new organization will fail. Also the enode id and accounts can be linked to one organization only.
```javascript tab="geth console"
> quorumPermission.addOrg("ABC", "enode://3d9ca5956b38557aba991e31cf510d4df641dce9cc26bfeb7de082f0c07abb6ede3a58410c8f249dabeecee4ad3979929ac4c7c496ad20b8cfdd061b7401b4f5@127.0.0.1:21003?discport=0&raftport=50404", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", {from: eth.accounts[0]})
Error: Pending approvals for the organization. Approve first
@ -336,8 +338,8 @@ Error: Account already in use in another organization
at web3.js:6347:15
at web3.js:5081:36
at <anonymous>:1:1
```
### `quorumPermission_approveOrg`
This api can be executed by a network admin account (`from:` in transactions args) only for approving a proposed organization into the network.
#### Parameters
@ -812,6 +814,7 @@ curl -X POST http://127.0.0.1:22000 --data '{"jsonrpc":"2.0","method":"quorumPer
```
## Roles
### Account access types
The table below indicates the numeric value for each account access type.
| AccessType | Value |
@ -864,4 +867,4 @@ The table below indicates the numeric value for various node status.
| Approved | 2 |
| Deactivated | 3 |
| Blacklisted | 4 |
| Recovery initiated for Blacklisted Node | 5 |
| Recovery initiated for Blacklisted Node | 5 |

View File

@ -1,13 +1,4 @@
**This section describes the usage of permission model for creation of a network, initial set up and management of network. The network management activities can be broadly categorized into:**
* [Initial network set up](#initial-network-set-up)
* [Proposing a new organization into the network](#proposing-a-new-organization-into-the-network)
* [Organization admin managing the organization level permissions](#organization-admin-managing-the-organization-level-permissions)
* [Suspending an organization temporarily](#suspending-an-organization-temporarily)
* [Revoking suspension of an organization](#revoking-suspension-of-an-organization)
* [Assigning admin privileges at organization and network level](#assigning-admin-privileges-at-organization-and-network-level)
Managing the advanced permissioning model can be broadly categorized into the following activities:
### Initial network set up
Please refer to [set up](../setup). For an existing network running with an older version of Quorum:
@ -99,7 +90,7 @@ then the network will have the following configuration once it has started up:
```
### Proposing a new organization into the network
Once the network is up, the network admin accounts can then propose a new organization into the network. Majority approval from the network admin accounts is required before an organization is approved. The APIs for [proposing](../Permissioning%20apis#quorumpermissionaddorg) and [approving](../Permissioning%20apis#quorumpermissionapproveorg) an organization are documented in [permission APIs](../Permissioning%20apis)
Once the network is up, the network admin accounts can then propose a new organization into the network. Majority approval from the network admin accounts is required before an organization is approved. The APIs for [proposing](../Permissioning%20apis#quorumpermission_addorg) and [approving](../Permissioning%20apis#quorumpermission_approveorg) an organization are documented in [permission APIs](../Permissioning%20apis)
#### Example
An example to propose and approve an organization by name `ORG1` is as shown below:
@ -182,7 +173,7 @@ The new node belonging to the organization can now join the network. In case the
### Organization admin managing the organization level permissions
Once the organization is approved and the node of the organization has joined the network, the organization admin can then create sub organizations, roles, add additional nodes at organization level, add accounts to the organization and change roles of existing organization level accounts.
To add a sub org at `ORG1` level refer to [addSubOrg API](../Permissioning%20apis#quorumpermissionaddsuborg)
To add a sub org at `ORG1` level refer to [addSubOrg API](../Permissioning%20apis#quorumpermission_addsuborg)
```javascript
> quorumPermission.addSubOrg("ORG1", "SUB1", "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0", {from: eth.accounts[0]})
"Action completed successfully"
@ -199,7 +190,7 @@ To add a sub org at `ORG1` level refer to [addSubOrg API](../Permissioning%20api
}
```
For adding a sub org the enode id is not mandatory. For the newly created sub org if the org admin desires to add an administration account, the org admin account will have to first create a role with `isAdmin` flag as `Y` and then assign this role to the account which belongs to the sub org. Once assigned the account will act as org admin at sub org level. Refer to [addNewRole API](../Permissioning%20apis#quorumpermissionaddnewrole)
For adding a sub org the enode id is not mandatory. For the newly created sub org if the org admin desires to add an administration account, the org admin account will have to first create a role with `isAdmin` flag as `Y` and then assign this role to the account which belongs to the sub org. Once assigned the account will act as org admin at sub org level. Refer to [addNewRole API](../Permissioning%20apis#quorumpermission_addnewrole)
```javascript
> quorumPermission.addNewRole("ORG1.SUB1", "SUBADMIN", 3, false, true,{from: eth.accounts[0]})
"Action completed successfully"
@ -259,7 +250,7 @@ The account `0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0` is now the admin for su
}]
```
To add an account to an organization refer to [addAccountToOrg API](../Permissioning%20apis#quorumpermissionaddaccounttoorg).
To add an account to an organization refer to [addAccountToOrg API](../Permissioning%20apis#quorumpermission_addaccounttoorg).
```javascript
> quorumPermission.addAccountToOrg("0x283f3b8989ec20df621166973c93b56b0f4b5455", "ORG1.SUB1", "SUBADMIN", {from: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0"})
"Action completed successfully"
@ -280,7 +271,7 @@ To add an account to an organization refer to [addAccountToOrg API](../Permissio
}]
```
To suspend an account [updateAccountStatus](../Permissioning%20apis#quorumpermissionupdateaccountstatus) API can be invoked with action as 1.
To suspend an account [updateAccountStatus](../Permissioning%20apis#quorumpermission_updateaccountstatus) API can be invoked with action as 1.
```javascript
> quorumPermission.updateAccountStatus("ORG1.SUB1", "0x283f3b8989ec20df621166973c93b56b0f4b5455", 1, {from: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0"})
"Action completed successfully"
@ -300,7 +291,7 @@ To suspend an account [updateAccountStatus](../Permissioning%20apis#quorumpermis
}]
```
To revoke suspension of an account [updateAccountStatus](../Permissioning%20apis#quorumpermissionupdateaccountstatus) API can be invoked with action as 2.
To revoke suspension of an account [updateAccountStatus](../Permissioning%20apis#quorumpermission_updateaccountstatus) API can be invoked with action as 2.
```javascript
> quorumPermission.updateAccountStatus("ORG1.SUB1", "0x283f3b8989ec20df621166973c93b56b0f4b5455", 2, {from: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0"})
"Action completed successfully"
@ -321,7 +312,7 @@ To revoke suspension of an account [updateAccountStatus](../Permissioning%20apis
}]
```
To [blacklist an account updateAccountStatus](../Permissioning%20apis#quorumpermissionupdateaccountstatus) API can be invoked with action as 3. Once blacklisted no further activity will be possible on the account.
To [blacklist an account updateAccountStatus](../Permissioning%20apis#quorumpermission_updateaccountstatus) API can be invoked with action as 3. Once blacklisted no further activity will be possible on the account.
```javascript
> quorumPermission.updateAccountStatus("ORG1.SUB1", "0x283f3b8989ec20df621166973c93b56b0f4b5455", 3, {from: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0"})
"Action completed successfully"
@ -342,7 +333,7 @@ To [blacklist an account updateAccountStatus](../Permissioning%20apis#quorumperm
}]
```
To [add nodes addNode ](../Permissioning%20apis#quorumpermissionaddnode) at organization and sub organization level by the org admin.
To [add Nodes ](../Permissioning%20apis#quorumpermission_addnode) at organization and sub organization level by the org admin.
```javascript
> quorumPermission.addNode("ORG1.SUB1", "enode://eacaa74c4b0e7a9e12d2fe5fee6595eda841d6d992c35dbbcc50fcee4aa86dfbbdeff7dc7e72c2305d5a62257f82737a8cffc80474c15c611c037f52db1a3a7b@127.0.0.1:21005?discport=0", {from: "0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0"})
"Action completed successfully"
@ -358,7 +349,7 @@ To [add nodes addNode ](../Permissioning%20apis#quorumpermissionaddnode) at orga
}]
```
Org admin can manage the status of the nodes by using [updateNodeStatus](../Permissioning%20apis#quorumpermissionupdatenodestatus) API. To deactivate a node the API can be invoked with action 1.
Org admin can manage the status of the nodes by using [updateNodeStatus](../Permissioning%20apis#quorumpermission_updatenodestatus) API. To deactivate a node the API can be invoked with action 1.
```javascript
> quorumPermission.getOrgDetails("ORG1.SUB1").nodeList
[{
@ -372,7 +363,7 @@ Org admin can manage the status of the nodes by using [updateNodeStatus](../Perm
}]
```
To activate the node back invoke [updateNodeStatus](../Permissioning%20apis#quorumpermissionupdatenodestatus) API with action 2.
To activate the node back invoke [updateNodeStatus](../Permissioning%20apis#quorumpermission_updatenodestatus) API with action 2.
```javascript
> quorumPermission.updateNodeStatus("ORG1.SUB1", "enode://eacaa74c4b0e7a9e12d2fe5fee6595eda841d6d992c35dbbcc50fcee4aa86dfbbdeff7dc7e72c2305d5a62257f82737a8cffc80474c15c611c037f52db1a3a7b@127.0.0.1:21005?discport=0",2, {from:"0x42ef6abedcb7ecd3e9c4816cd5f5a96df35bb9a0"})
"Action completed successfully"
@ -388,7 +379,7 @@ To activate the node back invoke [updateNodeStatus](../Permissioning%20apis#quor
}]
```
To blacklist a node invoke [updateNodeStatus](../Permissioning%20apis#quorumpermissionupdatenodestatus) API with action 3. Once blacklisted the node will never be able join the network again.
To blacklist a node invoke [updateNodeStatus](../Permissioning%20apis#quorumpermission_updatenodestatus) API with action 3. Once blacklisted the node will never be able join the network again.
```javascript
> quorumPermission.getOrgDetails("ORG1.SUB1").nodeList
[{
@ -410,7 +401,7 @@ Further:
* If a node is deactivated no transaction will be allowed from that node
### Suspending an organization temporarily
If there is a need to temporarily suspend all activities of an organization [updateOrgStatus](../Permissioning%20apis#quorumpermissionupdateorgstatus) API can be invoked with action 1. This can be invoked only by the network admin accounts and will reuiqre majority voting.
If there is a need to temporarily suspend all activities of an organization [updateOrgStatus](../Permissioning%20apis#quorumpermission_updateorgstatus) API can be invoked with action 1. This can be invoked only by the network admin accounts and will reuiqre majority voting.
```javascript
> quorumPermission.updateOrgStatus("ORG1", 1, {from: "0xed9d02e382b34818e88b88a309c7fe71e65f419d"})
"Action completed successfully"
@ -426,7 +417,7 @@ If there is a need to temporarily suspend all activities of an organization [upd
}
```
To approve the org, suspension majority approval from other network admin accounts is required. The api for the same is [approveOrgStatus](../Permissioning%20apis#quorumpermissionapproveorgstatus). Once approved the org status is marked as suspended.
To approve the org, suspension majority approval from other network admin accounts is required. The api for the same is [approveOrgStatus](../Permissioning%20apis#quorumpermission_approveorgstatus). Once approved the org status is marked as suspended.
```javascript
> quorumPermission.approveOrgStatus("ORG1", 1, {from: "0xca843569e3427144cead5e4d5999a3d0ccf92b8e"})
"Action completed successfully"
@ -446,7 +437,7 @@ When the org is suspended no transaction from any of the account linked to the o
### Revoking suspension of an organization
To revoke the suspension of an org [updateOrgStatus](../Permissioning%20apis#quorumpermissionupdateorgstatus) can be called with action as 2. This will require majority approval (API [approveOrgStatus](../Permissioning%20apis#quorumpermissionapproveorgstatus) with action 2).
To revoke the suspension of an org [updateOrgStatus](../Permissioning%20apis#quorumpermission_updateorgstatus) can be called with action as 2. This will require majority approval (API [approveOrgStatus](../Permissioning%20apis#quorumpermission_approveorgstatus) with action 2).
```javascript
> quorumPermission.updateOrgStatus("ORG1", 2, {from: "0xed9d02e382b34818e88b88a309c7fe71e65f419d"})
"Action completed successfully"
@ -468,7 +459,7 @@ Once the revoke is approved, all accounts in the organization and sub organizati
### Assigning admin privileges at organization and network level
There may be a scenario where one of the accounts at the organization level needs to have network admin level permissions and be able to perform network admin activities. Similarly there can be a need to change the admin account at organization level. Both these activities can be performed by existing network admin accounts only, and will require majority approval from the network admin accounts. The API usage details are as below.
To assign network admin or org admin role to an account invoke [assignAdminRole](../Permissioning%20apis#quorumpermissionassignadminrole).
To assign network admin or org admin role to an account invoke [assignAdminRole](../Permissioning%20apis#quorumpermission_assignadminrole).
```javascript
> quorumPermission.assignAdminRole("ORG1", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", "ADMIN", {from: "0xed9d02e382b34818e88b88a309c7fe71e65f419d"})
"Action completed successfully"
@ -482,7 +473,7 @@ To assign network admin or org admin role to an account invoke [assignAdminRole]
}
```
To approve the assignment of network admin role invoke [approveAdminRole](../Permissioning%20apis#quorumpermissionapproveadminrole) API.
To approve the assignment of network admin role invoke [approveAdminRole](../Permissioning%20apis#quorumpermission_approveadminrole) API.
```javascript
> quorumPermission.approveAdminRole("ORG1", "0x0638e1574728b6d862dd5d3a3e0942c3be47d996", {from: eth.accounts[0]})
"Action completed successfully"

View File

Before

Width:  |  Height:  |  Size: 798 KiB

After

Width:  |  Height:  |  Size: 798 KiB

View File

Before

Width:  |  Height:  |  Size: 340 KiB

After

Width:  |  Height:  |  Size: 340 KiB

View File

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 144 KiB

View File

@ -0,0 +1,6 @@
# Quorum Permissioning Overview
Quorum supports two network permissioning models.
* [Basic network permissioning](../Basic%20NetworkPermissions): Controls which nodes can connect to a given node and also to which nodes the given node can dial out to.
* [Enhanced network permissioning](../Enhanced%20Permissions%20Model/Overview): Caters for enterprise-level needs by having a **smart contract-based permissioning model**. This allows for significant flexibility to manage nodes, accounts, and account-level access controls.

View File

@ -30,15 +30,12 @@ The Enclave **performs** the following actions on request:
## Where does the Enclave sit in the private transaction flow?
The Enclave is the innermost actor of the sequence of events. The below diagram demonstrates where the Enclave sits:
![Quorum Tessera Privacy Flow](https://github.com/jpmorganchase/tessera/raw/master/Tessera%20Privacy%20flow.jpeg)
As the diagram shows, each Enclave interacts only with it's own transaction manager and no-one else.
Tessera provides different types of Enclaves to suit different needs:
The Enclave is the innermost actor of the sequence of events. Each Enclave only interacts with its corresponding Transaction Manager and nothing else.
See the [Lifecycle of a private transaction](../../../Lifecycle-of-a-private-transaction) for more information.
## Types of Enclave
Tessera provides different types of Enclaves to suit different needs:
### Local Enclave
The local Enclave is the classical option that was included in versions of Tessera prior to v0.9. This includes the Enclave inside the same process and the transaction manager. This is still an option, and requires all the Enclave configuration to be inside the same configuration file and the Transaction Manager configuration.

View File

@ -147,7 +147,19 @@ Password update can be used in multiple ways. Running any of these commands wil
```
All options have been overriden here but only the options you wish to alter from their defaults need to be provided.
### Password-protection algorithm
The following steps detail the process of password-protecting a private key:
1. Given private key `K` and password `P`
2. Generate random Argon2i nonce
3. Generate random encryption nonce
4. Stretch `P` using Argon2i (with the Argon2i nonce and custom or default [ArgonOptions](#securing-private-keys)) into a 32-byte master key (`MK`)
5. Symmetrically encrypt `K` with `MK` and the encryption nonce
## Using alternative curve key types
By default the `-keygen` and `-updatepassword` commands generate and update [NaCl](https://nacl.cr.yp.to/) compatible keys.
As of Tessera v0.10.2, the `--encryptor.type=EC` CLI option can be provided to generate/update keys of different types. See [encryptor config](../../../Configuration/Configuration Overview/#encryptor-supporting-alternative-curves-in-tessera) for more details.
## Rotation
Tessera is built to support rotation trivially, by allowing counterparties to advertise multiple keys at once. The tooling to make rotation seamless and automatic is on our Roadmap.

View File

@ -0,0 +1,256 @@
Messages are written to the logs using these rules for the log level:
* `ERROR`: system failures or situations that require some action to ensure correct operation of the system.
* `WARN`: notifications that don't require immediate action or that are indications that a transaction failed.
* `INFO`: information message to allow investigation of issues or to provide reassurance that the system is operating correctly.
* `DEBUG`: very verbose logging to assist with investigation of issues
The log level is written out in uppercase as part of the log message, this can be used for alert monitoring.
## Errors
Below is a non-exhaustive list of error messages and suggested actions. Braces '{}' indicate where further detail of the root cause is logged as part of the message.
<table>
<tr>
<th>Message</th>
<th>Cause</th>
</tr>
<tr>
<td>Error decoding message: {error details}</td>
<td>Invalid base64 in privateFrom/privateFor from Quorum or in tx hash for resend<br><b>Action:</b> <em>Sender needs to provide valid base64</em></td>
</tr>
<tr>
<td>Error occurred: {error details} Root cause: {root cause}</td>
<td>Generated for a variety of reasons:
<ul>
<li> Invalid content in message, e.g. <pre>curl -X POST "http://localhost:9001/push" \ <br> -H "accept: application/json" \<br> -H "Content-Type: application/octet-stream" \ <br> -d "[ \"a garbage string\"]"</pre></li>
<li> Could not send message to peer, e.g. <pre>"Root cause: Unable to push payload to recipient url<br>http://localhost:9001/"</pre></li>
</ul>
<b>Action:</b> <em>depends on the root cause in the log message</em>
</td>
</tr>
<tr>
<td>Enclave unavailable: {error details}</td>
<td><b>Action:</b> <em>user needs to check why enclave is unavailable (look in log file for enclave)</em></td>
</tr>
<tr>
<td>Entity not found: {error details}</td>
<td>API request received against <code>q2tserver/transaction/{key}</code> where key is not a tx hash in the DB</td>
</tr>
<tr>
<td>Entity not found:{error details}</td>
<td>Thrown if endpoint doesn't exist on that API, e.g.<pre>curl -s http://localhost:9001/invalidendpoint</pre></td>
</tr>
<tr>
<td>Security exception {followed by exception message, like "java.lang.SecurityException: No key found for url 127.1.1.1"}</td>
<td>Thrown if <code>enableRemoteKeyValidation: true</code> and partyinfo request received from a URL for which we don't hold a public key (i.e. potentially a malicious party).<br>Note: if key validation enabled then this exception will be thrown during startup whilst the nodes exchange key information.</td>
</tr>
<tr>
<td>ERROR c.q.t.a.e.DefaultExceptionMapper - HTTP 400 Bad Request</td>
<td>Logged if received message is corrupt/incorrectly formatted, e.g.<pre>curl -X POST "http://localhost:9001/resend" \<br> -H "accept: text/plain" \<br> -H "Content-Type: application/json" \<br> -d "{ \"some rubbish\" }"</pre></td>
</tr>
<tr>
<td>Error while reading secret from file</td>
<td>Unable to read the secret key (password) from file specified by <code>TESSERA_CONFIG_SECRET</code><br>
<b>Action:</b> <em>ensure the secret key file config is correct, and file can be read</em>
</td>
</tr>
<tr>
<td>unable to initialize encryption facade {error details}</td>
<td>Unable to initialise elliptical curve encryption. Logged error message will give further details<br>
<b>Action:</b> <em>check configuration properties</em>
</td>
</tr>
<tr>
<td>unable to generate shared secret {error details}</td>
<td>Unable to generate shared secret for elliptical curve encryption. Logged error message will give further details.<br>
<b>Action:</b> <em>check configuration properties</em>
</td>
</tr>
<tr>
<td>unable to perform symmetric encryption {error details}</td>
<td>Unable to encrypt data. Logged error message will give further details.<br>
<b>Action:</b> <em>check configuration properties</em>
</td>
</tr>
<tr>
<td>unable to perform symmetric decryption {error details}</td>
<td>Unable to decrypt data. Logged error message will give further details.<br>
<b>Action:</b> <em>check configuration properties</em>
</td>
</tr>
<tr>
<td>Error when executing action {action type}, exception details: {error details}</td>
<td> Unable to start Influx DB. Logged error message will give further details<br>
<b>Action:</b> <em>check configuration properties</em>
</td>
</tr>
<tr>
<td>Error creating bean with name 'entityManagerFactory'</td>
<td>Unable to create connection to database due to failure to decrypt the DB password using the supplied secret key<br>
<b>Action:</b> <em>ensure that the correct value is supplied for the secret key</em>
</td>
</tr>
<tr>
<td>Config validation issue: {property name} {error details}</td>
<td>Invalid configuration detected<br>
<b>Action:</b> <em>correct the configuration of the named property.</em>
</td>
</tr>
<tr>
<td>Invalid json, cause is {error details}</td>
<td>Invalid json in the configuration file<br>
<b>Action:</b> <em>check the configuration file for mistakes.</em>
</td>
</tr>
<tr>
<td>Configuration exception, cause is {error details}</td>
<td>Invalid data in the configuration file<br>
<b>Action:</b> <em>check the configuration file for mistakes.</em>
</td>
</tr>
<tr>
<td>CLI exception, cause is {error details}</td>
<td>Invalid command line<br>
<b>Action:</b> <em>The error details will give further information regarding the action to be taken.</em>
</td>
</tr>
</table>
## Warnings
Below is a list of warning messages and possible causes. Braces '{}' indicate where further detail of the root cause is logged as part of the message.
<table>
<tr>
<th>Message</th>
<th>Cause</th>
</tr>
<tr>
<td>Public key {publicKey} not found when searching for private key</td>
<td>The key in a transaction is not recognised, i.e. it is not the public key of a known participant node.</td>
</tr>
<tr>
<td>Recipient not found for key: {public key}</td>
<td>An unrecognised participant is specified in a transaction.<br>No action needed.</td>
</tr>
<tr>
<td>Unable to unmarshal payload</td>
<td>A received message is corrupt, or incorrectly formatted</td>
</tr>
<tr>
<td>Remote host {remote host name} with IP {remote host IP} failed whitelist validation</td>
<td>Logged if whitelist validation is enabled and the remote host is not in the whitelist.<br>
<b>Action:</b> <em>either this is a malicious connection attempt, or mis-configuration</em>
</td>
</tr>
<tr>
<td>Ignoring unknown/unmatched json element: {element tag name}</td>
<td>An unrecognised element has been found in the config file.<br>
<b>Action:</b> <em>remove or correct the config file entry</em>
</td>
</tr>
<tr>
<td>Not able to find or read any secret for decrypting sensitive values in config</td>
<td>Secret key (password) could not be read from console or password file (see <code>TESSERA_CONFIG_SECRET in docs</code>).<br>
<b>Action:</b> <em>correction needed for the secret key or the file access permission</em>
</td>
</tr>
<tr>
<td>Some sensitive values are being given as unencrypted plain text in config. Please note this is NOT recommended for production environment.</td>
<td>Self explanatory</td>
</tr>
<tr>
<td>Not able to parse configured property. Will use default value instead</td>
<td>Error in config file</td>
</tr>
<tr>
<td>IOException while attempting to close remote session {error details}</td>
<td>Only occurs on shutdown, no action needed</td>
</tr>
<tr>
<td>Could not compute the shared key for pub {public key} and priv REDACTED</td>
<td>Possible cause is that a public key does not match the configured cryptography algorithm.<br>
<b>Action:</b> <em>ensure provided key is correct</em>
</td>
</tr>
<tr>
<td>Could not create sealed payload using shared key {shared key}</td>
<td>Possible cause is that a public key does not match the configured cryptography algorithm.<br>
<b>Action:</b> <em>ensure provided key is correct</em>
</td>
</tr>
<tr>
<td>Could not open sealed payload using shared key {shared key}</td>
<td>Possible cause that wrong password was given for key file decryption or making a change to the values in the keyfile so that the password no longer works.<br>
<b>Action:</b> <em>ensure that password is correct for the keyfile</em>
</td>
</tr>
<tr>
<td>Unable to generate a new keypair!</td>
<td>Internal error - potentially an issue with jnacl dependency</td>
</tr>
<tr>
<td>Exception thrown : {exception message} While starting service {service name}</td>
<td>Internal error - failed to start a service</td>
</tr>
<tr>
<td>Invalid key found {remote host url} recipient will be ignored</td>
<td>Remote key validation check failed.<br>No action needed, however it is a possible indication of a malicious node</td>
</tr>
<tr>
<td>Push returned status code for peer {remote peer url} was {status code}</td>
<td>The peer rejected a transaction 'push' request.<br>
<b>Action:</b> <em>check logs on peer to see why it failed</em>
</td>
</tr>
<tr>
<td>PartyInfo returned status code for peer{remote peer url} was {status code}</td>
<td>The peer rejected a partyInfo request.<br>
<b>Action:</b> <em>check logs on peer to see why it failed</em></td>
</tr>
<tr>
<td>Unable to resend payload to recipient with public key {public key}, due to {error details}</td>
<td>The peer rejected a transaction push request during a resend operation.<br>
<b>Action:</b> <em>check reason message, or logs on peer to see why it failed</em>
</td>
</tr>
<tr>
<td>Attempt is being made to update existing key with new url. Please switch on remote key validation to avoid a security breach.</td>
<td>Self explanatory</td>
</tr>
<tr>
<td>Failed to connect to node {remote node url}, due to {error details}</td>
<td>A remote node refused partyinfo request. Can occur if:
<ul>
<li>remote node is not running</li>
<li>remote node doesn't recognise this node's public key</li>
<li>remote node doesn't have this node's IP registered against a key</li>
<li>etc</li>
</ul>
Can also be expected to occur when nodes are shutdown/restarted, so not necessarily an error.
</td>
</tr>
<tr>
<td>Failed to connect to node {remote node url} for partyInfo, due to {error details}</td>
<td>A node failed partyInfo request during resend to peer.<br>
<b>Action:</b> <em>check reason message, or logs on peer to see why it failed</em>
</td>
</tr>
<tr>
<td>Failed to make resend request to node {remote node url} for key {public key}, due to {error details}</td>
<td>Peer communication failed during '/resend' request.<br>
<b>Action:</b> <em>check reason message, or logs on peer to see why it failed</em>
</td>
</tr>
</table>
!!! Note
Some messages will be rearranged to correct logging levels in our next release.
## To change the default log level
The level of logging is controlled by the logback configuration file. The default file packaged with Tessera can be seen [here](https://github.com/jpmorganchase/tessera/blob/master/tessera-dist/tessera-launcher/src/main/resources/logback.xml).
To specify a different logging configuration, pass a customised logback file on the command line using:
`-Dlogback.configurationFile=/path/to/logback.xml`

Binary file not shown.

Before

Width:  |  Height:  |  Size: 278 KiB

View File

@ -1,42 +0,0 @@
## Network Permissioning
Network Permissioning is a feature that controls which nodes can connect to a given node and also to which nodes the given node can dial out to. Currently, it is managed at the individual node level by the `--permissioned` command line flag when starting the node.
If the `--permissioned` flag is set, the node looks for a file named `<data-dir>/permissioned-nodes.json` . This file contains the whitelist of enodes that this node can connect to and accept connections from. Therefore, with permissioning enabled, only the nodes that are listed in the `permissioned-nodes.json` file become part of the network. If the `--permissioned` flag is specified but no nodes are added to the `permissioned-nodes.json` file then this node can neither connect to any node nor accept any incoming connections.
The `permissioned-nodes.json` file follows the below pattern, which is similar to the `<data-dir>/static-nodes.json` file that is used to specify the list of static nodes a given node always connects to:
``` json
[
"enode://remoteky1@ip1:port1",
"enode://remoteky1@ip2:port2",
"enode://remoteky1@ip3:port3",
]
```
Sample file: (node id truncated for clarity)
``` json
[
"enode://6598638ac5b15ee386210156a43f565fa8c485924894e2f3a967207c047470@127.0.0.1:30300",
]
```
!!! Note
In the current implementation, every node has its own copy of the `permissioned-nodes.json` file. In this case, if different nodes have a different list of remote keys then each node may have a different list of permissioned nodes - which may have an adverse effect. In a future release, the permissioned nodes list will be moved from the `permissioned-nodes.json` file to a Smart Contract, thereby ensuring that all nodes will use one global on-chain list to verify network connections.
## Enclave Encryption Technique
The Enclave encrypts payloads sent to it by the Transaction Manager using xsalsa20poly1305 (payload container) and curve25519xsalsa20poly1305 (recipient box). Each payload encryption produces a payload container, as well as N recipient boxes, where N is the number of recipients specified in the `privateFor` param of the Transaction.
* A payload container contains the payload encrypted with a symmetric key and a random nonce
* A recipient box is the Master Key for the payload container encrypted for the public key of a recipient using a random nonce. (Note that this is basically how PGP works, but using the [NaCl](https://nacl.cr.yp.to/) cryptographic primitives.)
We currently manually define all public key whitelists, and dont do automatic rotation of keys, however the system was built to support rotation trivially, by allowing counterparties to advertise multiple keys at once. The tooling to make it seamless and automatic is on the our Roadmap.
We also do not currently have a PKI system, but simply randomly generate keys that are manually added to whitelists (e.g. a registry of authorized counterparties on the blockchain.) The process is currently for operators to generate a keypair and then add the public keys to the whitelists manually.
## Private Key Storage Algorithm
The following steps detail the technique used to manage the private keys:
1. Given a password P
2. Generate random Argon2i nonce
3. Generate random NaCl secretbox nonce
4. Stretch P using Argon2i (and the Argon2i nonce) into a 32-byte master key (MK)
5. Encrypt Private key in secretbox using secretbox nonce and Argon2i-stretched MK

View File

@ -1,5 +1,5 @@
## Quorum Wizard
[Quorum Wizard](https://github.com/jpmorganchase/quorum-wizard) is a command line tool that allow users to set up a development Quorum network on their local machine in less than 2 minutes.
[Quorum Wizard](https://github.com/jpmorganchase/quorum-wizard) is a command line tool that allows users to set up a development Quorum network on their local machine in less than 2 minutes.
![](docs/quorum-wizard.gif)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

View File

@ -1,97 +0,0 @@
# ZSL Proof of Concept
!!! caution
The POC discussed in this section should not be considered production-ready
## Overview
Quorum supports both Public Contracts (which are executed in the standard Ethereum way, and are visible to all participants in the distributed ledger) and Private Contracts (which are shared between the parties to the private contract using Tessera, but can not be read by other participants). This approach preserves the privacy of the parties to the private contract, and the confidentiality of the private contracts business logic. However, a key limitation is that it does not support prevention of double-spending for digital assets that are exchanged within private contracts.
ZSL (zero-knowledge security layer) is a protocol designed by the team behind Zcash, that leverages zk-SNARKS to enable the transfer of digital assets on a distributed ledger, without revealing any information about the Sender, Recipient, or the quantity of assets that are being transferred.
J.P. Morgan and the Zcash team partnered to create a proof of concept (POC) implementation of ZSL for Quorum, which enables the issuance of digital assets using ZSL-enabled public smart contracts (z-contracts). We refer to such digital assets as “z-tokens”. Z-tokens can be shielded from public view and transacted privately. Proof that a shielded transaction has been executed can be presented to a private contract, thereby allowing the private contract to update its state in response to shielded transactions that are executed using public z-contracts.
This combination of Tesseras private contracts with ZSLs z-contracts, allows obligations that arise from a private contract, to be settled using shielded transfers of z-tokens, while maintaining full privacy and confidentiality.
For more background, please read the [POC Technical Design Document](https://github.com/jpmorganchase/zsl-q/blob/master/docs/ZSL-Quorum-POC_TDD_v1.3pub.pdf).
## Implementation
The ZSL proof of concept has been implemented as follows:
* ZSL-specific code resides in the [zsl-q](https://github.com/jpmorganchase/zsl-q) repo
* The Quorum integration is implemented as a separate branch of the Quorum repo - [zsl_geth1.5](https://github.com/jpmorganchase/quorum/tree/zsl_geth1.5)
* There is also a ZSL-specific branch of the quorum-examples repo - [zsl_geth1.5](https://github.com/jpmorganchase/quorum-examples/tree/zsl_geth1.5)
* The [zsl-q-params](https://github.com/jpmorganchase/zsl-q-params) repo contains the shared parameters required for generating and verifying the zk-SNARK proofs.
Full instructions on how to install Quorum with ZSL can be found in the [zsl-q README](https://github.com/jpmorganchase/zsl-q/blob/master/README.md).
Please note that this POC is intended to demonstrate how ZSL can complement Quorum, and provide a platform for experimentation and exploration of different use cases. It implements a simplified, stripped-down version of the Zerocash protocol to enable rapid prototyping. There is no formal security proof for the protocol, exception-handling has not been implemented for proof verification, the software has not been subjected to rigorous testing, and **it should not be considered “production-ready”**.
Broadly speaking, Quorum ZSL supplies a contract within which virtual funds can be "bundled" into cryptographically obfuscated "notes". Each note represents a store of value, and can be unlocked, or "redeemed", only using a secret spending key. To effect a private transfer, Alice may bundle value into a note, and then transmit the note's secret key to Bob through a private, off-chain channel. Bob may then redeem this note on-chain, revealing, in the process, no public link between Alice and himself. Note that in a previous version, a failure to link _Ethereum_ and _note_ signatures made possible a sort of "front-running" attack; this has been fixed by PR [#587](https://github.com/jpmorganchase/quorum/pull/587).
## Equity Trade use case example
The following example illustrates a specific use case for Quorum with ZSL - a simple equity trade where Alice is buying ACME shares from Bob. The POC includes a demonstration that implements this example; instructions on how to run it can be found [here](https://github.com/jpmorganchase/zsl-q/blob/master/README.md#example-2---private-contract-trade).
![Quorum Equity Trade Use Case diagram](Quorum_Equity_Use_Case.png)
### Beginning State:
* Z-contracts have been created for US dollars (the USD z-contract) and ACME shares (the ACME z-contract),
* Z-tokens have been issued into both contracts by the relevant issuer, then shielded and transferred to Alice and Bob.
* Alice owns some USD z-tokens, and Bob owns some ACME z-tokens. Both their holdings are shielded (i.e. a third-party observer cannot tell who owns what).
### User Story:
1. **A Private Contract is established between Alice and Bob using Tessera.**
1. The Private Contract specifies an equity trade of a specific quantity of ACME shares at a specific price in USD, between two specific parties: Alice (who is buying the ACME shares) and Bob (who is selling ACME shares).
1. The Private Contract references the USD and ACME z-contracts, and the relevant public keys and payment addresses of the parties.
1. One party initialises the contract (this is the equivalent of bidding/offering). It doesn't matter which party does this - in this example, it's Alice.
1. After being initialised, the contract state is "Bid" (it would be "Offer" if Bob had initialised it).
2. **The other party sends the Private Contract a transaction indicating acceptance of the terms.**
1. In this example, it is Bob who accepts Alices bid.
1. At this point, the trade is "done" (i.e. the terms are agreed and both parties have committed to the trade) and all that remains is for Settlement to take place. Assume that the USD must be paid first.
1. Contract state: Done.
3. **The Private Contract instructs Payment.**
1. When the contract's status updates to Done, it issues an instruction to the Buyer's (i.e. Alices) client to pay the relevant amount of USD to the Seller (Bob).
1. Alice's client receives and queues that instruction, and instructs a shielded payment.
4. **The Buyers pays USD to the Seller.**
1. Alice pays the relevant amount of USD z-tokens to Bob's USD payment address by generating the necessary zk-SNARK proof and sending it to the USD z-contract.
1. A shielded transaction takes place, creating a note within the z-contract which only Bob can spend (i.e. Bobs USD z-token balance is increased).
1. Alices balance of USD z-tokens is reduced accordingly.
5. **The Buyer provides evidence of payment to the Private Contract.**
1. Alice sends the Private Contract a transaction with the output note of the USD payment.
1. This also transmits the note to Bob so he can spend it.
6. **The Private Contract verifies the payment.**
1. The Private Contract calls a constant function on the USD z-contract, using the note supplied by Alice, to verify that the payment is valid.
1. The z-contract responds in a binary fashion to indicate whether the note commitment is in the z-contracts note accumulator (in which case the shielded payment is valid) or not.
1. If it is valid, the contract's status updates to Payment Received, and...
7. **..the Private Contract instructs Delivery.**
1. The Private Contract issues an instruction to the Seller's (i.e. Bobs) client to transfer the relevant amount of ACME shares to the Buyer
1. Bob's client receives and queues that instruction, and prompts him to make the payment.
8. **The Seller delivers ACME shares to the Buyer.**
1. Bob transfers the relevant amount of ACME z-tokens to Alice's ACME payment address by generating the necessary zk-SNARK proof and sending it to the ACME z-contract.
1. A shielded transaction takes place, creating a note output that only Alice can spend (i.e. Alices ACME z-token balance is increased).
1. Bobs balance of ACME z-tokens is reduced accordingly.
9. **The Seller provides evidence of delivery to the Private Contract**
1. Bob sends the Private Contract a transaction with the output note of the ACME delivery.
1. This also transmits the note to Alice so she can “spend” the note (i.e. transfer those tokens to someone else).
10. **The Private Contract verifies delivery.**
1. The Private Contract calls the ACME z-contract (using a constant function), using the note supplied by Bob, to verify that the transfer is valid.
1. If it is valid, the contract's status updates to Settled.
After Alice has delivered the USD z-tokens to Bob in step 5, he can send them to a third party (e.g. Carol).
* Carol will not be able to ascertain the source of the tokens (i.e. that Bob obtained them from Alice).
* Alice will not be able to ascertain when Bob transfers the tokens to someone else (or who the recipient is). She will be able to see that a transaction has occurred (because the transaction is written to the z-contract on the main Quorum chain which she has access to) but she will not be able to ascertain the Sender, Recipient, nor the quantity of tokens being transferred.
* The same holds true for the ACME z-tokens Alice has obtained from Bob.
### Protocol
The diagram below illustrates how the cryptographic protocol supports steps 1 thru 6 from the example above.
![ZSL/Quorum Proof of Concept Protocol (v0.4)](ZSL-Quorum-POC_Protocol_v0_4.png)

View File

@ -0,0 +1,12 @@
# quorum.js
## Overview, Installation, Quickstart & Examples
See the [project page README](https://github.com/jpmorganchase/quorum.js).
## API
This documentation provides additional usage and API information not included in the README.
quorum.js exports two modules:
* [`extend`](../extend)
* [`rawTransactionManager`](../RawTransactionManager)

View File

@ -0,0 +1,164 @@
The `RawTransactionManager` module of quorum.js provides access to private transaction APIs that require a connection to a [Privacy Manager](../../Privacy/Privacy-Manager).
## Example
```js
const Web3 = require("web3");
const quorumjs = require("quorum-js");
const web3 = new Web3("http://localhost:22000");
const tlsOptions = {
key: fs.readFileSync("./cert.key"),
clcert: fs.readFileSync("./cert.pem"),
cacert: fs.readFileSync("./cacert.pem"),
allowInsecure: false
};
const enclaveOptions = {
privateUrl: "http://localhost:9081",
tlsSettings: tlsOptions
};
const txnMngr = quorumjs.RawTransactionManager(web3, enclaveOptions);
txnMngr.sendRawTransaction(args);
```
## Parameters
| param | type | required | description |
| :---: | :---: | :---: | --- |
| <span style="white-space:nowrap">`web3`</span> | `Object` | yes | web3 instance |
| <span style="white-space:nowrap">`enclaveOptions`</span> | `Object` | yes | Privacy Manager connection configuration - see [enclaveOptions](#enclaveoptions) |
### enclaveOptions
| param | type | required | description |
| :---: | :---: | :---: | --- |
| <span style="white-space:nowrap">`privateUrl`</span> | `String` | yes (unless `ipcPath` is provided) | Tessera `ThirdParty` server url (if using the Constellation Privacy Manager use `ipcPath` instead) |
| <span style="white-space:nowrap">`ipcPath`</span> | `String` | no | path to Privacy Manager `.ipc` socket file, `privateUrl` is preferred |
| <span style="white-space:nowrap">`tlsSettings`</span> | `Object` | no | TLS configuration for HTTPS Privacy Manager connections - see [tlsSettings](#tlssettings) |
### tlsSettings
| param | type | required | description |
| :---: | :---: | :---: | --- |
| <span style="white-space:nowrap">`key`</span> | `String` | no | client private key as byte string |
| <span style="white-space:nowrap">`clcert`</span> | `String` | no | client certificate (signed/unsigned) as byte string |
| <span style="white-space:nowrap">`cacert`</span> | `String` | no | CA certificate as byte string |
| <span style="white-space:nowrap">`allowInsecure`</span> | `boolean` | no | do not verify the Privacy Manager's certificate (can be used to allow self-signed certificates) |
## Methods
### sendRawTransaction
!!! info "If using Constellation"
Constellation privacy managers do not support this method. Use [`sendRawTransactionViaSendAPI`](#sendrawtransactionviasendapi) instead.
```js
txnMngr.sendRawTransaction(txnParams);
```
Calls Tessera's `ThirdParty` `/storeraw` API, replaces the `data` field in `txnParams` with the response (i.e. encrypted-payload hash), signs the transaction with the `from` account defined in `txnParams`, marks the transaction as private, RLP encodes the transaction in hex format, and submits the signed transaction to the blockchain with `eth_sendRawPrivateTransaction`.
#### Parameters
1. `txnParams` - The transaction to sign and send
- `gasPrice`: `Number` - Must always be 0 in Quorum networks
- `gasLimit`: `Number` - The amount of gas to use for the transaction
- `to`: `String` - (optional) The destination address of the message, left undefined for a contract-creation transaction
- `value`: `Number` - (optional) The value transferred for the transaction
- `data`: `String` - (optional) Either a byte string containing the associated data of the message, or the initialisation code (bytecode) in the case of a contract-creation transaction
- `from` - `Object`: [Decrypted account object](https://web3js.readthedocs.io/en/v1.2.7/web3-eth-accounts.html#decrypt)
- `nonce`: `Number` - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce
- `privateFrom`: `String` - When sending a private transaction, the sending party's base64-encoded public key to use. If not present *and* passing `privateFor`, the default key as configured in the `TransactionManager` is used
- `privateFor`: `List<String>` - When sending a private transaction, an array of the recipients' base64-encoded public keys
- `isPrivate`: `boolean` - Is the transaction private
1. `Function` - (optional) If you pass a callback the HTTP request is made asynchronous.
#### Returns
A promise that resolves to the transaction receipt if the transaction was sent successfully, else rejects with an error.
### sendRawTransactionViaSendAPI
!!! info "If using Tessera"
Tessera privacy managers support [`sendRawTransaction`](#sendrawtransaction) which should be used instead. `sendRawTransactionViaSendAPI` requires exposing the `Q2T` server to the `js` app. Ideally only the `ThirdParty` server should be exposed to such applications.
```js
txnMngr.sendRawTransactionViaSendAPI(txnParams);
```
Calls Privacy Manager's `/send` API to encrypt txn data and send to all participant Privacy Manager nodes, replaces `data` field in `txnParams` with response (i.e. encrypted-payload hash), signs the transaction with the `from` account defined in `txnParams`, marks the transaction as private, and submits the signed transaction to the blockchain with `eth_sendRawTransaction`.
#### Parameters
1. `txnParams` - The transaction to sign and send
- `gasPrice`: `Number` - Must always be 0 in Quorum networks
- `gasLimit`: `Number` - The amount of gas to use for the transaction
- `to`: `String` - (optional) The destination address of the message, left undefined for a contract-creation transaction
- `value`: `Number` - (optional) The value transferred for the transaction
- `data`: `String` - (optional) Either a byte string containing the associated data of the message, or the initialisation code (bytecode) in the case of a contract-creation transaction
- `from` - `Object`: [Decrypted account object](https://web3js.readthedocs.io/en/v1.2.7/web3-eth-accounts.html#decrypt)
- `nonce`: `Number` - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce
- `privateFrom`: `String` - When sending a private transaction, the sending party's base64-encoded public key to use. If not present *and* passing `privateFor`, the default key as configured in the `TransactionManager` is used
- `privateFor`: `List<String>` - When sending a private transaction, an array of the recipients' base64-encoded public keys
- `isPrivate`: `boolean` - Is the transaction private
1. `Function` - (optional) If you pass a callback the HTTP request is made asynchronous.
#### Returns
A promise that resolves to the transaction receipt if the transaction was sent successfully, else rejects with an error.
### setPrivate
```js
txnMngr.setPrivate(rawTransaction);
```
Marks a signed transaction as private by changing the value of `v` to `37` or `38`.
#### Parameters
1. `rawTransaction`: `String` - RLP-encoded hex-format signed transaction
#### Returns
Updated RLP-encoded hex-format signed transaction
### storeRawRequest
```js
txnMngr.storeRawRequest(data, privateFrom);
```
Calls Tessera's `ThirdParty` `/storeraw` API to encrypt the provided `data` and store in preparation for a `eth_sendRawPrivateTransaction`.
#### Parameters
1. `data`: `String` - Hex encoded private transaction data (i.e. value of `data`/`input` field in the transaction)
1. `privateFrom`: `String` - Sending party's base64-encoded public key
#### Returns
A promise that resolves to the hex-encoded hash of the encrypted `data` (`key` field) that should be used to replace the `data` field of a transaction if externally signing.
### sendRawRequest
```js
txnMngr.sendRawRequest(rawTransaction, privateFor);
```
Call `eth_sendRawPrivateTransaction`, sending the signed transaction to the recipients specified in `privateFor`.
#### Parameters
1. `rawTransaction`: `String` - RLP-encoded hex-format signed transaction
1. `privateFor`: `List<String>` - List of the recipients' base64-encoded public keys
#### Returns
A promise that resolves to the transaction receipt if the transaction was sent successfully, else rejects with an error.
## Examples
### Externally signing and sending a private tx
!!!info
This is not supported by Constellation and requires Quorum v2.2.0+
[Code sample](https://github.com/jpmorganchase/quorum.js/blob/master/7nodes-test/deployContractViaHttp-externalSigningTemplate.js).
1. `storeRawRequest` to encrypt the transaction `data`
```js
txnManager.storeRawRequest(data, from)
```
1. Replace `data` field of transaction with `key` field from `storeRawRequest` response
1. Sign the transaction
1. Mark the signed transaction as private with `setPrivate`
```js
txnManager.setPrivate(signedTx)
```
1. Send the signed transaction to Quorum with `sendRawRequest`
```js
txnManager.sendRawRequest(serializedTransaction, privateFor)
```
### Other examples
The [7nodes-test](https://github.com/jpmorganchase/quorum.js/tree/master/7nodes-test) directory in the quorum.js project repo contains examples of quorum.js usage. These scripts can be tested with a running [7nodes test network](https://github.com/jpmorganchase/quorum-examples/tree/master/examples/7nodes).

21
docs/quorum.js/extend.md Normal file
View File

@ -0,0 +1,21 @@
The `extend` module of quorum.js allows Quorum-specific APIs to be added to an instance of `web3`.
## Example
```js
const Web3 = require("web3");
const quorumjs = require("quorum-js");
const web3 = new Web3("http://localhost:22000");
quorumjs.extend(web3);
web3.quorum.eth.sendRawPrivateTransaction(signedTx, args);
```
## Parameters
| param | type | required | description |
| :---: | :---: | :---: | --- |
| `web3` | `Object` | yes | web3 instance |
| `apis` | `String` | no | comma-separated list of APIs to extend `web3` with. Default is to add all APIs, i.e. `quorumjs.extend(web3, 'eth, raft, istanbul, quorumPermission')` |
## Methods
See the [Raft](../../Consensus/raft/raft-rpc-api), [Istanbul](../../Consensus/ibft/istanbul-rpc-api/), [Privacy](../../Getting%20Started/api/#privacy-apis), and [Permissioning](../../Permissioning/Enhanced%20Permissions%20Model/Permissioning%20apis) API documentation for API details.

View File

@ -2,7 +2,7 @@
<footer class="md-footer">
<div class="help-sidetab">
<div class="md-footer-meta__help">
<a href="https://clh7rniov2.execute-api.us-east-1.amazonaws.com/Express/" target="_blank" rel="noopener">
<a href="https://www.goquorum.com/slack-inviter" target="_blank" rel="noopener">
Need further help?
</a>
</div>

View File

@ -1,8 +1,9 @@
package eth
import (
"github.com/stretchr/testify/assert"
"testing"
"github.com/stretchr/testify/assert"
)
func TestQuorumDefautConfig(t *testing.T) {

View File

@ -254,10 +254,10 @@ func testGetBlockBodies(t *testing.T, protocol int) {
available []bool // Availability of explicitly requested blocks
expected int // Total number of existing blocks to expect
}{
{1, nil, nil, 1}, // A single random block should be retrievable
{10, nil, nil, 10}, // Multiple random blocks should be retrievable
{limit, nil, nil, limit}, // The maximum possible blocks should be retrievable
{limit + 1, nil, nil, limit}, // No more than the possible block count should be returned
{1, nil, nil, 1}, // A single random block should be retrievable
{10, nil, nil, 10}, // Multiple random blocks should be retrievable
{limit, nil, nil, limit}, // The maximum possible blocks should be retrievable
{limit + 1, nil, nil, limit}, // No more than the possible block count should be returned
{0, []common.Hash{pm.blockchain.Genesis().Hash()}, []bool{true}, 1}, // The genesis block should be retrievable
{0, []common.Hash{pm.blockchain.CurrentBlock().Hash()}, []bool{true}, 1}, // The chains head block should be retrievable
{0, []common.Hash{{}}, []bool{false}, 0}, // A non existent block should not be returned

View File

@ -42,7 +42,7 @@ var protocolName = "eth"
var ProtocolVersions = []uint{eth64, eth63}
// protocolLengths are the number of implemented message corresponding to different protocol versions.
var protocolLengths = map[uint]uint64{eth64: 17, eth63: 17}
// var protocolLengths = map[uint]uint64{eth64: 17, eth63: 17}
const protocolMaxMsgSize = 10 * 1024 * 1024 // Maximum cap on the size of a protocol message

View File

@ -972,7 +972,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNrOrHash
//This makes the return value a potential over-estimate of gas, rather than the exact cost to run right now
//if the transaction has a value then it cannot be private, so we can skip this check
if args.Value.ToInt().Cmp(big.NewInt(0)) == 0 {
if args.Value != nil && args.Value.ToInt().Cmp(big.NewInt(0)) == 0 {
homestead := b.ChainConfig().IsHomestead(new(big.Int).SetInt64(int64(rpc.PendingBlockNumber)))
istanbul := b.ChainConfig().IsIstanbul(new(big.Int).SetInt64(int64(rpc.PendingBlockNumber)))
var data []byte
@ -1618,8 +1618,7 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen
// /Quorum
// Assemble the transaction and sign with the wallet
var tx *types.Transaction
tx = args.toTransaction()
tx := args.toTransaction()
if args.IsPrivate() {
tx.SetPrivate()
@ -1688,7 +1687,7 @@ func (s *PublicTransactionPoolAPI) SendRawPrivateTransaction(ctx context.Context
return common.Hash{}, err
}
txHash := []byte(tx.Data())
txHash := tx.Data()
isPrivate := (args.PrivateFor != nil) && tx.IsPrivate()
if isPrivate {
@ -1756,7 +1755,7 @@ func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args Sen
// set gas to constant if nil
if args.IsPrivate() && args.Gas == nil {
gas := (hexutil.Uint64)(90000)
args.Gas = (*hexutil.Uint64)(&gas)
args.Gas = &gas
}
// /Quorum
if err := args.setDefaults(ctx, s.b); err != nil {
@ -1817,7 +1816,7 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxAr
// set gas to constant if nil
if sendArgs.IsPrivate() && sendArgs.Gas == nil {
gas := (hexutil.Uint64)(90000)
sendArgs.Gas = (*hexutil.Uint64)(&gas)
sendArgs.Gas = &gas
}
if err := sendArgs.setDefaults(ctx, s.b); err != nil {
return common.Hash{}, err

View File

@ -20,86 +20,92 @@ nav:
- Running Quorum: Getting Started/running.md
- Quorum API: Getting Started/api.md
- Quorum GraphQL: Getting Started/graphql.md
- Migration: Getting Started/migration.md
- Consensus:
- Consensus: Consensus/Consensus.md
- Raft BFT:
- Consensus/raft/raft.md
- Consensus/raft/raft-rpc-api.md
- Istanbul BFT:
- Overview: Consensus/ibft/ibft.md
- Consensus/ibft/istanbul-rpc-api.md
- Consensus/ibft/ibft-parameters.md
- Transaction & Contract Privacy:
- Overview: Privacy/Overview.md
- Privacy/Privacy-Manager.md
- Privacy/Lifecycle-of-a-private-transaction.md
- Tessera:
- What is Tessera: Privacy/Tessera/Tessera.md
- Configuration:
- Overview: Privacy/Tessera/Configuration/Configuration Overview.md
- Keys Config: Privacy/Tessera/Configuration/Keys.md
- TLS Config: Privacy/Tessera/Configuration/TLS.md
- Using CLI to override config: Privacy/Tessera/Configuration/Using CLI to override config.md
- Sample Configuration: Privacy/Tessera/Configuration/Sample Configuration.md
- Tessera Services:
- Transaction Manager: Privacy/Tessera/Tessera Services/Transaction Manager.md
- Enclave: Privacy/Tessera/Tessera Services/Enclave.md
- Keys:
- Key Generation: Privacy/Tessera/Tessera Services/Keys/Keys.md
- Setting up Hashicorp Vault: Privacy/Tessera/Tessera Services/Keys/Setting up a Hashicorp Vault.md
- Setting up Azure Key Vault: Privacy/Tessera/Tessera Services/Keys/Setting up an Azure Key Vault.md
- Setting up AWS Secrets Manager: Privacy/Tessera/Tessera Services/Keys/Setting up an AWS Secrets Manager.md
- Usage:
- Interfaces & API: Privacy/Tessera/Usage/Interface & API.md
- Admin Usage: Privacy/Tessera/Usage/Admin Usage.md
- Monitoring: Privacy/Tessera/Usage/Monitoring.md
- Migration from Constellation: Privacy/Tessera/Migration from Constellation.md
- Constellation:
- What is Constellation: Privacy/Constellation/Constellation.md
- How it works: Privacy/Constellation/How constellation works.md
- Sample Configuration: Privacy/Constellation/Sample Configuration.md
- Running Constellation: Privacy/Constellation/Installation & Running.md
- Permissioning:
- Overview: Permissioning/Overview.md
- Design: Permissioning/Contract Design.md
- Setup: Permissioning/setup.md
- APIs: Permissioning/Permissioning apis.md
- Usage: Permissioning/Usage.md
- Migration: Getting Started/migration.md
- Quorum Features:
- Transaction/Contract Privacy:
- Overview: Privacy/Overview.md
- Privacy/Privacy-Manager.md
- Privacy/Lifecycle-of-a-private-transaction.md
- Tessera:
- What is Tessera: Privacy/Tessera/Tessera.md
- Configuration:
- Overview: Privacy/Tessera/Configuration/Configuration Overview.md
- Keys Config: Privacy/Tessera/Configuration/Keys.md
- TLS Config: Privacy/Tessera/Configuration/TLS.md
- Using CLI to override config: Privacy/Tessera/Configuration/Using CLI to override config.md
- Sample Configuration: Privacy/Tessera/Configuration/Sample Configuration.md
- Tessera Services:
- Transaction Manager: Privacy/Tessera/Tessera Services/Transaction Manager.md
- Enclave: Privacy/Tessera/Tessera Services/Enclave.md
- Keys:
- Key Generation: Privacy/Tessera/Tessera Services/Keys/Keys.md
- Setting up Hashicorp Vault: Privacy/Tessera/Tessera Services/Keys/Setting up a Hashicorp Vault.md
- Setting up Azure Key Vault: Privacy/Tessera/Tessera Services/Keys/Setting up an Azure Key Vault.md
- Setting up AWS Secrets Manager: Privacy/Tessera/Tessera Services/Keys/Setting up an AWS Secrets Manager.md
- Usage:
- Interfaces & API: Privacy/Tessera/Usage/Interface & API.md
- Admin Usage: Privacy/Tessera/Usage/Admin Usage.md
- Monitoring: Privacy/Tessera/Usage/Monitoring.md
- Logging: Privacy/Tessera/Usage/Logging.md
- Migration from Constellation: Privacy/Tessera/Migration from Constellation.md
- Constellation:
- What is Constellation: Privacy/Constellation/Constellation.md
- How it works: Privacy/Constellation/How constellation works.md
- Sample Configuration: Privacy/Constellation/Sample Configuration.md
- Running Constellation: Privacy/Constellation/Installation & Running.md
- Consensus:
- Consensus: Consensus/Consensus.md
- Raft BFT:
- Consensus/raft/raft.md
- Consensus/raft/raft-rpc-api.md
- Istanbul BFT:
- Overview: Consensus/ibft/ibft.md
- Consensus/ibft/istanbul-rpc-api.md
- Consensus/ibft/ibft-parameters.md
- Permissioning:
- Overview: Permissioning/Permissions Overview.md
- Basic: Permissioning/Basic NetworkPermissions.md
- Enhanced:
- Overview: Permissioning/Enhanced Permissions Model/Overview.md
- Design: Permissioning/Enhanced Permissions Model/Contract Design.md
- Setup: Permissioning/Enhanced Permissions Model/setup.md
- APIs: Permissioning/Enhanced Permissions Model/Permissioning apis.md
- Usage: Permissioning/Enhanced Permissions Model/Usage.md
- Pluggable Architecture:
- Overview: PluggableArchitecture/Overview.md
- Settings: PluggableArchitecture/Settings.md
- Internals: PluggableArchitecture/Internals.md
- Plugins:
- helloworld:
- Interface: PluggableArchitecture/Plugins/helloworld/interface.md
- Implementation: PluggableArchitecture/Plugins/helloworld/implementation.md
- Plugin Development: PluggableArchitecture/PluginDevelopment.md
- DNS: Quorum Features/dns.md
- Quorum Projects:
- Quorum Wizard:
- Getting Started: Wizard/GettingStarted.md
- Interacting with the Network: Wizard/Interacting.md
- Cakeshop:
- Overview: Cakeshop/Overview.md
- Getting Started: Cakeshop/Getting started.md
- Cakeshop FAQ: Cakeshop/Cakeshop FAQ.md
- Remix Plugin:
- Overview: RemixPlugin/Overview.md
- Getting Started: RemixPlugin/GettingStarted.md
- quorum.js:
- Overview: quorum.js/Overview.md
- extend API: quorum.js/extend.md
- RawTransactionManager API: quorum.js/RawTransactionManager.md
- Security Framework:
- Overview: Security/Framework/Overview.md
- Quorum Network:
- Consortium: Security/Framework/Quorum Network Security/Consortium.md
- Quorum Node:
- Overview: Security/Framework/Quorum Network Security/Node.md
- Permissioning:
- Network Permissioning: Security/Framework/Quorum Network Security/Nodes/Permissioning/Network Permissioning.md
- Quorum Node: Security/Framework/Quorum Network Security/Node.md
- Transaction Manager: Security/Framework/Quorum Network Security/Transaction Manager.md
- Operational Considerations: Security/Framework/Quorum Network Security/Opertional Considerations.md
- Decentralized App:
- Frontend: Security/Framework/Decentralized Application/Frontend Components.md
- Smart Contracts: Security/Framework/Decentralized Application/Smart Contracts Security.md
- Pluggable Architecture:
- Overview: PluggableArchitecture/Overview.md
- Settings: PluggableArchitecture/Settings.md
- Internals: PluggableArchitecture/Internals.md
- Plugins:
- helloworld:
- Interface: PluggableArchitecture/Plugins/helloworld/interface.md
- Implementation: PluggableArchitecture/Plugins/helloworld/implementation.md
- Plugin Development: PluggableArchitecture/PluginDevelopment.md
- Quorum Wizard:
- Getting Started: Wizard/GettingStarted.md
- Interacting with the Network: Wizard/Interacting.md
- Cakeshop:
- Overview: Cakeshop/Overview.md
- Getting Started: Cakeshop/Getting started.md
- Cakeshop FAQ: Cakeshop/Cakeshop FAQ.md
- Remix Plugin:
- Overview: RemixPlugin/Overview.md
- Getting Started: RemixPlugin/Getting started.md
- Quorum Features:
- DNS: Features/dns.md
- Smart Contracts: Security/Framework/Decentralized Application/Smart Contracts Security.md
- How-To Guides:
- Adding new nodes: How-To-Guides/adding_nodes.md
- Adding IBFT validators: How-To-Guides/add_ibft_validator.md

View File

@ -193,7 +193,7 @@ type Config struct {
staticNodesWarning bool
trustedNodesWarning bool
oldGethResourceWarning bool
Plugins *plugin.Settings `toml:",omitempty"`
Plugins *plugin.Settings `toml:",omitempty"`
// Quorum: EnableNodePermission comes from EnableNodePermissionFlag --permissioned.
EnableNodePermission bool `toml:",omitempty"`
}

View File

@ -17,8 +17,8 @@
package node
import (
"path/filepath"
"crypto/ecdsa"
"path/filepath"
"reflect"
"github.com/ethereum/go-ethereum/accounts"

View File

@ -110,7 +110,6 @@ func isNewV4(n *Node) bool {
return n.r.IdentityScheme() == "" && n.r.Load(&k) == nil && len(n.r.Signature()) == 0
}
// Quorum
// NewV4Hostname creates a node from discovery v4 node information. The record

View File

@ -30,10 +30,7 @@ func isNodePermissioned(nodename string, currentNode string, datadir string, dir
if v == nodename {
log.Debug("isNodePermissioned", "connection", direction, "nodename", nodename[:NODE_NAME_LENGTH], "ALLOWED-BY", currentNode[:NODE_NAME_LENGTH])
// check if the node is blacklisted
if isNodeBlackListed(nodename, datadir) {
return false
}
return true
return !isNodeBlackListed(nodename, datadir)
}
}
log.Debug("isNodePermissioned", "connection", direction, "nodename", nodename[:NODE_NAME_LENGTH], "DENIED-BY", currentNode[:NODE_NAME_LENGTH])

View File

@ -98,7 +98,6 @@ func TestCheckCompatible(t *testing.T) {
rec2 := MaxCodeConfigStruct{big.NewInt(10), 40}
rec3 := MaxCodeConfigStruct{big.NewInt(8), 40}
storedMaxCodeConfig0 = append(storedMaxCodeConfig0, defaultRec)
storedMaxCodeConfig1 = append(storedMaxCodeConfig1, defaultRec)
@ -274,7 +273,7 @@ func TestCheckCompatible(t *testing.T) {
wantErr: nil,
},
{
stored: &ChainConfig{MaxCodeSize: 32, MaxCodeSizeChangeBlock:big.NewInt(10)},
stored: &ChainConfig{MaxCodeSize: 32, MaxCodeSizeChangeBlock: big.NewInt(10)},
new: &ChainConfig{MaxCodeSizeConfig: storedMaxCodeConfig1},
head: 15,
wantErr: nil,

View File

@ -1,8 +1,9 @@
package params
import (
"github.com/stretchr/testify/assert"
"testing"
"github.com/stretchr/testify/assert"
)
//Quorum - test key constant values modified by Quorum

View File

@ -50,7 +50,7 @@ type PermissionCtrl struct {
permOrg *pbind.OrgManager
permConfig *types.PermissionConfig
startWaitGroup *sync.WaitGroup // waitgroup to make sure all dependenies are ready before we start the service
startWaitGroup *sync.WaitGroup // waitgroup to make sure all dependencies are ready before we start the service
stopFeed event.Feed // broadcasting stopEvent when service is being stopped
errorChan chan error // channel to capture error when starting aysnc
@ -295,7 +295,7 @@ func (p *PermissionCtrl) monitorQIP714Block() error {
defer stopSubscription.Unsubscribe()
for {
select {
case head := <-chainHeadCh:
case head := <-chainHeadCh:
if p.eth.BlockChain().Config().IsQIP714(head.Block.Number()) {
types.SetDefaultAccess()
return

View File

@ -5,7 +5,6 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/miner"
"io/ioutil"
"log"
"math/big"
@ -24,6 +23,7 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/params"
@ -112,8 +112,8 @@ func setup() {
},
}
ethConf := &eth.Config{
Genesis: &core.Genesis{Config: params.AllEthashProtocolChanges, GasLimit: 10000000000, Alloc: genesisAlloc},
Miner: miner.Config{Etherbase: guardianAddress},
Genesis: &core.Genesis{Config: params.AllEthashProtocolChanges, GasLimit: 10000000000, Alloc: genesisAlloc},
Miner: miner.Config{Etherbase: guardianAddress},
Ethash: ethash.Config{
PowMode: ethash.ModeTest,
},
@ -274,7 +274,6 @@ func TestQuorumControlsAPI_OrgAPIs(t *testing.T) {
testObject := typicalQuorumControlsAPI(t)
invalidTxa := ethapi.SendTxArgs{From: getArbitraryAccount()}
// test AddOrg
orgAdminKey, _ := crypto.GenerateKey()
orgAdminAddress := crypto.PubkeyToAddress(orgAdminKey.PublicKey)

View File

@ -44,7 +44,7 @@ func (cc *CentralClient) getNewSecureDialer() Dialer {
if cc.config.CertFingerprint != "" {
conState := c.ConnectionState()
for _, peercert := range conState.PeerCertificates {
if bytes.Compare(peercert.Signature[0:], []byte(cc.config.CertFingerprint)) == 0 {
if bytes.Equal(peercert.Signature[0:], []byte(cc.config.CertFingerprint)) {
return c, nil
}
}
@ -100,10 +100,8 @@ func (cc *CentralClient) PluginDistribution(definition *PluginDefinition, outFil
defer func() {
_ = readCloser.Close()
}()
if _, err := io.Copy(outFile, readCloser); err != nil {
return err
}
return nil
_, err = io.Copy(outFile, readCloser)
return err
}
// perform HTTP GET

View File

@ -15,8 +15,5 @@ func (g *PluginGateway) Init(ctx context.Context, nodeIdentity string, rawConfig
HostIdentity: nodeIdentity,
RawConfiguration: rawConfiguration,
})
if err != nil {
return err
}
return nil
return err
}

View File

@ -56,10 +56,8 @@ func unzipFile(output string, input *zip.File) error {
defer func() {
_ = outputFile.Close()
}()
if _, err = io.Copy(outputFile, inputFile); err != nil {
return err
}
return nil
_, err = io.Copy(outputFile, inputFile)
return err
}
// Unzip src path to dest. Creates dest if the file doesnt exists.
@ -109,7 +107,7 @@ func getSha256Checksum(filePath string) (string, error) {
func unpackPlugin(pluginPath string) (string, *MetaData, error) {
// Unpack pluginMeta
// Reduce TOC/TOU risk
unpackDir := path.Join(os.TempDir(), string(uuid.New()), string(uuid.New()))
unpackDir := path.Join(os.TempDir(), uuid.New(), uuid.New())
err := os.MkdirAll(unpackDir, os.ModePerm)
if err != nil {
@ -139,7 +137,7 @@ func unpackPlugin(pluginPath string) (string, *MetaData, error) {
return unpackDir, nil, fmt.Errorf("plugin-meta.json entry point not set")
}
if isCleanEntryPoint(pluginMeta.EntryPoint) == false {
if !isCleanEntryPoint(pluginMeta.EntryPoint) {
return unpackDir, nil, fmt.Errorf("entrypoint must be only alphanumeric value")
}
return unpackDir, &pluginMeta, nil

16
private/cache/cache.go vendored Normal file
View File

@ -0,0 +1,16 @@
package cache
import (
"time"
gocache "github.com/patrickmn/go-cache"
)
const (
DefaultExpiration = 5 * time.Minute
CleanupInterval = 5 * time.Minute
)
func NewDefaultCache() *gocache.Cache {
return gocache.New(DefaultExpiration, CleanupInterval)
}

View File

@ -0,0 +1,30 @@
package notinuse
import "errors"
var ErrPrivateTxManagerNotInUse = errors.New("private transaction manager is not in use")
// NotInUsePrivateTxManager returns an error for all communication functions,
// stating that no private transaction manager is being used by the node
type PrivateTransactionManager struct{}
func (ptm *PrivateTransactionManager) Send(data []byte, from string, to []string) ([]byte, error) {
return nil, ErrPrivateTxManagerNotInUse
}
func (ptm *PrivateTransactionManager) StoreRaw(data []byte, from string) ([]byte, error) {
return nil, ErrPrivateTxManagerNotInUse
}
func (ptm *PrivateTransactionManager) SendSignedTx(data []byte, to []string) ([]byte, error) {
return nil, ErrPrivateTxManagerNotInUse
}
func (ptm *PrivateTransactionManager) Receive(data []byte) ([]byte, error) {
//error not thrown here, acts as though no private data to fetch
return nil, nil
}
func (ptm *PrivateTransactionManager) Name() string {
return "NotInUse"
}

View File

@ -0,0 +1,46 @@
package notinuse
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestName(t *testing.T) {
ptm := &PrivateTransactionManager{}
name := ptm.Name()
assert.Equal(t, name, "NotInUse", "got wrong name for NotInUsePrivateTxManager")
}
func TestSendReturnsError(t *testing.T) {
ptm := &PrivateTransactionManager{}
_, err := ptm.Send([]byte{}, "", []string{})
assert.Equal(t, err, ErrPrivateTxManagerNotInUse, "got wrong error in 'send'")
}
func TestStoreRawReturnsError(t *testing.T) {
ptm := &PrivateTransactionManager{}
_, err := ptm.StoreRaw([]byte{}, "")
assert.Equal(t, err, ErrPrivateTxManagerNotInUse, "got wrong error in 'storeraw'")
}
func TestReceiveReturnsError(t *testing.T) {
ptm := &PrivateTransactionManager{}
_, err := ptm.Receive([]byte{})
assert.Nil(t, err, "got unexpected error in 'receive'")
}
func TestSendSignedTxReturnsError(t *testing.T) {
ptm := &PrivateTransactionManager{}
_, err := ptm.SendSignedTx([]byte{}, []string{})
assert.Equal(t, err, ErrPrivateTxManagerNotInUse, "got wrong error in 'SendSignedTx'")
}

View File

@ -2,6 +2,9 @@ package private
import (
"os"
"strings"
"github.com/ethereum/go-ethereum/private/engine/notinuse"
"github.com/ethereum/go-ethereum/private/privatetransactionmanager"
)
@ -18,6 +21,9 @@ func FromEnvironmentOrNil(name string) PrivateTransactionManager {
if cfgPath == "" {
return nil
}
if strings.EqualFold(cfgPath, "ignore") {
return &notinuse.PrivateTransactionManager{}
}
return privatetransactionmanager.MustNew(cfgPath)
}

24
private/private_test.go Normal file
View File

@ -0,0 +1,24 @@
package private_test
import (
"os"
"reflect"
"testing"
"github.com/ethereum/go-ethereum/private/engine/notinuse"
"github.com/ethereum/go-ethereum/private"
)
func TestDummyPrivateTxManagerUsedWhenIgnoreSpecified(t *testing.T) {
os.Setenv("PRIVATE_CONFIG", "ignore")
ptm := private.FromEnvironmentOrNil("PRIVATE_CONFIG")
if _, ok := ptm.(*notinuse.PrivateTransactionManager); !ok {
expectedType := reflect.TypeOf(&notinuse.PrivateTransactionManager{}).String()
actualType := reflect.TypeOf(ptm).String()
t.Errorf("got wrong tx manager type. Expected '%s' but got '%s'", expectedType, actualType)
}
}

View File

@ -1,30 +1,20 @@
package privatetransactionmanager
import (
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"time"
"github.com/patrickmn/go-cache"
"github.com/ethereum/go-ethereum/private/cache"
gocache "github.com/patrickmn/go-cache"
)
type PrivateTransactionManager struct {
node *Client
c *cache.Cache
isPrivateTransactionManagerNotInUse bool
node *Client
c *gocache.Cache
}
var (
errPrivateTransactionManagerNotUsed = errors.New("private transaction manager not in use")
)
func (g *PrivateTransactionManager) Send(data []byte, from string, to []string) (out []byte, err error) {
if g.isPrivateTransactionManagerNotInUse {
return nil, errPrivateTransactionManagerNotUsed
}
out, err = g.node.SendPayload(data, from, to)
if err != nil {
return nil, err
@ -34,9 +24,6 @@ func (g *PrivateTransactionManager) Send(data []byte, from string, to []string)
}
func (g *PrivateTransactionManager) StoreRaw(data []byte, from string) (out []byte, err error) {
if g.isPrivateTransactionManagerNotInUse {
return nil, errPrivateTransactionManagerNotUsed
}
out, err = g.node.StorePayload(data, from)
if err != nil {
return nil, err
@ -46,9 +33,6 @@ func (g *PrivateTransactionManager) StoreRaw(data []byte, from string) (out []by
}
func (g *PrivateTransactionManager) SendSignedTx(data []byte, to []string) (out []byte, err error) {
if g.isPrivateTransactionManagerNotInUse {
return nil, errPrivateTransactionManagerNotUsed
}
out, err = g.node.SendSignedPayload(data, to)
if err != nil {
return nil, err
@ -57,9 +41,6 @@ func (g *PrivateTransactionManager) SendSignedTx(data []byte, to []string) (out
}
func (g *PrivateTransactionManager) Receive(data []byte) ([]byte, error) {
if g.isPrivateTransactionManagerNotInUse {
return nil, nil
}
if len(data) == 0 {
return data, nil
}
@ -101,20 +82,12 @@ func New(path string) (*PrivateTransactionManager, error) {
return nil, err
}
return &PrivateTransactionManager{
node: n,
c: cache.New(5*time.Minute, 5*time.Minute),
isPrivateTransactionManagerNotInUse: false,
node: n,
c: cache.NewDefaultCache(),
}, nil
}
func MustNew(path string) *PrivateTransactionManager {
if strings.EqualFold(path, "ignore") {
return &PrivateTransactionManager{
node: nil,
c: nil,
isPrivateTransactionManagerNotInUse: true,
}
}
g, err := New(path)
if err != nil {
panic(fmt.Sprintf("MustNew: Failed to connect to private transaction manager (%s): %v", path, err))

View File

@ -2,6 +2,7 @@ package raft
import (
"errors"
"github.com/coreos/etcd/pkg/types"
)
@ -124,11 +125,8 @@ func (s *PublicRaftAPI) checkIfNodeIsActive(raftId uint16) bool {
if raftId == s.raftService.raftProtocolManager.raftId {
return true
}
activeSince := s.raftService.raftProtocolManager.transport.ActiveSince(types.ID(raftId))
if activeSince.IsZero() {
return false
}
return true
activeSince := s.raftService.raftProtocolManager.transport.ActiveSince(types.ID(raftId))
return !activeSince.IsZero()
}
func (s *PublicRaftAPI) GetRaftId(enodeId string) (uint16, error) {

View File

@ -5,19 +5,19 @@ import (
)
const (
protocolName = "raft"
protocolVersion uint64 = 0x01
//protocolName = "raft"
//protocolVersion uint64 = 0x01
raftMsg = 0x00
//raftMsg = 0x00
minterRole = etcdRaft.LEADER
verifierRole = etcdRaft.NOT_LEADER
minterRole = etcdRaft.LEADER
//verifierRole = etcdRaft.NOT_LEADER
// Raft's ticker interval
tickerMS = 100
// We use a bounded channel of constant size buffering incoming messages
msgChanSize = 1000
//msgChanSize = 1000
// Snapshot after this many raft messages
//
@ -25,7 +25,7 @@ const (
//
snapshotPeriod = 250
peerUrlKeyPrefix = "peerUrl-"
//peerUrlKeyPrefix = "peerUrl-"
chainExtensionMessage = "Successfully extended chain"
)

View File

@ -870,7 +870,7 @@ func (pm *ProtocolManager) eventLoop() {
var block types.Block
err := rlp.DecodeBytes(entry.Data, &block)
if err != nil {
log.Error("error decoding block: ", err)
log.Error("error decoding block", "err", err)
}
if pm.blockchain.HasBlock(block.Hash(), block.NumberU64()) {

View File

@ -118,10 +118,7 @@ func writeAppliedIndex(workingDir string, node int, index uint64) error {
}()
buf := make([]byte, 8)
binary.LittleEndian.PutUint64(buf, index)
if err := db.Put(appliedDbKey, buf, noFsync); err != nil {
return err
}
return nil
return db.Put(appliedDbKey, buf, noFsync)
}
func mustNewNodeKey(t *testing.T) *ecdsa.PrivateKey {

View File

@ -429,8 +429,7 @@ func (minter *minter) buildExtraSeal(headerHash common.Hash) []byte {
//build the extraSeal struct
raftIdString := hexutil.EncodeUint64(uint64(minter.eth.raftProtocolManager.raftId))
var extra extraSeal
extra = extraSeal{
extra := extraSeal{
RaftId: []byte(raftIdString[2:]), //remove the 0x prefix
Signature: sig,
}

View File

@ -1,7 +1,6 @@
package raft
import (
"errors"
"fmt"
"math/big"
"strings"
@ -9,14 +8,13 @@ import (
"time"
"github.com/coreos/etcd/raft/raftpb"
"github.com/deckarep/golang-set"
"github.com/ethereum/go-ethereum/p2p/enode"
mapset "github.com/deckarep/golang-set"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/rlp"
)
@ -100,7 +98,7 @@ func TestAddLearner_whenTypical(t *testing.T) {
t.Errorf("2. wrong raft id. expected %d got %d\n", raftService.raftProtocolManager.raftId+1, uint16(confChange.NodeID))
}
case <-time.After(time.Millisecond * 200):
t.Errorf("add learner conf change not recieved")
t.Errorf("add learner conf change not received")
}
}
@ -123,7 +121,7 @@ func TestPromoteLearnerToPeer_whenTypical(t *testing.T) {
t.Errorf("2. wrong raft id. expected %d got %d\n", learnerRaftId, uint16(confChange.NodeID))
}
case <-time.After(time.Millisecond * 200):
t.Errorf("add learner conf change not recieved")
t.Errorf("add learner conf change not received")
}
}
@ -137,7 +135,7 @@ func TestAddLearnerOrPeer_fromLearner(t *testing.T) {
t.Errorf("learner should not be allowed to add learner or peer")
}
if err != nil && strings.Index(err.Error(), "learner node can't add peer or learner") == -1 {
if err != nil && !strings.Contains(err.Error(), "learner node can't add peer or learner") {
t.Errorf("expect error message: propose new peer failed, got: %v\n", err)
}
@ -147,7 +145,7 @@ func TestAddLearnerOrPeer_fromLearner(t *testing.T) {
t.Errorf("learner should not be allowed to add learner or peer")
}
if err != nil && strings.Index(err.Error(), "learner node can't add peer or learner") == -1 {
if err != nil && !strings.Contains(err.Error(), "learner node can't add peer or learner") {
t.Errorf("expect error message: propose new peer failed, got: %v\n", err)
}
@ -163,7 +161,7 @@ func TestPromoteLearnerToPeer_fromLearner(t *testing.T) {
t.Errorf("learner should not be allowed to promote to peer")
}
if err != nil && strings.Index(err.Error(), "learner node can't promote to peer") == -1 {
if err != nil && !strings.Contains(err.Error(), "learner node can't promote to peer") {
t.Errorf("expect error message: propose new peer failed, got: %v\n", err)
}
@ -177,7 +175,7 @@ func peerList(url string) (error, []*enode.Node) {
var nodes []*enode.Node
node, err := enode.ParseV4(url)
if err != nil {
return errors.New(fmt.Sprintf("Node URL %s: %v\n", url, err)), nil
return fmt.Errorf("Node URL %s: %v\n", url, err), nil
}
nodes = append(nodes, node)
return nil, nodes

View File

@ -22,7 +22,6 @@ import (
)
type InProcServerReadyEvent struct {
}
// DialInProc attaches an in-process connection to the given RPC server.