merge 1.8.18 with quorum/master

refactor raft & istanbul based on upstream changes
fix unit test cases
This commit is contained in:
amalraj.manigmail.com 2019-02-08 17:29:01 +08:00
parent 4dbd95947d
commit 73667e7942
26 changed files with 323 additions and 219 deletions

View File

@ -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

View File

@ -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;
} }
} }

View File

@ -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())
} }

View File

@ -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))

View File

@ -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.

View File

@ -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 {

View File

@ -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 {

View File

@ -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)

View File

@ -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

View File

@ -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()

View File

@ -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
} }

View File

@ -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)
} }

View File

@ -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)

View File

@ -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)
} }

View File

@ -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

View File

@ -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.

View File

@ -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"))

View File

@ -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"}

View File

@ -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}

View File

@ -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

View File

@ -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}

View File

@ -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

View File

@ -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(),

View File

@ -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

View File

@ -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)

View File

@ -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)
} }
} }