| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- // Copyright 2018 The go-ethereum Authors
- // This file is part of the go-ethereum library.
- //
- // The go-ethereum library is free software: you can redistribute it and/or modify
- // it under the terms of the GNU Lesser General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // The go-ethereum library is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU Lesser General Public License for more details.
- //
- // You should have received a copy of the GNU Lesser General Public License
- // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
- package protocols
- import (
- "testing"
- "github.com/ethereum/go-ethereum/p2p"
- "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
- "github.com/ethereum/go-ethereum/rlp"
- )
- //dummy Balance implementation
- type dummyBalance struct {
- amount int64
- peer *Peer
- }
- //dummy Prices implementation
- type dummyPrices struct{}
- //a dummy message which needs size based accounting
- //sender pays
- type perBytesMsgSenderPays struct {
- Content string
- }
- //a dummy message which needs size based accounting
- //receiver pays
- type perBytesMsgReceiverPays struct {
- Content string
- }
- //a dummy message which is paid for per unit
- //sender pays
- type perUnitMsgSenderPays struct{}
- //receiver pays
- type perUnitMsgReceiverPays struct{}
- //a dummy message which has zero as its price
- type zeroPriceMsg struct{}
- //a dummy message which has no accounting
- type nilPriceMsg struct{}
- //return the price for the defined messages
- func (d *dummyPrices) Price(msg interface{}) *Price {
- switch msg.(type) {
- //size based message cost, receiver pays
- case *perBytesMsgReceiverPays:
- return &Price{
- PerByte: true,
- Value: uint64(100),
- Payer: Receiver,
- }
- //size based message cost, sender pays
- case *perBytesMsgSenderPays:
- return &Price{
- PerByte: true,
- Value: uint64(100),
- Payer: Sender,
- }
- //unitary cost, receiver pays
- case *perUnitMsgReceiverPays:
- return &Price{
- PerByte: false,
- Value: uint64(99),
- Payer: Receiver,
- }
- //unitary cost, sender pays
- case *perUnitMsgSenderPays:
- return &Price{
- PerByte: false,
- Value: uint64(99),
- Payer: Sender,
- }
- case *zeroPriceMsg:
- return &Price{
- PerByte: false,
- Value: uint64(0),
- Payer: Sender,
- }
- case *nilPriceMsg:
- return nil
- }
- return nil
- }
- //dummy accounting implementation, only stores values for later check
- func (d *dummyBalance) Add(amount int64, peer *Peer) error {
- d.amount = amount
- d.peer = peer
- return nil
- }
- type testCase struct {
- msg interface{}
- size uint32
- sendResult int64
- recvResult int64
- }
- //lowest level unit test
- func TestBalance(t *testing.T) {
- //create instances
- balance := &dummyBalance{}
- prices := &dummyPrices{}
- //create the spec
- spec := createTestSpec()
- //create the accounting hook for the spec
- acc := NewAccounting(balance, prices)
- //create a peer
- id := adapters.RandomNodeConfig().ID
- p := p2p.NewPeer(id, "testPeer", nil)
- peer := NewPeer(p, &dummyRW{}, spec)
- //price depends on size, receiver pays
- msg := &perBytesMsgReceiverPays{Content: "testBalance"}
- size, _ := rlp.EncodeToBytes(msg)
- testCases := []testCase{
- {
- msg,
- uint32(len(size)),
- int64(len(size) * 100),
- int64(len(size) * -100),
- },
- {
- &perBytesMsgSenderPays{Content: "testBalance"},
- uint32(len(size)),
- int64(len(size) * -100),
- int64(len(size) * 100),
- },
- {
- &perUnitMsgSenderPays{},
- 0,
- int64(-99),
- int64(99),
- },
- {
- &perUnitMsgReceiverPays{},
- 0,
- int64(99),
- int64(-99),
- },
- {
- &zeroPriceMsg{},
- 0,
- int64(0),
- int64(0),
- },
- {
- &nilPriceMsg{},
- 0,
- int64(0),
- int64(0),
- },
- }
- checkAccountingTestCases(t, testCases, acc, peer, balance, true)
- checkAccountingTestCases(t, testCases, acc, peer, balance, false)
- }
- func checkAccountingTestCases(t *testing.T, cases []testCase, acc *Accounting, peer *Peer, balance *dummyBalance, send bool) {
- for _, c := range cases {
- var err error
- var expectedResult int64
- //reset balance before every check
- balance.amount = 0
- if send {
- err = acc.Send(peer, c.size, c.msg)
- expectedResult = c.sendResult
- } else {
- err = acc.Receive(peer, c.size, c.msg)
- expectedResult = c.recvResult
- }
- checkResults(t, err, balance, peer, expectedResult)
- }
- }
- func checkResults(t *testing.T, err error, balance *dummyBalance, peer *Peer, result int64) {
- if err != nil {
- t.Fatal(err)
- }
- if balance.peer != peer {
- t.Fatalf("expected Add to be called with peer %v, got %v", peer, balance.peer)
- }
- if balance.amount != result {
- t.Fatalf("Expected balance to be %d but is %d", result, balance.amount)
- }
- }
- //create a test spec
- func createTestSpec() *Spec {
- spec := &Spec{
- Name: "test",
- Version: 42,
- MaxMsgSize: 10 * 1024,
- Messages: []interface{}{
- &perBytesMsgReceiverPays{},
- &perBytesMsgSenderPays{},
- &perUnitMsgReceiverPays{},
- &perUnitMsgSenderPays{},
- &zeroPriceMsg{},
- &nilPriceMsg{},
- },
- }
- return spec
- }
|