-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
312 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,270 @@ | ||
package trust | ||
|
||
import ( | ||
"math/big" | ||
"testing" | ||
|
||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/consensus/clique" | ||
"github.com/ethereum/go-ethereum/core" | ||
"github.com/ethereum/go-ethereum/core/rawdb" | ||
"github.com/ethereum/go-ethereum/core/types" | ||
"github.com/ethereum/go-ethereum/core/vm" | ||
"github.com/ethereum/go-ethereum/crypto" | ||
"github.com/ethereum/go-ethereum/ethdb" | ||
"github.com/ethereum/go-ethereum/p2p" | ||
"github.com/ethereum/go-ethereum/p2p/enode" | ||
"github.com/ethereum/go-ethereum/params" | ||
) | ||
|
||
var ( | ||
// testKey is a private key to use for funding a tester account. | ||
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | ||
|
||
// testAddr is the Ethereum address of the tester account. | ||
testAddr = crypto.PubkeyToAddress(testKey.PublicKey) | ||
) | ||
|
||
// testBackend is a mock implementation of the live Ethereum message handler. Its | ||
// purpose is to allow testing the request/reply workflows and wire serialization | ||
// in the `eth` protocol without actually doing any data processing. | ||
type testBackend struct { | ||
db ethdb.Database | ||
chain *core.BlockChain | ||
txpool *core.TxPool | ||
} | ||
|
||
// newTestBackend creates an empty chain and wraps it into a mock backend. | ||
func newTestBackend(blocks int) *testBackend { | ||
return newTestBackendWithGenerator(blocks) | ||
} | ||
|
||
// newTestBackend creates a chain with a number of explicitly defined blocks and | ||
// wraps it into a mock backend. | ||
func newTestBackendWithGenerator(blocks int) *testBackend { | ||
signer := types.HomesteadSigner{} | ||
db := rawdb.NewMemoryDatabase() | ||
engine := clique.New(params.AllCliqueProtocolChanges.Clique, db) | ||
genspec := &core.Genesis{ | ||
//Config: params.TestChainConfig, | ||
ExtraData: make([]byte, 32+common.AddressLength+65), | ||
Alloc: core.GenesisAlloc{testAddr: {Balance: big.NewInt(100000000000000000)}}, | ||
} | ||
copy(genspec.ExtraData[32:], testAddr[:]) | ||
genesis := genspec.MustCommit(db) | ||
|
||
chain, _ := core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil) | ||
generator := func(i int, block *core.BlockGen) { | ||
// The chain maker doesn't have access to a chain, so the difficulty will be | ||
// lets unset (nil). Set it here to the correct value. | ||
// block.SetCoinbase(testAddr) | ||
block.SetDifficulty(big.NewInt(2)) | ||
|
||
// We want to simulate an empty middle block, having the same state as the | ||
// first one. The last is needs a state change again to force a reorg. | ||
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), common.Address{0x01}, big.NewInt(1), params.TxGas, nil, nil), signer, testKey) | ||
if err != nil { | ||
panic(err) | ||
} | ||
block.AddTxWithChain(chain, tx) | ||
} | ||
|
||
bs, _ := core.GenerateChain(params.AllCliqueProtocolChanges, genesis, engine, db, blocks, generator) | ||
for i, block := range bs { | ||
header := block.Header() | ||
if i > 0 { | ||
header.ParentHash = bs[i-1].Hash() | ||
} | ||
header.Extra = make([]byte, 32+65) | ||
header.Difficulty = big.NewInt(2) | ||
|
||
sig, _ := crypto.Sign(clique.SealHash(header).Bytes(), testKey) | ||
copy(header.Extra[len(header.Extra)-65:], sig) | ||
bs[i] = block.WithSeal(header) | ||
} | ||
|
||
if _, err := chain.InsertChain(bs); err != nil { | ||
panic(err) | ||
} | ||
|
||
txconfig := core.DefaultTxPoolConfig | ||
txconfig.Journal = "" // Don't litter the disk with test journals | ||
|
||
return &testBackend{ | ||
db: db, | ||
chain: chain, | ||
txpool: core.NewTxPool(txconfig, params.AllCliqueProtocolChanges, chain), | ||
} | ||
} | ||
|
||
// close tears down the transaction pool and chain behind the mock backend. | ||
func (b *testBackend) close() { | ||
b.txpool.Stop() | ||
b.chain.Stop() | ||
} | ||
|
||
func (b *testBackend) Chain() *core.BlockChain { return b.chain } | ||
|
||
func (b *testBackend) RunPeer(peer *Peer, handler Handler) error { | ||
// Normally the backend would do peer mainentance and handshakes. All that | ||
// is omitted and we will just give control back to the handler. | ||
return handler(peer) | ||
} | ||
func (b *testBackend) PeerInfo(enode.ID) interface{} { panic("not implemented") } | ||
|
||
func (b *testBackend) Handle(*Peer, Packet) error { | ||
panic("data processing tests should be done in the handler package") | ||
} | ||
|
||
func TestRequestRoot(t *testing.T) { testRequestRoot(t, Trust1) } | ||
|
||
func testRequestRoot(t *testing.T, protocol uint) { | ||
t.Parallel() | ||
|
||
blockNum := 1032 // The latest 1024 blocks' DiffLayer will be cached. | ||
backend := newTestBackend(blockNum) | ||
defer backend.close() | ||
|
||
peer, _ := newTestPeer("peer", protocol, backend) | ||
defer peer.close() | ||
|
||
pairs := []struct { | ||
req RootRequestPacket | ||
res RootResponsePacket | ||
}{ | ||
{ | ||
req: RootRequestPacket{ | ||
RequestId: 1, | ||
BlockNumber: 1, | ||
}, | ||
res: RootResponsePacket{ | ||
RequestId: 1, | ||
Status: types.StatusPartiallyVerified, | ||
BlockNumber: 1, | ||
Extra: defaultExtra, | ||
}, | ||
}, | ||
{ | ||
req: RootRequestPacket{ | ||
RequestId: 2, | ||
BlockNumber: 128, | ||
}, | ||
res: RootResponsePacket{ | ||
RequestId: 2, | ||
Status: types.StatusFullVerified, | ||
BlockNumber: 128, | ||
Extra: defaultExtra, | ||
}, | ||
}, | ||
{ | ||
req: RootRequestPacket{ | ||
RequestId: 3, | ||
BlockNumber: 128, | ||
BlockHash: types.EmptyRootHash, | ||
DiffHash: types.EmptyRootHash, | ||
}, | ||
res: RootResponsePacket{ | ||
RequestId: 3, | ||
Status: types.StatusImpossibleFork, | ||
BlockNumber: 128, | ||
BlockHash: types.EmptyRootHash, | ||
Root: common.Hash{}, | ||
Extra: defaultExtra, | ||
}, | ||
}, | ||
{ | ||
req: RootRequestPacket{ | ||
RequestId: 4, | ||
BlockNumber: 128, | ||
DiffHash: types.EmptyRootHash, | ||
}, | ||
res: RootResponsePacket{ | ||
RequestId: 4, | ||
Status: types.StatusDiffHashMismatch, | ||
BlockNumber: 128, | ||
Root: common.Hash{}, | ||
Extra: defaultExtra, | ||
}, | ||
}, | ||
{ | ||
req: RootRequestPacket{ | ||
RequestId: 5, | ||
BlockNumber: 1024, | ||
}, | ||
res: RootResponsePacket{ | ||
RequestId: 5, | ||
Status: types.StatusFullVerified, | ||
BlockNumber: 1024, | ||
Extra: defaultExtra, | ||
}, | ||
}, | ||
{ | ||
req: RootRequestPacket{ | ||
RequestId: 6, | ||
BlockNumber: 1024, | ||
BlockHash: types.EmptyRootHash, | ||
DiffHash: types.EmptyRootHash, | ||
}, | ||
res: RootResponsePacket{ | ||
RequestId: 6, | ||
Status: types.StatusPossibleFork, | ||
BlockNumber: 1024, | ||
BlockHash: types.EmptyRootHash, | ||
Root: common.Hash{}, | ||
Extra: defaultExtra, | ||
}, | ||
}, | ||
{ | ||
req: RootRequestPacket{ | ||
RequestId: 7, | ||
BlockNumber: 1033, | ||
BlockHash: types.EmptyRootHash, | ||
DiffHash: types.EmptyRootHash, | ||
}, | ||
res: RootResponsePacket{ | ||
RequestId: 7, | ||
Status: types.StatusBlockNewer, | ||
BlockNumber: 1033, | ||
BlockHash: types.EmptyRootHash, | ||
Root: common.Hash{}, | ||
Extra: defaultExtra, | ||
}, | ||
}, | ||
{ | ||
req: RootRequestPacket{ | ||
RequestId: 8, | ||
BlockNumber: 1044, | ||
BlockHash: types.EmptyRootHash, | ||
DiffHash: types.EmptyRootHash, | ||
}, | ||
res: RootResponsePacket{ | ||
RequestId: 8, | ||
Status: types.StatusBlockTooNew, | ||
BlockNumber: 1044, | ||
BlockHash: types.EmptyRootHash, | ||
Root: common.Hash{}, | ||
Extra: defaultExtra, | ||
}, | ||
}, | ||
} | ||
|
||
for idx, pair := range pairs { | ||
header := backend.Chain().GetHeaderByNumber(pair.req.BlockNumber) | ||
if header != nil { | ||
if pair.res.Status.Code&0xFF00 == types.StatusVerified.Code { | ||
pair.req.BlockHash = header.Hash() | ||
pair.req.DiffHash, _ = core.CalculateDiffHash(backend.Chain().GetTrustedDiffLayer(header.Hash())) | ||
pair.res.BlockHash = pair.req.BlockHash | ||
pair.res.Root = header.Root | ||
} else if pair.res.Status.Code == types.StatusDiffHashMismatch.Code { | ||
pair.req.BlockHash = header.Hash() | ||
pair.res.BlockHash = pair.req.BlockHash | ||
} | ||
} | ||
|
||
p2p.Send(peer.app, RequestRootMsg, pair.req) | ||
if err := p2p.ExpectMsg(peer.app, RespondRootMsg, pair.res); err != nil { | ||
t.Errorf("test %d: root response not expected: %v", idx, err) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package trust | ||
|
||
import ( | ||
"math/rand" | ||
|
||
"github.com/ethereum/go-ethereum/p2p" | ||
"github.com/ethereum/go-ethereum/p2p/enode" | ||
) | ||
|
||
// testPeer is a simulated peer to allow testing direct network calls. | ||
type testPeer struct { | ||
*Peer | ||
|
||
net p2p.MsgReadWriter // Network layer reader/writer to simulate remote messaging | ||
app *p2p.MsgPipeRW // Application layer reader/writer to simulate the local side | ||
} | ||
|
||
// newTestPeer creates a new peer registered at the given data backend. | ||
func newTestPeer(name string, version uint, backend Backend) (*testPeer, <-chan error) { | ||
// Create a message pipe to communicate through | ||
app, net := p2p.MsgPipe() | ||
|
||
// Start the peer on a new thread | ||
var id enode.ID | ||
rand.Read(id[:]) | ||
|
||
peer := NewPeer(version, p2p.NewPeer(id, name, nil), net) | ||
errc := make(chan error, 1) | ||
go func() { | ||
errc <- backend.RunPeer(peer, func(peer *Peer) error { | ||
return Handle(backend, peer) | ||
}) | ||
}() | ||
return &testPeer{app: app, net: net, Peer: peer}, errc | ||
} | ||
|
||
// close terminates the local side of the peer, notifying the remote protocol | ||
// manager of termination. | ||
func (p *testPeer) close() { | ||
p.Peer.Close() | ||
p.app.Close() | ||
} |