mirror of https://github.com/poanetwork/quorum.git
merge 1.8.18 with quorum/master
refactor raft & istanbul based on upstream changes fix unit test cases
This commit is contained in:
parent
4dbd95947d
commit
73667e7942
185
.travis.yml
185
.travis.yml
|
@ -1,95 +1,108 @@
|
||||||
# simplifed version of the upstream travis configuration
|
# simplified version of the upstream travis configuration.
|
||||||
|
# automated acceptance test is run[in linux box] for raft, istanbul and clique consensus in parallel as part of every build
|
||||||
|
# unit test is run in linux and macOS boxes as part of every build
|
||||||
|
|
||||||
language: go
|
language: go
|
||||||
go_import_path: github.com/ethereum/go-ethereum
|
go_import_path: github.com/ethereum/go-ethereum
|
||||||
go: 1.9.x
|
sudo: false
|
||||||
sudo: true
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- /.*/ # everything including tags
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- BINTRAY_ORGANIZATION=quorumengineering
|
- TESSERA_JAR="$HOME/tessera.jar"
|
||||||
- BINTRAY_USER=quorumbot
|
|
||||||
# Bintray API Key
|
addons:
|
||||||
- secure: "QHiPcd3zQoJEsT3VSpxoLVTYwbiYzS8H18EpY7Tk0EqCIfswS2AvRlyRXUxNvCf9ktzpaeXV4b5cPYJ67dwdp5V/O/ARaK5AL6ZjjrTPR1avPnmz/X2VeQEP0aWk1UGMs1nBUj5rzMbIIxlVhpbiITTLAI4Ao0+xRcBi215mDbv271Z7mACEZfXxjaoJA0/3IkbKz9pu1nC7bTjaaExCDAeLp2p8fHi2YQPnBll/7dkn/m1rnsIY9M3KWNCx6xBmQOr1hulrrB6tZoHwFBoDsVTFJFLckPfrWUZsYUgtfWJMQWc6ntv1gFl0f9x6s5fYEphCU2m1JYjEczlQ03B5ro9EyPGKjO7vQxAaFd5nVd2Xf34ZbssEIyXxlSnP/4Gv1GXl9L9aU1Hth9ckYvT5gYP5t/Nw3CDbKD0HelPBvkf8jZwfdlotzFPS2bOZNdl/rJLWgQrX18a/mC3BH9l4TSRz13tbRfo6YcC3Y/uOvG1n4GxzcVaWojAxn86SkknOczPTf2pk9F3JOcGVSYA2R4kGQAe+ErJH2X5g2sh1D5cCYDjQyl5rzWg6P3eK//HYW+mg2+TQ8k2iQVVSwFwrR0Yn4P+5cRDCW9mjtktgq1rTtslj41gSH49Avqr9oXGM2rqdcJPdN8dnmLMrAtmeSUNMMoexiRMmlF2OQKLrW3k="
|
apt:
|
||||||
|
update: true
|
||||||
|
sources:
|
||||||
|
- sourceline: ppa:ethereum/ethereum
|
||||||
|
- sourceline: ppa:openjdk-r/ppa
|
||||||
|
packages:
|
||||||
|
- openjdk-8-jdk
|
||||||
|
- dpkg # fixes issue with dpkg-deb error due to travis image
|
||||||
|
- openssh-client
|
||||||
|
- dnsutils
|
||||||
|
- maven
|
||||||
|
- solc
|
||||||
|
- jq
|
||||||
|
- curl
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- if [ $TRAVIS_OS_NAME = linux ]; then git clone https://github.com/amalrajmani/quorum-acceptance-tests.git $TRAVIS_HOME/quorum-acceptance-tests; fi;
|
||||||
|
- if [ $TRAVIS_OS_NAME = linux ]; then sudo chmod 755 $TRAVIS_HOME/quorum-acceptance-tests/src/travis/install-linux.sh; fi;
|
||||||
|
- if [ $TRAVIS_OS_NAME = linux ]; then sudo chmod 755 $TRAVIS_HOME/quorum-acceptance-tests/src/travis/script-linux.sh; fi;
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- if: tag IS blank
|
- name: linux-raft
|
||||||
os: linux
|
os: linux
|
||||||
dist: xenial
|
dist: trusty
|
||||||
script:
|
sudo: true
|
||||||
- sudo modprobe fuse
|
go: 1.10.x
|
||||||
- sudo chmod 666 /dev/fuse
|
|
||||||
- sudo chown root:$USER /etc/fuse.conf
|
|
||||||
- go run build/ci.go install
|
|
||||||
- go run build/ci.go test -coverage $TEST_PACKAGES
|
|
||||||
- if: tag IS blank
|
|
||||||
os: osx
|
|
||||||
osx_image: xcode9.2 # so we don't have to deal with Kernel Extension Consent UI which is never possible in CI
|
|
||||||
script:
|
|
||||||
- brew update
|
|
||||||
- brew install caskroom/cask/brew-cask
|
|
||||||
- brew cask install osxfuse
|
|
||||||
- go run build/ci.go install
|
|
||||||
- go run build/ci.go test -coverage $TEST_PACKAGES
|
|
||||||
|
|
||||||
- if: tag IS present
|
cache:
|
||||||
os: linux
|
directories:
|
||||||
dist: xenial
|
- $HOME/.m2
|
||||||
env: OUTPUT_FILE=geth_${TRAVIS_TAG}_linux_amd64.tar.gz
|
|
||||||
script:
|
env:
|
||||||
- build/env.sh go run build/ci.go install ./cmd/geth
|
- TF_VAR_consensus_mechanism=raft
|
||||||
- sudo mkdir -p /dist
|
|
||||||
- cd build/bin
|
install: $TRAVIS_HOME/quorum-acceptance-tests/src/travis/install-linux.sh
|
||||||
- sudo tar cfvz /dist/${OUTPUT_FILE} geth
|
|
||||||
- if: tag IS present
|
script: $TRAVIS_HOME/quorum-acceptance-tests/src/travis/script-linux.sh
|
||||||
os: osx
|
|
||||||
osx_image: xcode9.2
|
|
||||||
env: OUTPUT_FILE=geth_${TRAVIS_TAG}_darwin_amd64.tar.gz
|
- name: linux-istanbul
|
||||||
script:
|
os: linux
|
||||||
- build/env.sh go run build/ci.go install ./cmd/geth
|
dist: trusty
|
||||||
- sudo mkdir -p /dist
|
sudo: true
|
||||||
- cd build/bin
|
go: 1.10.x
|
||||||
- sudo tar cfvz /dist/${OUTPUT_FILE} geth
|
|
||||||
|
directories:
|
||||||
|
- $HOME/.m2
|
||||||
|
|
||||||
|
env:
|
||||||
|
- TF_VAR_consensus_mechanism=istanbul
|
||||||
|
|
||||||
|
install: $TRAVIS_HOME/quorum-acceptance-tests/src/travis/install-linux.sh
|
||||||
|
|
||||||
|
script: $TRAVIS_HOME/quorum-acceptance-tests/src/travis/script-linux.sh
|
||||||
|
|
||||||
|
- name: linux-clique
|
||||||
|
os: linux
|
||||||
|
dist: trusty
|
||||||
|
sudo: true
|
||||||
|
go: 1.10.x
|
||||||
|
|
||||||
|
directories:
|
||||||
|
- $HOME/.m2
|
||||||
|
|
||||||
|
env:
|
||||||
|
- TF_VAR_consensus_mechanism=clique
|
||||||
|
|
||||||
|
install: $TRAVIS_HOME/quorum-acceptance-tests/src/travis/install-linux.sh
|
||||||
|
|
||||||
|
script: $TRAVIS_HOME/quorum-acceptance-tests/src/travis/script-linux.sh
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
dist: trusty
|
||||||
|
sudo: required
|
||||||
|
go: 1.10.x
|
||||||
|
script:
|
||||||
|
- sudo modprobe fuse
|
||||||
|
- sudo chmod 666 /dev/fuse
|
||||||
|
- sudo chown root:$USER /etc/fuse.conf
|
||||||
|
- go run build/ci.go install
|
||||||
|
- go run build/ci.go test -coverage $TEST_PACKAGES
|
||||||
|
|
||||||
|
|
||||||
|
- os: osx
|
||||||
|
osx_image: xcode9.2 # so we don't have to deal with Kernel Extension Consent UI which is never possible in CI
|
||||||
|
go: 1.10.x
|
||||||
|
sudo: required
|
||||||
|
script:
|
||||||
|
- brew update
|
||||||
|
- brew install caskroom/cask/brew-cask
|
||||||
|
- brew cask install osxfuse
|
||||||
|
- 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
|
|
|
@ -23,9 +23,10 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
testSource = `
|
testSource = `
|
||||||
|
pragma solidity ^0.5.0;
|
||||||
contract test {
|
contract test {
|
||||||
/// @notice Will multiply ` + "`a`" + ` by 7.
|
/// @notice Will multiply ` + "`a`" + ` by 7.
|
||||||
function multiply(uint a) returns(uint d) {
|
function multiply(uint a) public returns(uint d) {
|
||||||
return a * 7;
|
return a * 7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ func newBlockChain(n int) (*core.BlockChain, *backend) {
|
||||||
// Use the first key as private key
|
// Use the first key as private key
|
||||||
b, _ := New(config, nodeKeys[0], memDB).(*backend)
|
b, _ := New(config, nodeKeys[0], memDB).(*backend)
|
||||||
genesis.MustCommit(memDB)
|
genesis.MustCommit(memDB)
|
||||||
blockchain, err := core.NewBlockChain(memDB, nil, genesis.Config, b, vm.Config{})
|
blockchain, err := core.NewBlockChain(memDB, nil, genesis.Config, b, vm.Config{}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,7 @@ func makeHeader(parent *types.Block, config *istanbul.Config) *types.Header {
|
||||||
header := &types.Header{
|
header := &types.Header{
|
||||||
ParentHash: parent.Hash(),
|
ParentHash: parent.Hash(),
|
||||||
Number: parent.Number().Add(parent.Number(), common.Big1),
|
Number: parent.Number().Add(parent.Number(), common.Big1),
|
||||||
GasLimit: core.CalcGasLimit(parent),
|
GasLimit: core.CalcGasLimit(parent, parent.GasLimit(), parent.GasLimit()),
|
||||||
GasUsed: 0,
|
GasUsed: 0,
|
||||||
Extra: parent.Extra(),
|
Extra: parent.Extra(),
|
||||||
Time: new(big.Int).Add(parent.Time(), new(big.Int).SetUint64(config.BlockPeriod)),
|
Time: new(big.Int).Add(parent.Time(), new(big.Int).SetUint64(config.BlockPeriod)),
|
||||||
|
@ -131,8 +131,11 @@ func makeHeader(parent *types.Block, config *istanbul.Config) *types.Header {
|
||||||
|
|
||||||
func makeBlock(chain *core.BlockChain, engine *backend, parent *types.Block) *types.Block {
|
func makeBlock(chain *core.BlockChain, engine *backend, parent *types.Block) *types.Block {
|
||||||
block := makeBlockWithoutSeal(chain, engine, parent)
|
block := makeBlockWithoutSeal(chain, engine, parent)
|
||||||
block, _ = engine.Seal(chain, block, nil)
|
stopCh := make(chan struct{})
|
||||||
return block
|
resultCh := make(chan *types.Block, 10)
|
||||||
|
go engine.Seal(chain, block, resultCh, stopCh)
|
||||||
|
blk := <-resultCh
|
||||||
|
return blk
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeBlockWithoutSeal(chain *core.BlockChain, engine *backend, parent *types.Block) *types.Block {
|
func makeBlockWithoutSeal(chain *core.BlockChain, engine *backend, parent *types.Block) *types.Block {
|
||||||
|
@ -174,10 +177,15 @@ func TestSealStopChannel(t *testing.T) {
|
||||||
eventSub.Unsubscribe()
|
eventSub.Unsubscribe()
|
||||||
}
|
}
|
||||||
go eventLoop()
|
go eventLoop()
|
||||||
finalBlock, err := engine.Seal(chain, block, stop)
|
resultCh := make(chan *types.Block, 10)
|
||||||
if err != nil {
|
go func() {
|
||||||
t.Errorf("error mismatch: have %v, want nil", err)
|
err := engine.Seal(chain, block, resultCh, stop)
|
||||||
}
|
if err != nil {
|
||||||
|
t.Errorf("error mismatch: have %v, want nil", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
finalBlock := <-resultCh
|
||||||
if finalBlock != nil {
|
if finalBlock != nil {
|
||||||
t.Errorf("block mismatch: have %v, want nil", finalBlock)
|
t.Errorf("block mismatch: have %v, want nil", finalBlock)
|
||||||
}
|
}
|
||||||
|
@ -201,7 +209,7 @@ func TestSealCommittedOtherHash(t *testing.T) {
|
||||||
}
|
}
|
||||||
go eventLoop()
|
go eventLoop()
|
||||||
seal := func() {
|
seal := func() {
|
||||||
engine.Seal(chain, block, nil)
|
engine.Seal(chain, block, nil, make(chan struct{}))
|
||||||
t.Error("seal should not be completed")
|
t.Error("seal should not be completed")
|
||||||
}
|
}
|
||||||
go seal()
|
go seal()
|
||||||
|
@ -218,11 +226,16 @@ func TestSealCommitted(t *testing.T) {
|
||||||
chain, engine := newBlockChain(1)
|
chain, engine := newBlockChain(1)
|
||||||
block := makeBlockWithoutSeal(chain, engine, chain.Genesis())
|
block := makeBlockWithoutSeal(chain, engine, chain.Genesis())
|
||||||
expectedBlock, _ := engine.updateBlock(engine.chain.GetHeader(block.ParentHash(), block.NumberU64()-1), block)
|
expectedBlock, _ := engine.updateBlock(engine.chain.GetHeader(block.ParentHash(), block.NumberU64()-1), block)
|
||||||
|
resultCh := make(chan *types.Block, 10)
|
||||||
|
go func() {
|
||||||
|
err := engine.Seal(chain, block, resultCh, make(chan struct{}))
|
||||||
|
|
||||||
finalBlock, err := engine.Seal(chain, block, nil)
|
if err != nil {
|
||||||
if err != nil {
|
t.Errorf("error mismatch: have %v, want %v", err, expectedBlock)
|
||||||
t.Errorf("error mismatch: have %v, want nil", err)
|
}
|
||||||
}
|
}()
|
||||||
|
|
||||||
|
finalBlock := <-resultCh
|
||||||
if finalBlock.Hash() != expectedBlock.Hash() {
|
if finalBlock.Hash() != expectedBlock.Hash() {
|
||||||
t.Errorf("hash mismatch: have %v, want %v", finalBlock.Hash(), expectedBlock.Hash())
|
t.Errorf("hash mismatch: have %v, want %v", finalBlock.Hash(), expectedBlock.Hash())
|
||||||
}
|
}
|
||||||
|
|
|
@ -347,7 +347,7 @@ func TestVoting(t *testing.T) {
|
||||||
config.Epoch = tt.epoch
|
config.Epoch = tt.epoch
|
||||||
}
|
}
|
||||||
engine := New(config, accounts.accounts[tt.validators[0]], db).(*backend)
|
engine := New(config, accounts.accounts[tt.validators[0]], db).(*backend)
|
||||||
chain, err := core.NewBlockChain(db, nil, genesis.Config, engine, vm.Config{})
|
chain, err := core.NewBlockChain(db, nil, genesis.Config, engine, vm.Config{}, nil)
|
||||||
|
|
||||||
// Assemble a chain of headers from the cast votes
|
// Assemble a chain of headers from the cast votes
|
||||||
headers := make([]*types.Header, len(tt.votes))
|
headers := make([]*types.Header, len(tt.votes))
|
||||||
|
|
|
@ -156,6 +156,10 @@ func (self *testSystemBackend) ParentValidators(proposal istanbul.Proposal) ista
|
||||||
return self.peers
|
return self.peers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sb *testSystemBackend) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// ==============================================
|
// ==============================================
|
||||||
//
|
//
|
||||||
// define the struct that need to be provided for integration tests.
|
// define the struct that need to be provided for integration tests.
|
||||||
|
|
|
@ -103,8 +103,10 @@ func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *stat
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CalcGasLimit computes the gas limit of the next block after parent.
|
// CalcGasLimit computes the gas limit of the next block after parent. It aims
|
||||||
// This is miner strategy, not consensus protocol.
|
// to keep the baseline gas above the provided floor, and increase it towards the
|
||||||
|
// ceil if the blocks are full. If the ceil is exceeded, it will always decrease
|
||||||
|
// the gas allowance.
|
||||||
func CalcGasLimit(parent *types.Block, gasFloor, gasCeil uint64) uint64 {
|
func CalcGasLimit(parent *types.Block, gasFloor, gasCeil uint64) uint64 {
|
||||||
// contrib = (parentGasUsed * 3 / 2) / 4096
|
// contrib = (parentGasUsed * 3 / 2) / 4096
|
||||||
contrib := (parent.GasUsed() + parent.GasUsed()/2) / params.GasLimitBoundDivisor
|
contrib := (parent.GasUsed() + parent.GasUsed()/2) / params.GasLimitBoundDivisor
|
||||||
|
@ -123,8 +125,7 @@ func CalcGasLimit(parent *types.Block, gasFloor, gasCeil uint64) uint64 {
|
||||||
if limit < params.MinGasLimit {
|
if limit < params.MinGasLimit {
|
||||||
limit = params.MinGasLimit
|
limit = params.MinGasLimit
|
||||||
}
|
}
|
||||||
// however, if we're now below the target (TargetGasLimit) we increase the
|
// If we're outside our allowed gas range, we try to hone towards them
|
||||||
// limit as much as we can (parentGasLimit / 4096 -1)
|
|
||||||
if limit < gasFloor {
|
if limit < gasFloor {
|
||||||
limit = parent.GasLimit() + decay
|
limit = parent.GasLimit() + decay
|
||||||
if limit > gasFloor {
|
if limit > gasFloor {
|
||||||
|
|
|
@ -117,25 +117,70 @@ func gasReturnDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *
|
||||||
|
|
||||||
func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
var (
|
var (
|
||||||
db = getDualState(evm, contract.Address())
|
db = getDualState(evm, contract.Address())
|
||||||
y, x = stack.Back(1), stack.Back(0)
|
y, x = stack.Back(1), stack.Back(0)
|
||||||
val = db.GetState(contract.Address(), common.BigToHash(x))
|
current = db.GetState(contract.Address(), common.BigToHash(x))
|
||||||
)
|
)
|
||||||
// This checks for 3 scenario's and calculates gas accordingly
|
// The legacy gas metering only takes into consideration the current state
|
||||||
// 1. From a zero-value address to a non-zero value (NEW VALUE)
|
if !evm.chainRules.IsConstantinople {
|
||||||
// 2. From a non-zero value address to a zero-value address (DELETE)
|
// This checks for 3 scenario's and calculates gas accordingly:
|
||||||
// 3. From a non-zero to a non-zero (CHANGE)
|
//
|
||||||
if val == (common.Hash{}) && y.Sign() != 0 {
|
// 1. From a zero-value address to a non-zero value (NEW VALUE)
|
||||||
// 0 => non 0
|
// 2. From a non-zero value address to a zero-value address (DELETE)
|
||||||
return params.SstoreSetGas, nil
|
// 3. From a non-zero to a non-zero (CHANGE)
|
||||||
} else if val != (common.Hash{}) && y.Sign() == 0 {
|
switch {
|
||||||
// non 0 => 0
|
case current == (common.Hash{}) && y.Sign() != 0: // 0 => non 0
|
||||||
db.AddRefund(params.SstoreRefundGas)
|
return params.SstoreSetGas, nil
|
||||||
return params.SstoreClearGas, nil
|
case current != (common.Hash{}) && y.Sign() == 0: // non 0 => 0
|
||||||
} else {
|
evm.StateDB.AddRefund(params.SstoreRefundGas)
|
||||||
// non 0 => non 0 (or 0 => 0)
|
return params.SstoreClearGas, nil
|
||||||
return params.SstoreResetGas, nil
|
default: // non 0 => non 0 (or 0 => 0)
|
||||||
|
return params.SstoreResetGas, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// The new gas metering is based on net gas costs (EIP-1283):
|
||||||
|
//
|
||||||
|
// 1. If current value equals new value (this is a no-op), 200 gas is deducted.
|
||||||
|
// 2. If current value does not equal new value
|
||||||
|
// 2.1. If original value equals current value (this storage slot has not been changed by the current execution context)
|
||||||
|
// 2.1.1. If original value is 0, 20000 gas is deducted.
|
||||||
|
// 2.1.2. Otherwise, 5000 gas is deducted. If new value is 0, add 15000 gas to refund counter.
|
||||||
|
// 2.2. If original value does not equal current value (this storage slot is dirty), 200 gas is deducted. Apply both of the following clauses.
|
||||||
|
// 2.2.1. If original value is not 0
|
||||||
|
// 2.2.1.1. If current value is 0 (also means that new value is not 0), remove 15000 gas from refund counter. We can prove that refund counter will never go below 0.
|
||||||
|
// 2.2.1.2. If new value is 0 (also means that current value is not 0), add 15000 gas to refund counter.
|
||||||
|
// 2.2.2. If original value equals new value (this storage slot is reset)
|
||||||
|
// 2.2.2.1. If original value is 0, add 19800 gas to refund counter.
|
||||||
|
// 2.2.2.2. Otherwise, add 4800 gas to refund counter.
|
||||||
|
value := common.BigToHash(y)
|
||||||
|
if current == value { // noop (1)
|
||||||
|
return params.NetSstoreNoopGas, nil
|
||||||
|
}
|
||||||
|
original := evm.StateDB.GetCommittedState(contract.Address(), common.BigToHash(x))
|
||||||
|
if original == current {
|
||||||
|
if original == (common.Hash{}) { // create slot (2.1.1)
|
||||||
|
return params.NetSstoreInitGas, nil
|
||||||
|
}
|
||||||
|
if value == (common.Hash{}) { // delete slot (2.1.2b)
|
||||||
|
evm.StateDB.AddRefund(params.NetSstoreClearRefund)
|
||||||
|
}
|
||||||
|
return params.NetSstoreCleanGas, nil // write existing slot (2.1.2)
|
||||||
|
}
|
||||||
|
if original != (common.Hash{}) {
|
||||||
|
if current == (common.Hash{}) { // recreate slot (2.2.1.1)
|
||||||
|
evm.StateDB.SubRefund(params.NetSstoreClearRefund)
|
||||||
|
} else if value == (common.Hash{}) { // delete slot (2.2.1.2)
|
||||||
|
evm.StateDB.AddRefund(params.NetSstoreClearRefund)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if original == value {
|
||||||
|
if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1)
|
||||||
|
evm.StateDB.AddRefund(params.NetSstoreResetClearRefund)
|
||||||
|
} else { // reset to original existing slot (2.2.2.2)
|
||||||
|
evm.StateDB.AddRefund(params.NetSstoreResetRefund)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return params.NetSstoreDirtyGas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeGasLog(n uint64) gasFunc {
|
func makeGasLog(n uint64) gasFunc {
|
||||||
|
|
|
@ -494,7 +494,7 @@ func BenchmarkOpMstore(bench *testing.B) {
|
||||||
|
|
||||||
func BenchmarkOpSHA3(bench *testing.B) {
|
func BenchmarkOpSHA3(bench *testing.B) {
|
||||||
var (
|
var (
|
||||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
env = NewEVM(Context{}, nil, nil, params.TestChainConfig, Config{})
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
mem = NewMemory()
|
mem = NewMemory()
|
||||||
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
||||||
|
|
|
@ -26,6 +26,7 @@ import (
|
||||||
|
|
||||||
// Quorum uses a cut-down StateDB, MinimalApiState. We leave the methods in StateDB commented out so they'll produce a
|
// Quorum uses a cut-down StateDB, MinimalApiState. We leave the methods in StateDB commented out so they'll produce a
|
||||||
// conflict when upstream changes.
|
// conflict when upstream changes.
|
||||||
|
//TODO(Amal): to be reviewed
|
||||||
type MinimalApiState interface {
|
type MinimalApiState interface {
|
||||||
GetBalance(addr common.Address) *big.Int
|
GetBalance(addr common.Address) *big.Int
|
||||||
GetCode(addr common.Address) []byte
|
GetCode(addr common.Address) []byte
|
||||||
|
|
|
@ -50,7 +50,8 @@ func (*dummyStatedb) GetRefund() uint64 { return 1337 }
|
||||||
|
|
||||||
func TestStoreCapture(t *testing.T) {
|
func TestStoreCapture(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
env = NewEVM(Context{}, &dummyStatedb{}, nil, params.TestChainConfig, Config{})
|
db = &dummyStatedb{}
|
||||||
|
env = NewEVM(Context{}, db, db, params.TestChainConfig, Config{})
|
||||||
logger = NewStructLogger(nil)
|
logger = NewStructLogger(nil)
|
||||||
mem = NewMemory()
|
mem = NewMemory()
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
|
|
|
@ -288,7 +288,7 @@ func (s EthAPIState) GetNonce(addr common.Address) uint64 {
|
||||||
return s.state.GetNonce(addr)
|
return s.state.GetNonce(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement the following methods for Quorum
|
// TODO(Amal): implement the following methods for Quorum
|
||||||
func (s EthAPIState) GetProof(common.Address) ([][]byte, error) {
|
func (s EthAPIState) GetProof(common.Address) ([][]byte, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -562,7 +562,7 @@ func testBroadcastBlock(t *testing.T, totalPeers, broadcastExpected int) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create new blockchain: %v", err)
|
t.Fatalf("failed to create new blockchain: %v", err)
|
||||||
}
|
}
|
||||||
pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db)
|
pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to start test protocol manager: %v", err)
|
t.Fatalf("failed to start test protocol manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,8 @@ type dummyStatedb struct {
|
||||||
func (*dummyStatedb) GetRefund() uint64 { return 1337 }
|
func (*dummyStatedb) GetRefund() uint64 { return 1337 }
|
||||||
|
|
||||||
func runTrace(tracer *Tracer) (json.RawMessage, error) {
|
func runTrace(tracer *Tracer) (json.RawMessage, error) {
|
||||||
env := vm.NewEVM(vm.Context{BlockNumber: big.NewInt(1)}, &dummyStatedb{}, nil, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer})
|
db := &dummyStatedb{}
|
||||||
|
env := vm.NewEVM(vm.Context{BlockNumber: big.NewInt(1)}, db, db, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer})
|
||||||
|
|
||||||
contract := vm.NewContract(account{}, account{}, big.NewInt(0), 10000)
|
contract := vm.NewContract(account{}, account{}, big.NewInt(0), 10000)
|
||||||
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0}
|
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0}
|
||||||
|
@ -132,8 +133,8 @@ func TestHaltBetweenSteps(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
db := &dummyStatedb{}
|
||||||
env := vm.NewEVM(vm.Context{BlockNumber: big.NewInt(1)}, &dummyStatedb{}, nil, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer})
|
env := vm.NewEVM(vm.Context{BlockNumber: big.NewInt(1)}, db, db, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer})
|
||||||
contract := vm.NewContract(&account{}, &account{}, big.NewInt(0), 0)
|
contract := vm.NewContract(&account{}, &account{}, big.NewInt(0), 0)
|
||||||
|
|
||||||
tracer.CaptureState(env, 0, 0, 0, 0, nil, nil, contract, 0, nil)
|
tracer.CaptureState(env, 0, 0, 0, 0, nil, nil, contract, 0, nil)
|
||||||
|
|
|
@ -124,6 +124,7 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *testWorkerBackend) ChainDb() ethdb.Database { return b.db }
|
||||||
func (b *testWorkerBackend) BlockChain() *core.BlockChain { return b.chain }
|
func (b *testWorkerBackend) BlockChain() *core.BlockChain { return b.chain }
|
||||||
func (b *testWorkerBackend) TxPool() *core.TxPool { return b.txPool }
|
func (b *testWorkerBackend) TxPool() *core.TxPool { return b.txPool }
|
||||||
func (b *testWorkerBackend) PostChainEvents(events []interface{}) {
|
func (b *testWorkerBackend) PostChainEvents(events []interface{}) {
|
||||||
|
@ -153,7 +154,7 @@ func testPendingStateAndBlock(t *testing.T, chainConfig *params.ChainConfig, eng
|
||||||
|
|
||||||
// Ensure snapshot has been updated.
|
// Ensure snapshot has been updated.
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
block, state := w.pending()
|
block, state, _ := w.pending()
|
||||||
if block.NumberU64() != 1 {
|
if block.NumberU64() != 1 {
|
||||||
t.Errorf("block number mismatch: have %d, want %d", block.NumberU64(), 1)
|
t.Errorf("block number mismatch: have %d, want %d", block.NumberU64(), 1)
|
||||||
}
|
}
|
||||||
|
@ -164,7 +165,7 @@ func testPendingStateAndBlock(t *testing.T, chainConfig *params.ChainConfig, eng
|
||||||
|
|
||||||
// Ensure the new tx events has been processed
|
// Ensure the new tx events has been processed
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
block, state = w.pending()
|
block, state, _ = w.pending()
|
||||||
if balance := state.GetBalance(testUserAddress); balance.Cmp(big.NewInt(2000)) != 0 {
|
if balance := state.GetBalance(testUserAddress); balance.Cmp(big.NewInt(2000)) != 0 {
|
||||||
t.Errorf("account balance mismatch: have %d, want %d", balance, 2000)
|
t.Errorf("account balance mismatch: have %d, want %d", balance, 2000)
|
||||||
}
|
}
|
||||||
|
|
|
@ -368,9 +368,7 @@ func (c *Config) parsePersistentNodes(path string) []*enode.Node {
|
||||||
if url == "" {
|
if url == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
log.Info("AJ-parsePersistentNodes1", "url", url)
|
|
||||||
node, err := enode.ParseV4(url)
|
node, err := enode.ParseV4(url)
|
||||||
log.Info("AJ-parsePersistentNodes2", "url", url, "ID", node.ID().String(), "EnodeID", node.EnodeID())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(fmt.Sprintf("Node URL %s: %v\n", url, err))
|
log.Error(fmt.Sprintf("Node URL %s: %v\n", url, err))
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -86,7 +86,8 @@ func (V4ID) NodeAddr(r *enr.Record) []byte {
|
||||||
buf := make([]byte, 64)
|
buf := make([]byte, 64)
|
||||||
math.ReadBits(pubkey.X, buf[:32])
|
math.ReadBits(pubkey.X, buf[:32])
|
||||||
math.ReadBits(pubkey.Y, buf[32:])
|
math.ReadBits(pubkey.Y, buf[32:])
|
||||||
return crypto.Keccak256(buf)
|
b := crypto.Keccak256(buf)
|
||||||
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// Secp256k1 is the "secp256k1" key, which holds a public key.
|
// Secp256k1 is the "secp256k1" key, which holds a public key.
|
||||||
|
|
|
@ -82,6 +82,7 @@ func (n *Node) UDP() int {
|
||||||
return int(port)
|
return int(port)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: Amal to review
|
||||||
// RAFTPORT returns the RAFT PORT of the node
|
// RAFTPORT returns the RAFT PORT of the node
|
||||||
func (n *Node) RAFTPORT() int {
|
func (n *Node) RAFTPORT() int {
|
||||||
var port enr.RAFTPORT
|
var port enr.RAFTPORT
|
||||||
|
@ -194,6 +195,34 @@ func (n *ID) UnmarshalText(text []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ID is a unique identifier for each node used by RAFT
|
||||||
|
type EnodeID [64]byte
|
||||||
|
|
||||||
|
// ID prints as a long hexadecimal number.
|
||||||
|
func (n EnodeID) String() string {
|
||||||
|
return fmt.Sprintf("%x", n[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Go syntax representation of a ID is a call to HexID.
|
||||||
|
func (n EnodeID) GoString() string {
|
||||||
|
return fmt.Sprintf("enode.HexID(\"%x\")", n[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText implements the encoding.TextMarshaler interface.
|
||||||
|
func (n EnodeID) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(hex.EncodeToString(n[:])), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||||
|
func (n *EnodeID) UnmarshalText(text []byte) error {
|
||||||
|
id, err := RaftHexID(string(text))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*n = id
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// HexID converts a hex string to an ID.
|
// HexID converts a hex string to an ID.
|
||||||
// The string may be prefixed with 0x.
|
// The string may be prefixed with 0x.
|
||||||
// It panics if the string is not a valid ID.
|
// It panics if the string is not a valid ID.
|
||||||
|
@ -205,6 +234,20 @@ func HexID(in string) ID {
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO(Amal): to review
|
||||||
|
func RaftHexID(in string) (EnodeID, error) {
|
||||||
|
var id EnodeID
|
||||||
|
b, err := hex.DecodeString(strings.TrimPrefix(in, "0x"))
|
||||||
|
if err != nil {
|
||||||
|
return id, err
|
||||||
|
} else if len(b) != len(id) {
|
||||||
|
return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2)
|
||||||
|
}
|
||||||
|
|
||||||
|
copy(id[:], b)
|
||||||
|
return id, nil
|
||||||
|
}
|
||||||
|
|
||||||
func parseID(in string) (ID, error) {
|
func parseID(in string) (ID, error) {
|
||||||
var id ID
|
var id ID
|
||||||
b, err := hex.DecodeString(strings.TrimPrefix(in, "0x"))
|
b, err := hex.DecodeString(strings.TrimPrefix(in, "0x"))
|
||||||
|
|
|
@ -28,7 +28,6 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
"github.com/ethereum/go-ethereum/p2p/enr"
|
"github.com/ethereum/go-ethereum/p2p/enr"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -93,7 +92,7 @@ func NewV4(pubkey *ecdsa.PublicKey, ip net.IP, tcp, udp, raftPort int) *Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
if raftPort != 0 {
|
if raftPort != 0 {
|
||||||
r.Set(enr.RAFTPORT(tcp))
|
r.Set(enr.RAFTPORT(raftPort))
|
||||||
}
|
}
|
||||||
|
|
||||||
signV4Compat(&r, pubkey)
|
signV4Compat(&r, pubkey)
|
||||||
|
@ -101,7 +100,6 @@ func NewV4(pubkey *ecdsa.PublicKey, ip net.IP, tcp, udp, raftPort int) *Node {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
log.Info("NewV4", "raftPort", raftPort, "nodeId", n.ID().String(), "NodeId.bytes", n.ID().Bytes())
|
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,11 +120,9 @@ func parseComplete(rawurl string) (*Node, error) {
|
||||||
if u.User == nil {
|
if u.User == nil {
|
||||||
return nil, errors.New("does not contain node ID")
|
return nil, errors.New("does not contain node ID")
|
||||||
}
|
}
|
||||||
log.Info("AJ-parseComplete1", "u.User", u.User.String())
|
|
||||||
if id, err = parsePubkey(u.User.String()); err != nil {
|
if id, err = parsePubkey(u.User.String()); err != nil {
|
||||||
return nil, fmt.Errorf("invalid node ID (%v)", err)
|
return nil, fmt.Errorf("invalid node ID (%v)", err)
|
||||||
}
|
}
|
||||||
log.Info("AJ-parseComplete2", "id", id)
|
|
||||||
// Parse the IP address.
|
// Parse the IP address.
|
||||||
host, port, err := net.SplitHostPort(u.Host)
|
host, port, err := net.SplitHostPort(u.Host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -187,7 +183,7 @@ func parsePubkey(in string) (*ecdsa.PublicKey, error) {
|
||||||
return crypto.UnmarshalPubkey(b)
|
return crypto.UnmarshalPubkey(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Amal to review it - added for RAFT
|
// TODO(Amal): to review it - added for RAFT
|
||||||
func (n *Node) EnodeID() string {
|
func (n *Node) EnodeID() string {
|
||||||
var (
|
var (
|
||||||
scheme enr.ID
|
scheme enr.ID
|
||||||
|
@ -215,10 +211,8 @@ func (n *Node) v4URL() string {
|
||||||
n.Load((*Secp256k1)(&key))
|
n.Load((*Secp256k1)(&key))
|
||||||
switch {
|
switch {
|
||||||
case scheme == "v4" || key != ecdsa.PublicKey{}:
|
case scheme == "v4" || key != ecdsa.PublicKey{}:
|
||||||
log.Info("AJ-schemeV4")
|
|
||||||
nodeid = fmt.Sprintf("%x", crypto.FromECDSAPub(&key)[1:])
|
nodeid = fmt.Sprintf("%x", crypto.FromECDSAPub(&key)[1:])
|
||||||
default:
|
default:
|
||||||
log.Info("AJ-NOT schemeV4")
|
|
||||||
nodeid = fmt.Sprintf("%s.%x", scheme, n.id[:])
|
nodeid = fmt.Sprintf("%s.%x", scheme, n.id[:])
|
||||||
}
|
}
|
||||||
u := url.URL{Scheme: "enode"}
|
u := url.URL{Scheme: "enode"}
|
||||||
|
|
|
@ -40,7 +40,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -121,7 +120,6 @@ func (r *Record) Load(e Entry) error {
|
||||||
if err := rlp.DecodeBytes(r.pairs[i].v, e); err != nil {
|
if err := rlp.DecodeBytes(r.pairs[i].v, e); err != nil {
|
||||||
return &KeyError{Key: e.ENRKey(), Err: err}
|
return &KeyError{Key: e.ENRKey(), Err: err}
|
||||||
}
|
}
|
||||||
log.Info("AJ-Load", "key", e.ENRKey(), "value", r.pairs[i].v)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return &KeyError{Key: e.ENRKey(), Err: errNotFound}
|
return &KeyError{Key: e.ENRKey(), Err: errNotFound}
|
||||||
|
|
|
@ -925,8 +925,6 @@ func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *enode.Node) erro
|
||||||
} else {
|
} else {
|
||||||
c.node = nodeFromConn(remotePubkey, c.fd)
|
c.node = nodeFromConn(remotePubkey, c.fd)
|
||||||
}
|
}
|
||||||
log.Info("AJ-setupConn1", "remotePubkey", remotePubkey)
|
|
||||||
log.Info("AJ-setupConn2", "c.node.ID", c.node.ID(), "c.node.ID.Bytes", c.node.ID().Bytes(), "node", c.node.String())
|
|
||||||
clog := srv.log.New("id", c.node.ID(), "addr", c.fd.RemoteAddr(), "conn", c.flags)
|
clog := srv.log.New("id", c.node.ID(), "addr", c.fd.RemoteAddr(), "conn", c.flags)
|
||||||
|
|
||||||
//START - QUORUM Permissioning
|
//START - QUORUM Permissioning
|
||||||
|
|
|
@ -131,16 +131,16 @@ var (
|
||||||
//
|
//
|
||||||
// This configuration is intentionally not using keyed fields to force anyone
|
// This configuration is intentionally not using keyed fields to force anyone
|
||||||
// adding flags to the config to also have to set these fields.
|
// adding flags to the config to also have to set these fields.
|
||||||
AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil, nil, false}
|
AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, nil, false}
|
||||||
|
|
||||||
// AllCliqueProtocolChanges contains every protocol change (EIPs) introduced
|
// AllCliqueProtocolChanges contains every protocol change (EIPs) introduced
|
||||||
// and accepted by the Ethereum core developers into the Clique consensus.
|
// and accepted by the Ethereum core developers into the Clique consensus.
|
||||||
//
|
//
|
||||||
// This configuration is intentionally not using keyed fields to force anyone
|
// This configuration is intentionally not using keyed fields to force anyone
|
||||||
// adding flags to the config to also have to set these fields.
|
// adding flags to the config to also have to set these fields.
|
||||||
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}, nil, false}
|
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}, nil, false}
|
||||||
|
|
||||||
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil, nil, false}
|
TestChainConfig = &ChainConfig{big.NewInt(10), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, nil, false}
|
||||||
TestRules = TestChainConfig.Rules(new(big.Int))
|
TestRules = TestChainConfig.Rules(new(big.Int))
|
||||||
|
|
||||||
QuorumTestChainConfig = &ChainConfig{big.NewInt(10), big.NewInt(0), nil, false, nil, common.Hash{}, nil, nil, nil, nil, nil, new(EthashConfig), nil, nil, true}
|
QuorumTestChainConfig = &ChainConfig{big.NewInt(10), big.NewInt(0), nil, false, nil, common.Hash{}, nil, nil, nil, nil, nil, new(EthashConfig), nil, nil, true}
|
||||||
|
|
|
@ -31,6 +31,7 @@ func (s *PublicRaftAPI) RemovePeer(raftId uint16) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *PublicRaftAPI) Leader() (string, error) {
|
func (s *PublicRaftAPI) Leader() (string, error) {
|
||||||
|
|
||||||
addr, err := s.raftService.raftProtocolManager.LeaderAddress()
|
addr, err := s.raftService.raftProtocolManager.LeaderAddress()
|
||||||
if nil != err {
|
if nil != err {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
|
@ -23,17 +23,16 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
|
||||||
"crypto/ecdsa"
|
|
||||||
"github.com/coreos/etcd/etcdserver/stats"
|
"github.com/coreos/etcd/etcdserver/stats"
|
||||||
raftTypes "github.com/coreos/etcd/pkg/types"
|
raftTypes "github.com/coreos/etcd/pkg/types"
|
||||||
etcdRaft "github.com/coreos/etcd/raft"
|
etcdRaft "github.com/coreos/etcd/raft"
|
||||||
"github.com/coreos/etcd/raft/raftpb"
|
"github.com/coreos/etcd/raft/raftpb"
|
||||||
"github.com/coreos/etcd/rafthttp"
|
"github.com/coreos/etcd/rafthttp"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
|
||||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
"github.com/ethereum/go-ethereum/p2p/enr"
|
"github.com/ethereum/go-ethereum/p2p/enr"
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
"gopkg.in/fatih/set.v0"
|
|
||||||
|
"github.com/deckarep/golang-set"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ProtocolManager struct {
|
type ProtocolManager struct {
|
||||||
|
@ -56,7 +55,7 @@ type ProtocolManager struct {
|
||||||
// Remote peer state (protected by mu vs concurrent access via JS)
|
// Remote peer state (protected by mu vs concurrent access via JS)
|
||||||
leader uint16
|
leader uint16
|
||||||
peers map[uint16]*Peer
|
peers map[uint16]*Peer
|
||||||
removedPeers *set.Set // *Permanently removed* peers
|
removedPeers mapset.Set // *Permanently removed* peers
|
||||||
|
|
||||||
// P2P transport
|
// P2P transport
|
||||||
p2pServer *p2p.Server // Initialized in start()
|
p2pServer *p2p.Server // Initialized in start()
|
||||||
|
@ -107,7 +106,7 @@ func NewProtocolManager(raftId uint16, raftPort uint16, blockchain *core.BlockCh
|
||||||
bootstrapNodes: bootstrapNodes,
|
bootstrapNodes: bootstrapNodes,
|
||||||
peers: make(map[uint16]*Peer),
|
peers: make(map[uint16]*Peer),
|
||||||
leader: uint16(etcdRaft.None),
|
leader: uint16(etcdRaft.None),
|
||||||
removedPeers: set.New(set.ThreadSafe).(*set.Set),
|
removedPeers: mapset.NewSet(),
|
||||||
joinExisting: joinExisting,
|
joinExisting: joinExisting,
|
||||||
blockchain: blockchain,
|
blockchain: blockchain,
|
||||||
eventMux: mux,
|
eventMux: mux,
|
||||||
|
@ -201,10 +200,12 @@ func (pm *ProtocolManager) NodeInfo() *RaftNodeInfo {
|
||||||
peerIdx += 1
|
peerIdx += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
removedPeerIfaces := pm.removedPeers.List()
|
removedPeerIfaces := pm.removedPeers
|
||||||
removedPeerIds := make([]uint16, len(removedPeerIfaces))
|
removedPeerIds := make([]uint16, removedPeerIfaces.Cardinality())
|
||||||
for i, removedIface := range removedPeerIfaces {
|
i := 0
|
||||||
|
for removedIface := range removedPeerIfaces.Iterator().C {
|
||||||
removedPeerIds[i] = removedIface.(uint16)
|
removedPeerIds[i] = removedIface.(uint16)
|
||||||
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -247,8 +248,8 @@ func (pm *ProtocolManager) nextRaftId() uint16 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removedPeerIfaces := pm.removedPeers.List()
|
removedPeerIfaces := pm.removedPeers
|
||||||
for _, removedIface := range removedPeerIfaces {
|
for removedIface := range removedPeerIfaces.Iterator().C {
|
||||||
removedId := removedIface.(uint16)
|
removedId := removedIface.(uint16)
|
||||||
|
|
||||||
if maxId < removedId {
|
if maxId < removedId {
|
||||||
|
@ -263,7 +264,7 @@ func (pm *ProtocolManager) isRaftIdRemoved(id uint16) bool {
|
||||||
pm.mu.RLock()
|
pm.mu.RLock()
|
||||||
defer pm.mu.RUnlock()
|
defer pm.mu.RUnlock()
|
||||||
|
|
||||||
return pm.removedPeers.Has(id)
|
return pm.removedPeers.Contains(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *ProtocolManager) isRaftIdUsed(raftId uint16) bool {
|
func (pm *ProtocolManager) isRaftIdUsed(raftId uint16) bool {
|
||||||
|
@ -286,14 +287,14 @@ func (pm *ProtocolManager) isNodeAlreadyInCluster(node *enode.Node) error {
|
||||||
peerNode := peer.p2pNode
|
peerNode := peer.p2pNode
|
||||||
|
|
||||||
if peerNode.ID() == node.ID() {
|
if peerNode.ID() == node.ID() {
|
||||||
return fmt.Errorf("node with this enode has already been added to the cluster: %v", node.ID)
|
return fmt.Errorf("node with this enode has already been added to the cluster: %s", node.ID())
|
||||||
}
|
}
|
||||||
|
|
||||||
if peerNode.IP().Equal(node.IP()) {
|
if peerNode.IP().Equal(node.IP()) {
|
||||||
if peerNode.TCP() == node.TCP() {
|
if peerNode.TCP() == node.TCP() {
|
||||||
return fmt.Errorf("existing node %v with raft ID %v is already using eth p2p at %v:%v", peerNode.ID, peerRaftId, node.IP, node.TCP)
|
return fmt.Errorf("existing node %v with raft ID %v is already using eth p2p at %v:%v", peerNode.ID(), peerRaftId, node.IP(), node.TCP())
|
||||||
} else if peer.address.RaftPort == enr.RAFTPORT(node.RAFTPORT()) {
|
} else if peer.address.RaftPort == enr.RAFTPORT(node.RAFTPORT()) {
|
||||||
return fmt.Errorf("existing node %v with raft ID %v is already using raft at %v:%v", peerNode.ID, peerRaftId, node.IP, node.RAFTPORT())
|
return fmt.Errorf("existing node %v with raft ID %v is already using raft at %v:%v", peerNode.ID(), peerRaftId, node.IP(), node.RAFTPORT())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -641,31 +642,21 @@ func raftUrl(address *Address) string {
|
||||||
return fmt.Sprintf("http://%s:%d", address.Ip, address.RaftPort)
|
return fmt.Sprintf("http://%s:%d", address.Ip, address.RaftPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodePubkey64(b []byte) (*ecdsa.PublicKey, error) {
|
|
||||||
return crypto.UnmarshalPubkey(append([]byte{0x04}, b...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pm *ProtocolManager) addPeer(address *Address) {
|
func (pm *ProtocolManager) addPeer(address *Address) {
|
||||||
pm.mu.Lock()
|
pm.mu.Lock()
|
||||||
defer pm.mu.Unlock()
|
defer pm.mu.Unlock()
|
||||||
|
|
||||||
raftId := address.RaftId
|
raftId := address.RaftId
|
||||||
|
|
||||||
log.Info("AJ-addPeer:", "raftId", raftId, "nodeId", address.NodeId.String(), "bytes", address.NodeId.Bytes(), "address", address)
|
//TODO(Amal): to review
|
||||||
|
pubKey, err := enode.HexPubkey(address.NodeId.String())
|
||||||
//TODO: Amal to confirm if this decoding is correct
|
if err != nil {
|
||||||
//pubKey, err := decodePubkey64(address.NodeId.Bytes())
|
log.Error("error decoding pub key from enodeId", "enodeId", address.NodeId.String(), "err", err)
|
||||||
|
panic(err)
|
||||||
/*if err != nil {
|
}
|
||||||
log.Error("AJ-error decoding pub key", "nodeId", address.NodeId.String(), "err", err)
|
|
||||||
return
|
|
||||||
}*/
|
|
||||||
|
|
||||||
log.Info("addPeer: decoded pub key", "pubKey", address.PubKey)
|
|
||||||
|
|
||||||
// Add P2P connection:
|
// Add P2P connection:
|
||||||
p2pNode := enode.NewV4(address.PubKey, address.Ip, 0, int(address.P2pPort), 0)
|
p2pNode := enode.NewV4(pubKey, address.Ip, 0, int(address.P2pPort), int(address.RaftPort))
|
||||||
log.Info("AJ-p2pNode", "ID1", address.NodeId.String(), "ID2", p2pNode.ID().String())
|
|
||||||
pm.p2pServer.AddPeer(p2pNode)
|
pm.p2pServer.AddPeer(p2pNode)
|
||||||
|
|
||||||
// Add raft transport connection:
|
// Add raft transport connection:
|
||||||
|
@ -858,7 +849,6 @@ func (pm *ProtocolManager) makeInitialRaftPeers() (raftPeers []etcdRaft.Peer, pe
|
||||||
// requiring the use of static peers for the initial set, and load them from e.g. another JSON file which
|
// requiring the use of static peers for the initial set, and load them from e.g. another JSON file which
|
||||||
// contains pairs of enodes and raft ports, or we can get this initial peer list from commandline flags.
|
// contains pairs of enodes and raft ports, or we can get this initial peer list from commandline flags.
|
||||||
address := newAddress(raftId, node.RAFTPORT(), node)
|
address := newAddress(raftId, node.RAFTPORT(), node)
|
||||||
|
|
||||||
raftPeers[i] = etcdRaft.Peer{
|
raftPeers[i] = etcdRaft.Peer{
|
||||||
ID: uint64(raftId),
|
ID: uint64(raftId),
|
||||||
Context: address.toBytes(),
|
Context: address.toBytes(),
|
||||||
|
|
31
raft/peer.go
31
raft/peer.go
|
@ -5,38 +5,35 @@ import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
|
|
||||||
"crypto/ecdsa"
|
|
||||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
"github.com/ethereum/go-ethereum/p2p/enr"
|
"github.com/ethereum/go-ethereum/p2p/enr"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const nodeIDBits = 512
|
|
||||||
|
|
||||||
type EnodeID [nodeIDBits / 8]byte
|
|
||||||
|
|
||||||
// Serializable information about a Peer. Sufficient to build `etcdRaft.Peer`
|
// Serializable information about a Peer. Sufficient to build `etcdRaft.Peer`
|
||||||
// or `discover.Node`.
|
// or `discover.Node`.
|
||||||
type Address struct {
|
type Address struct {
|
||||||
RaftId uint16 `json:"raftId"`
|
RaftId uint16 `json:"raftId"`
|
||||||
NodeId [64]byte `json:"nodeId"`
|
NodeId enode.EnodeID `json:"nodeId"`
|
||||||
Ip net.IP `json:"ip"`
|
Ip net.IP `json:"ip"`
|
||||||
P2pPort enr.TCP `json:"p2pPort"`
|
P2pPort enr.TCP `json:"p2pPort"`
|
||||||
RaftPort enr.RAFTPORT `json:"raftPort"`
|
RaftPort enr.RAFTPORT `json:"raftPort"`
|
||||||
PubKey *ecdsa.PublicKey
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(Amal): to review
|
||||||
|
|
||||||
func newAddress(raftId uint16, raftPort int, node *enode.Node) *Address {
|
func newAddress(raftId uint16, raftPort int, node *enode.Node) *Address {
|
||||||
node.ID().Bytes()
|
id, err := enode.RaftHexID(node.EnodeID())
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
return &Address{
|
return &Address{
|
||||||
RaftId: raftId,
|
RaftId: raftId,
|
||||||
NodeId: []byte(node.EnodeID()),
|
NodeId: id,
|
||||||
Ip: node.IP(),
|
Ip: node.IP(),
|
||||||
P2pPort: enr.TCP(node.TCP()),
|
P2pPort: enr.TCP(node.TCP()),
|
||||||
RaftPort: enr.RAFTPORT(raftPort),
|
RaftPort: enr.RAFTPORT(raftPort),
|
||||||
PubKey: node.Pubkey(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +51,7 @@ func (addr *Address) DecodeRLP(s *rlp.Stream) error {
|
||||||
// These fields need to be public:
|
// These fields need to be public:
|
||||||
var temp struct {
|
var temp struct {
|
||||||
RaftId uint16
|
RaftId uint16
|
||||||
NodeId enode.ID
|
NodeId enode.EnodeID
|
||||||
Ip net.IP
|
Ip net.IP
|
||||||
P2pPort enr.TCP
|
P2pPort enr.TCP
|
||||||
RaftPort enr.RAFTPORT
|
RaftPort enr.RAFTPORT
|
||||||
|
|
|
@ -10,12 +10,12 @@ import (
|
||||||
"github.com/coreos/etcd/raft/raftpb"
|
"github.com/coreos/etcd/raft/raftpb"
|
||||||
"github.com/coreos/etcd/snap"
|
"github.com/coreos/etcd/snap"
|
||||||
"github.com/coreos/etcd/wal/walpb"
|
"github.com/coreos/etcd/wal/walpb"
|
||||||
|
"github.com/deckarep/golang-set"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"gopkg.in/fatih/set.v0"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Snapshot
|
// Snapshot
|
||||||
|
@ -37,9 +37,7 @@ func (pm *ProtocolManager) buildSnapshot() *Snapshot {
|
||||||
defer pm.mu.RUnlock()
|
defer pm.mu.RUnlock()
|
||||||
|
|
||||||
numNodes := len(pm.confState.Nodes)
|
numNodes := len(pm.confState.Nodes)
|
||||||
log.Info("AJ-numNodes", "nodesSize", numNodes, "nodes", pm.confState.Nodes)
|
numRemovedNodes := pm.removedPeers.Cardinality()
|
||||||
log.Info("AJ-peers", "pm.peers", pm.peers)
|
|
||||||
numRemovedNodes := pm.removedPeers.Size()
|
|
||||||
|
|
||||||
snapshot := &Snapshot{
|
snapshot := &Snapshot{
|
||||||
addresses: make([]Address, numNodes),
|
addresses: make([]Address, numNodes),
|
||||||
|
@ -61,9 +59,10 @@ func (pm *ProtocolManager) buildSnapshot() *Snapshot {
|
||||||
sort.Sort(ByRaftId(snapshot.addresses))
|
sort.Sort(ByRaftId(snapshot.addresses))
|
||||||
|
|
||||||
// Populate removed IDs
|
// Populate removed IDs
|
||||||
|
i := 0
|
||||||
for i, removedIface := range pm.removedPeers.List() {
|
for removedIface := range pm.removedPeers.Iterator().C {
|
||||||
snapshot.removedRaftIds[i] = removedIface.(uint16)
|
snapshot.removedRaftIds[i] = removedIface.(uint16)
|
||||||
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
return snapshot
|
return snapshot
|
||||||
|
@ -101,8 +100,8 @@ func (pm *ProtocolManager) triggerSnapshot(index uint64) {
|
||||||
pm.mu.Unlock()
|
pm.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func confStateIdSet(confState raftpb.ConfState) *set.Set {
|
func confStateIdSet(confState raftpb.ConfState) mapset.Set {
|
||||||
set := set.New(set.ThreadSafe).(*set.Set)
|
set := mapset.NewSet()
|
||||||
for _, rawRaftId := range confState.Nodes {
|
for _, rawRaftId := range confState.Nodes {
|
||||||
set.Add(uint16(rawRaftId))
|
set.Add(uint16(rawRaftId))
|
||||||
}
|
}
|
||||||
|
@ -117,7 +116,7 @@ func (pm *ProtocolManager) updateClusterMembership(newConfState raftpb.ConfState
|
||||||
// Update tombstones for permanently removed peers. For simplicity we do not
|
// Update tombstones for permanently removed peers. For simplicity we do not
|
||||||
// allow the re-use of peer IDs once a peer is removed.
|
// allow the re-use of peer IDs once a peer is removed.
|
||||||
|
|
||||||
removedPeers := set.New(set.ThreadSafe).(*set.Set)
|
removedPeers := mapset.NewSet()
|
||||||
for _, removedRaftId := range removedRaftIds {
|
for _, removedRaftId := range removedRaftIds {
|
||||||
removedPeers.Add(removedRaftId)
|
removedPeers.Add(removedRaftId)
|
||||||
}
|
}
|
||||||
|
@ -129,8 +128,8 @@ func (pm *ProtocolManager) updateClusterMembership(newConfState raftpb.ConfState
|
||||||
|
|
||||||
prevIds := confStateIdSet(prevConfState)
|
prevIds := confStateIdSet(prevConfState)
|
||||||
newIds := confStateIdSet(newConfState)
|
newIds := confStateIdSet(newConfState)
|
||||||
idsToRemove := set.Difference(prevIds, newIds)
|
idsToRemove := prevIds.Difference(newIds)
|
||||||
for _, idIfaceToRemove := range idsToRemove.List() {
|
for idIfaceToRemove := range idsToRemove.Iterator().C {
|
||||||
raftId := idIfaceToRemove.(uint16)
|
raftId := idIfaceToRemove.(uint16)
|
||||||
log.Info("removing old raft peer", "peer id", raftId)
|
log.Info("removing old raft peer", "peer id", raftId)
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,8 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
|
||||||
"gopkg.in/fatih/set.v0"
|
"github.com/deckarep/golang-set"
|
||||||
lane "gopkg.in/oleiade/lane.v1"
|
"gopkg.in/oleiade/lane.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The speculative chain represents blocks that we have minted which haven't been accepted into the chain yet, building
|
// The speculative chain represents blocks that we have minted which haven't been accepted into the chain yet, building
|
||||||
|
@ -21,16 +21,16 @@ import (
|
||||||
type speculativeChain struct {
|
type speculativeChain struct {
|
||||||
head *types.Block
|
head *types.Block
|
||||||
unappliedBlocks *lane.Deque
|
unappliedBlocks *lane.Deque
|
||||||
expectedInvalidBlockHashes *set.Set // This is thread-safe. This set is referred to as our "guard" below.
|
expectedInvalidBlockHashes mapset.Set // This is thread-safe. This set is referred to as our "guard" below.
|
||||||
proposedTxes *set.Set // This is thread-safe.
|
proposedTxes mapset.Set // This is thread-safe.
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSpeculativeChain() *speculativeChain {
|
func newSpeculativeChain() *speculativeChain {
|
||||||
return &speculativeChain{
|
return &speculativeChain{
|
||||||
head: nil,
|
head: nil,
|
||||||
unappliedBlocks: lane.NewDeque(),
|
unappliedBlocks: lane.NewDeque(),
|
||||||
expectedInvalidBlockHashes: set.New(set.ThreadSafe).(*set.Set),
|
expectedInvalidBlockHashes: mapset.NewSet(),
|
||||||
proposedTxes: set.New(set.ThreadSafe).(*set.Set),
|
proposedTxes: mapset.NewSet(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ func (chain *speculativeChain) unwindFrom(invalidHash common.Hash, headBlock *ty
|
||||||
|
|
||||||
// check our "guard" to see if this is a (descendant) block we're
|
// check our "guard" to see if this is a (descendant) block we're
|
||||||
// expected to be ruled invalid. if we find it, remove from the guard
|
// expected to be ruled invalid. if we find it, remove from the guard
|
||||||
if chain.expectedInvalidBlockHashes.Has(invalidHash) {
|
if chain.expectedInvalidBlockHashes.Contains(invalidHash) {
|
||||||
log.Info("Removing expected-invalid block from guard.", "block", invalidHash)
|
log.Info("Removing expected-invalid block from guard.", "block", invalidHash)
|
||||||
|
|
||||||
chain.expectedInvalidBlockHashes.Remove(invalidHash)
|
chain.expectedInvalidBlockHashes.Remove(invalidHash)
|
||||||
|
@ -140,7 +140,9 @@ func (chain *speculativeChain) recordProposedTransactions(txes types.Transaction
|
||||||
for i, tx := range txes {
|
for i, tx := range txes {
|
||||||
txHashIs[i] = tx.Hash()
|
txHashIs[i] = tx.Hash()
|
||||||
}
|
}
|
||||||
chain.proposedTxes.Add(txHashIs...)
|
for _, i := range txHashIs {
|
||||||
|
chain.proposedTxes.Add(i)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes txes in block from our "blacklist" of "proposed tx" hashes. When we
|
// Removes txes in block from our "blacklist" of "proposed tx" hashes. When we
|
||||||
|
@ -161,7 +163,9 @@ func (chain *speculativeChain) removeProposedTxes(block *types.Block) {
|
||||||
// here and in mintNewBlock concurrently. using a finer-grained set-specific
|
// here and in mintNewBlock concurrently. using a finer-grained set-specific
|
||||||
// lock here is preferable, because mintNewBlock holds its locks for a
|
// lock here is preferable, because mintNewBlock holds its locks for a
|
||||||
// nontrivial amount of time.
|
// nontrivial amount of time.
|
||||||
chain.proposedTxes.Remove(minedTxInterfaces...)
|
for _, i := range minedTxInterfaces {
|
||||||
|
chain.proposedTxes.Remove(i)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (chain *speculativeChain) withoutProposedTxes(addrTxes AddressTxes) AddressTxes {
|
func (chain *speculativeChain) withoutProposedTxes(addrTxes AddressTxes) AddressTxes {
|
||||||
|
@ -170,7 +174,7 @@ func (chain *speculativeChain) withoutProposedTxes(addrTxes AddressTxes) Address
|
||||||
for addr, txes := range addrTxes {
|
for addr, txes := range addrTxes {
|
||||||
filteredTxes := make(types.Transactions, 0)
|
filteredTxes := make(types.Transactions, 0)
|
||||||
for _, tx := range txes {
|
for _, tx := range txes {
|
||||||
if !chain.proposedTxes.Has(tx.Hash()) {
|
if !chain.proposedTxes.Contains(tx.Hash()) {
|
||||||
filteredTxes = append(filteredTxes, tx)
|
filteredTxes = append(filteredTxes, tx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue