github.com/codingfuture/orig-energi3@v0.8.4/p2p/protocols/accounting_test.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package protocols 18 19 import ( 20 "testing" 21 22 "github.com/ethereum/go-ethereum/p2p" 23 "github.com/ethereum/go-ethereum/p2p/simulations/adapters" 24 "github.com/ethereum/go-ethereum/rlp" 25 ) 26 27 //dummy Balance implementation 28 type dummyBalance struct { 29 amount int64 30 peer *Peer 31 } 32 33 //dummy Prices implementation 34 type dummyPrices struct{} 35 36 //a dummy message which needs size based accounting 37 //sender pays 38 type perBytesMsgSenderPays struct { 39 Content string 40 } 41 42 //a dummy message which needs size based accounting 43 //receiver pays 44 type perBytesMsgReceiverPays struct { 45 Content string 46 } 47 48 //a dummy message which is paid for per unit 49 //sender pays 50 type perUnitMsgSenderPays struct{} 51 52 //receiver pays 53 type perUnitMsgReceiverPays struct{} 54 55 //a dummy message which has zero as its price 56 type zeroPriceMsg struct{} 57 58 //a dummy message which has no accounting 59 type nilPriceMsg struct{} 60 61 //return the price for the defined messages 62 func (d *dummyPrices) Price(msg interface{}) *Price { 63 switch msg.(type) { 64 //size based message cost, receiver pays 65 case *perBytesMsgReceiverPays: 66 return &Price{ 67 PerByte: true, 68 Value: uint64(100), 69 Payer: Receiver, 70 } 71 //size based message cost, sender pays 72 case *perBytesMsgSenderPays: 73 return &Price{ 74 PerByte: true, 75 Value: uint64(100), 76 Payer: Sender, 77 } 78 //unitary cost, receiver pays 79 case *perUnitMsgReceiverPays: 80 return &Price{ 81 PerByte: false, 82 Value: uint64(99), 83 Payer: Receiver, 84 } 85 //unitary cost, sender pays 86 case *perUnitMsgSenderPays: 87 return &Price{ 88 PerByte: false, 89 Value: uint64(99), 90 Payer: Sender, 91 } 92 case *zeroPriceMsg: 93 return &Price{ 94 PerByte: false, 95 Value: uint64(0), 96 Payer: Sender, 97 } 98 case *nilPriceMsg: 99 return nil 100 } 101 return nil 102 } 103 104 //dummy accounting implementation, only stores values for later check 105 func (d *dummyBalance) Add(amount int64, peer *Peer) error { 106 d.amount = amount 107 d.peer = peer 108 return nil 109 } 110 111 type testCase struct { 112 msg interface{} 113 size uint32 114 sendResult int64 115 recvResult int64 116 } 117 118 //lowest level unit test 119 func TestBalance(t *testing.T) { 120 //create instances 121 balance := &dummyBalance{} 122 prices := &dummyPrices{} 123 //create the spec 124 spec := createTestSpec() 125 //create the accounting hook for the spec 126 acc := NewAccounting(balance, prices) 127 //create a peer 128 id := adapters.RandomNodeConfig().ID 129 p := p2p.NewPeer(id, "testPeer", nil) 130 peer := NewPeer(p, &dummyRW{}, spec) 131 //price depends on size, receiver pays 132 msg := &perBytesMsgReceiverPays{Content: "testBalance"} 133 size, _ := rlp.EncodeToBytes(msg) 134 135 testCases := []testCase{ 136 { 137 msg, 138 uint32(len(size)), 139 int64(len(size) * 100), 140 int64(len(size) * -100), 141 }, 142 { 143 &perBytesMsgSenderPays{Content: "testBalance"}, 144 uint32(len(size)), 145 int64(len(size) * -100), 146 int64(len(size) * 100), 147 }, 148 { 149 &perUnitMsgSenderPays{}, 150 0, 151 int64(-99), 152 int64(99), 153 }, 154 { 155 &perUnitMsgReceiverPays{}, 156 0, 157 int64(99), 158 int64(-99), 159 }, 160 { 161 &zeroPriceMsg{}, 162 0, 163 int64(0), 164 int64(0), 165 }, 166 { 167 &nilPriceMsg{}, 168 0, 169 int64(0), 170 int64(0), 171 }, 172 } 173 checkAccountingTestCases(t, testCases, acc, peer, balance, true) 174 checkAccountingTestCases(t, testCases, acc, peer, balance, false) 175 } 176 177 func checkAccountingTestCases(t *testing.T, cases []testCase, acc *Accounting, peer *Peer, balance *dummyBalance, send bool) { 178 for _, c := range cases { 179 var err error 180 var expectedResult int64 181 //reset balance before every check 182 balance.amount = 0 183 if send { 184 err = acc.Send(peer, c.size, c.msg) 185 expectedResult = c.sendResult 186 } else { 187 err = acc.Receive(peer, c.size, c.msg) 188 expectedResult = c.recvResult 189 } 190 191 checkResults(t, err, balance, peer, expectedResult) 192 } 193 } 194 195 func checkResults(t *testing.T, err error, balance *dummyBalance, peer *Peer, result int64) { 196 if err != nil { 197 t.Fatal(err) 198 } 199 if balance.peer != peer { 200 t.Fatalf("expected Add to be called with peer %v, got %v", peer, balance.peer) 201 } 202 if balance.amount != result { 203 t.Fatalf("Expected balance to be %d but is %d", result, balance.amount) 204 } 205 } 206 207 //create a test spec 208 func createTestSpec() *Spec { 209 spec := &Spec{ 210 Name: "test", 211 Version: 42, 212 MaxMsgSize: 10 * 1024, 213 Messages: []interface{}{ 214 &perBytesMsgReceiverPays{}, 215 &perBytesMsgSenderPays{}, 216 &perUnitMsgReceiverPays{}, 217 &perUnitMsgSenderPays{}, 218 &zeroPriceMsg{}, 219 &nilPriceMsg{}, 220 }, 221 } 222 return spec 223 }