Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
7f00e8c0
Commit
7f00e8c0
authored
Jul 08, 2016
by
Péter Szilágyi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
core, eth: enforce network split post DAO hard-fork
parent
a87089fd
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
141 additions
and
7 deletions
+141
-7
block_validator.go
core/block_validator.go
+7
-0
handler.go
eth/handler.go
+55
-3
handler_test.go
eth/handler_test.go
+73
-0
peer.go
eth/peer.go
+6
-4
No files found.
core/block_validator.go
View file @
7f00e8c0
...
@@ -248,6 +248,13 @@ func ValidateHeader(config *ChainConfig, pow pow.PoW, header *types.Header, pare
...
@@ -248,6 +248,13 @@ func ValidateHeader(config *ChainConfig, pow pow.PoW, header *types.Header, pare
return
&
BlockNonceErr
{
header
.
Number
,
header
.
Hash
(),
header
.
Nonce
.
Uint64
()}
return
&
BlockNonceErr
{
header
.
Number
,
header
.
Hash
(),
header
.
Nonce
.
Uint64
()}
}
}
}
}
// If all checks passed, validate the extra-data field for hard forks
return
ValidateHeaderExtraData
(
config
,
header
)
}
// ValidateHeaderExtraData validates the extra-data field of a block header to
// ensure it conforms to hard-fork rules.
func
ValidateHeaderExtraData
(
config
*
ChainConfig
,
header
*
types
.
Header
)
error
{
// DAO hard-fork extension to the header validity: a) if the node is no-fork,
// DAO hard-fork extension to the header validity: a) if the node is no-fork,
// do not accept blocks in the [fork, fork+10) range with the fork specific
// do not accept blocks in the [fork, fork+10) range with the fork specific
// extra-data set; b) if the node is pro-fork, require blocks in the specific
// extra-data set; b) if the node is pro-fork, require blocks in the specific
...
...
eth/handler.go
View file @
7f00e8c0
...
@@ -45,6 +45,10 @@ const (
...
@@ -45,6 +45,10 @@ const (
estHeaderRlpSize
=
500
// Approximate size of an RLP encoded block header
estHeaderRlpSize
=
500
// Approximate size of an RLP encoded block header
)
)
var
(
daoChallengeTimeout
=
15
*
time
.
Second
// Time allowance for a node to reply to the DAO handshake challenge
)
// errIncompatibleConfig is returned if the requested protocols and configs are
// errIncompatibleConfig is returned if the requested protocols and configs are
// not compatible (low protocol version restrictions and high requirements).
// not compatible (low protocol version restrictions and high requirements).
var
errIncompatibleConfig
=
errors
.
New
(
"incompatible configuration"
)
var
errIncompatibleConfig
=
errors
.
New
(
"incompatible configuration"
)
...
@@ -62,9 +66,10 @@ type ProtocolManager struct {
...
@@ -62,9 +66,10 @@ type ProtocolManager struct {
fastSync
uint32
// Flag whether fast sync is enabled (gets disabled if we already have blocks)
fastSync
uint32
// Flag whether fast sync is enabled (gets disabled if we already have blocks)
synced
uint32
// Flag whether we're considered synchronised (enables transaction processing)
synced
uint32
// Flag whether we're considered synchronised (enables transaction processing)
txpool
txPool
txpool
txPool
blockchain
*
core
.
BlockChain
blockchain
*
core
.
BlockChain
chaindb
ethdb
.
Database
chaindb
ethdb
.
Database
chainconfig
*
core
.
ChainConfig
downloader
*
downloader
.
Downloader
downloader
*
downloader
.
Downloader
fetcher
*
fetcher
.
Fetcher
fetcher
*
fetcher
.
Fetcher
...
@@ -99,6 +104,7 @@ func NewProtocolManager(config *core.ChainConfig, fastSync bool, networkId int,
...
@@ -99,6 +104,7 @@ func NewProtocolManager(config *core.ChainConfig, fastSync bool, networkId int,
txpool
:
txpool
,
txpool
:
txpool
,
blockchain
:
blockchain
,
blockchain
:
blockchain
,
chaindb
:
chaindb
,
chaindb
:
chaindb
,
chainconfig
:
config
,
peers
:
newPeerSet
(),
peers
:
newPeerSet
(),
newPeerCh
:
make
(
chan
*
peer
),
newPeerCh
:
make
(
chan
*
peer
),
noMorePeers
:
make
(
chan
struct
{}),
noMorePeers
:
make
(
chan
struct
{}),
...
@@ -278,6 +284,18 @@ func (pm *ProtocolManager) handle(p *peer) error {
...
@@ -278,6 +284,18 @@ func (pm *ProtocolManager) handle(p *peer) error {
// after this will be sent via broadcasts.
// after this will be sent via broadcasts.
pm
.
syncTransactions
(
p
)
pm
.
syncTransactions
(
p
)
// If we're DAO hard-fork aware, validate any remote peer with regard to the hard-fork
if
daoBlock
:=
pm
.
chainconfig
.
DAOForkBlock
;
daoBlock
!=
nil
{
// Request the peer's DAO fork header for extra-data validation
if
err
:=
p
.
RequestHeadersByNumber
(
daoBlock
.
Uint64
(),
1
,
0
,
false
);
err
!=
nil
{
return
err
}
// Start a timer to disconnect if the peer doesn't reply in time
p
.
forkDrop
=
time
.
AfterFunc
(
daoChallengeTimeout
,
func
()
{
glog
.
V
(
logger
.
Warn
)
.
Infof
(
"%v: timed out DAO fork-check, dropping"
,
p
)
pm
.
removePeer
(
p
.
id
)
})
}
// main loop. handle incoming messages.
// main loop. handle incoming messages.
for
{
for
{
if
err
:=
pm
.
handleMsg
(
p
);
err
!=
nil
{
if
err
:=
pm
.
handleMsg
(
p
);
err
!=
nil
{
...
@@ -481,9 +499,43 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
...
@@ -481,9 +499,43 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
if
err
:=
msg
.
Decode
(
&
headers
);
err
!=
nil
{
if
err
:=
msg
.
Decode
(
&
headers
);
err
!=
nil
{
return
errResp
(
ErrDecode
,
"msg %v: %v"
,
msg
,
err
)
return
errResp
(
ErrDecode
,
"msg %v: %v"
,
msg
,
err
)
}
}
// If no headers were received, but we're expending a DAO fork check, maybe it's that
if
len
(
headers
)
==
0
&&
p
.
forkDrop
!=
nil
{
// Possibly an empty reply to the fork header checks, sanity check TDs
verifyDAO
:=
true
// If we already have a DAO header, we can check the peer's TD against it. If
// the peer's ahead of this, it too must have a reply to the DAO check
if
daoHeader
:=
pm
.
blockchain
.
GetHeaderByNumber
(
pm
.
chainconfig
.
DAOForkBlock
.
Uint64
());
daoHeader
!=
nil
{
if
p
.
Td
()
.
Cmp
(
pm
.
blockchain
.
GetTd
(
daoHeader
.
Hash
(),
daoHeader
.
Number
.
Uint64
()))
>=
0
{
verifyDAO
=
false
}
}
// If we're seemingly on the same chain, disable the drop timer
if
verifyDAO
{
glog
.
V
(
logger
.
Info
)
.
Infof
(
"%v: seems to be on the same side of the DAO fork"
,
p
)
p
.
forkDrop
.
Stop
()
p
.
forkDrop
=
nil
return
nil
}
}
// Filter out any explicitly requested headers, deliver the rest to the downloader
// Filter out any explicitly requested headers, deliver the rest to the downloader
filter
:=
len
(
headers
)
==
1
filter
:=
len
(
headers
)
==
1
if
filter
{
if
filter
{
// If it's a potential DAO fork check, validate against the rules
if
p
.
forkDrop
!=
nil
&&
pm
.
chainconfig
.
DAOForkBlock
.
Cmp
(
headers
[
0
]
.
Number
)
==
0
{
// Disable the fork drop timer
p
.
forkDrop
.
Stop
()
p
.
forkDrop
=
nil
// Validate the header and either drop the peer or continue
if
err
:=
core
.
ValidateHeaderExtraData
(
pm
.
chainconfig
,
headers
[
0
]);
err
!=
nil
{
glog
.
V
(
logger
.
Info
)
.
Infof
(
"%v: verified to be on the other side of the DAO fork, dropping"
,
p
)
return
err
}
glog
.
V
(
logger
.
Info
)
.
Infof
(
"%v: verified to be on the same side of the DAO fork"
,
p
)
}
// Irrelevant of the fork checks, send the header to the fetcher just in case
headers
=
pm
.
fetcher
.
FilterHeaders
(
headers
,
time
.
Now
())
headers
=
pm
.
fetcher
.
FilterHeaders
(
headers
,
time
.
Now
())
}
}
if
len
(
headers
)
>
0
||
!
filter
{
if
len
(
headers
)
>
0
||
!
filter
{
...
...
eth/handler_test.go
View file @
7f00e8c0
...
@@ -20,6 +20,7 @@ import (
...
@@ -20,6 +20,7 @@ import (
"math/big"
"math/big"
"math/rand"
"math/rand"
"testing"
"testing"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core"
...
@@ -28,6 +29,7 @@ import (
...
@@ -28,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/params"
)
)
...
@@ -580,3 +582,74 @@ func testGetReceipt(t *testing.T, protocol int) {
...
@@ -580,3 +582,74 @@ func testGetReceipt(t *testing.T, protocol int) {
t
.
Errorf
(
"receipts mismatch: %v"
,
err
)
t
.
Errorf
(
"receipts mismatch: %v"
,
err
)
}
}
}
}
// Tests that post eth protocol handshake, DAO fork-enabled clients also execute
// a DAO "challenge" verifying each others' DAO fork headers to ensure they're on
// compatible chains.
func
TestDAOChallengeNoVsNo
(
t
*
testing
.
T
)
{
testDAOChallenge
(
t
,
false
,
false
,
false
)
}
func
TestDAOChallengeNoVsPro
(
t
*
testing
.
T
)
{
testDAOChallenge
(
t
,
false
,
true
,
false
)
}
func
TestDAOChallengeProVsNo
(
t
*
testing
.
T
)
{
testDAOChallenge
(
t
,
true
,
false
,
false
)
}
func
TestDAOChallengeProVsPro
(
t
*
testing
.
T
)
{
testDAOChallenge
(
t
,
true
,
true
,
false
)
}
func
TestDAOChallengeNoVsTimeout
(
t
*
testing
.
T
)
{
testDAOChallenge
(
t
,
false
,
false
,
true
)
}
func
TestDAOChallengeProVsTimeout
(
t
*
testing
.
T
)
{
testDAOChallenge
(
t
,
true
,
true
,
true
)
}
func
testDAOChallenge
(
t
*
testing
.
T
,
localForked
,
remoteForked
bool
,
timeout
bool
)
{
// Reduce the DAO handshake challenge timeout
if
timeout
{
defer
func
(
old
time
.
Duration
)
{
daoChallengeTimeout
=
old
}(
daoChallengeTimeout
)
daoChallengeTimeout
=
500
*
time
.
Millisecond
}
// Create a DAO aware protocol manager
var
(
evmux
=
new
(
event
.
TypeMux
)
pow
=
new
(
core
.
FakePow
)
db
,
_
=
ethdb
.
NewMemDatabase
()
genesis
=
core
.
WriteGenesisBlockForTesting
(
db
)
config
=
&
core
.
ChainConfig
{
DAOForkBlock
:
big
.
NewInt
(
1
),
DAOForkSupport
:
localForked
}
blockchain
,
_
=
core
.
NewBlockChain
(
db
,
config
,
pow
,
evmux
)
)
pm
,
err
:=
NewProtocolManager
(
config
,
false
,
NetworkId
,
evmux
,
new
(
testTxPool
),
pow
,
blockchain
,
db
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to start test protocol manager: %v"
,
err
)
}
pm
.
Start
()
defer
pm
.
Stop
()
// Connect a new peer and check that we receive the DAO challenge
peer
,
_
:=
newTestPeer
(
"peer"
,
eth63
,
pm
,
true
)
defer
peer
.
close
()
challenge
:=
&
getBlockHeadersData
{
Origin
:
hashOrNumber
{
Number
:
config
.
DAOForkBlock
.
Uint64
()},
Amount
:
1
,
Skip
:
0
,
Reverse
:
false
,
}
if
err
:=
p2p
.
ExpectMsg
(
peer
.
app
,
GetBlockHeadersMsg
,
challenge
);
err
!=
nil
{
t
.
Fatalf
(
"challenge mismatch: %v"
,
err
)
}
// Create a block to reply to the challenge if no timeout is simualted
if
!
timeout
{
blocks
,
_
:=
core
.
GenerateChain
(
genesis
,
db
,
1
,
func
(
i
int
,
block
*
core
.
BlockGen
)
{
if
remoteForked
{
block
.
SetExtra
(
params
.
DAOForkBlockExtra
)
}
})
if
err
:=
p2p
.
Send
(
peer
.
app
,
BlockHeadersMsg
,
[]
*
types
.
Header
{
blocks
[
0
]
.
Header
()});
err
!=
nil
{
t
.
Fatalf
(
"failed to answer challenge: %v"
,
err
)
}
}
else
{
// Otherwise wait until the test timeout passes
time
.
Sleep
(
daoChallengeTimeout
+
500
*
time
.
Millisecond
)
}
// Verify that depending on fork side, the remote peer is maintained or dropped
if
localForked
==
remoteForked
&&
!
timeout
{
if
peers
:=
pm
.
peers
.
Len
();
peers
!=
1
{
t
.
Fatalf
(
"peer count mismatch: have %d, want %d"
,
peers
,
1
)
}
}
else
{
if
peers
:=
pm
.
peers
.
Len
();
peers
!=
0
{
t
.
Fatalf
(
"peer count mismatch: have %d, want %d"
,
peers
,
0
)
}
}
}
eth/peer.go
View file @
7f00e8c0
...
@@ -59,10 +59,12 @@ type peer struct {
...
@@ -59,10 +59,12 @@ type peer struct {
*
p2p
.
Peer
*
p2p
.
Peer
rw
p2p
.
MsgReadWriter
rw
p2p
.
MsgReadWriter
version
int
// Protocol version negotiated
version
int
// Protocol version negotiated
head
common
.
Hash
forkDrop
*
time
.
Timer
// Timed connection dropper if forks aren't validated in time
td
*
big
.
Int
lock
sync
.
RWMutex
head
common
.
Hash
td
*
big
.
Int
lock
sync
.
RWMutex
knownTxs
*
set
.
Set
// Set of transaction hashes known to be known by this peer
knownTxs
*
set
.
Set
// Set of transaction hashes known to be known by this peer
knownBlocks
*
set
.
Set
// Set of block hashes known to be known by this peer
knownBlocks
*
set
.
Set
// Set of block hashes known to be known by this peer
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment