accounting_test.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  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. package protocols
  17. import (
  18. "testing"
  19. "github.com/ethereum/go-ethereum/p2p"
  20. "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
  21. "github.com/ethereum/go-ethereum/rlp"
  22. )
  23. //dummy Balance implementation
  24. type dummyBalance struct {
  25. amount int64
  26. peer *Peer
  27. }
  28. //dummy Prices implementation
  29. type dummyPrices struct{}
  30. //a dummy message which needs size based accounting
  31. //sender pays
  32. type perBytesMsgSenderPays struct {
  33. Content string
  34. }
  35. //a dummy message which needs size based accounting
  36. //receiver pays
  37. type perBytesMsgReceiverPays struct {
  38. Content string
  39. }
  40. //a dummy message which is paid for per unit
  41. //sender pays
  42. type perUnitMsgSenderPays struct{}
  43. //receiver pays
  44. type perUnitMsgReceiverPays struct{}
  45. //a dummy message which has zero as its price
  46. type zeroPriceMsg struct{}
  47. //a dummy message which has no accounting
  48. type nilPriceMsg struct{}
  49. //return the price for the defined messages
  50. func (d *dummyPrices) Price(msg interface{}) *Price {
  51. switch msg.(type) {
  52. //size based message cost, receiver pays
  53. case *perBytesMsgReceiverPays:
  54. return &Price{
  55. PerByte: true,
  56. Value: uint64(100),
  57. Payer: Receiver,
  58. }
  59. //size based message cost, sender pays
  60. case *perBytesMsgSenderPays:
  61. return &Price{
  62. PerByte: true,
  63. Value: uint64(100),
  64. Payer: Sender,
  65. }
  66. //unitary cost, receiver pays
  67. case *perUnitMsgReceiverPays:
  68. return &Price{
  69. PerByte: false,
  70. Value: uint64(99),
  71. Payer: Receiver,
  72. }
  73. //unitary cost, sender pays
  74. case *perUnitMsgSenderPays:
  75. return &Price{
  76. PerByte: false,
  77. Value: uint64(99),
  78. Payer: Sender,
  79. }
  80. case *zeroPriceMsg:
  81. return &Price{
  82. PerByte: false,
  83. Value: uint64(0),
  84. Payer: Sender,
  85. }
  86. case *nilPriceMsg:
  87. return nil
  88. }
  89. return nil
  90. }
  91. //dummy accounting implementation, only stores values for later check
  92. func (d *dummyBalance) Add(amount int64, peer *Peer) error {
  93. d.amount = amount
  94. d.peer = peer
  95. return nil
  96. }
  97. type testCase struct {
  98. msg interface{}
  99. size uint32
  100. sendResult int64
  101. recvResult int64
  102. }
  103. //lowest level unit test
  104. func TestBalance(t *testing.T) {
  105. //create instances
  106. balance := &dummyBalance{}
  107. prices := &dummyPrices{}
  108. //create the spec
  109. spec := createTestSpec()
  110. //create the accounting hook for the spec
  111. acc := NewAccounting(balance, prices)
  112. //create a peer
  113. id := adapters.RandomNodeConfig().ID
  114. p := p2p.NewPeer(id, "testPeer", nil)
  115. peer := NewPeer(p, &dummyRW{}, spec)
  116. //price depends on size, receiver pays
  117. msg := &perBytesMsgReceiverPays{Content: "testBalance"}
  118. size, _ := rlp.EncodeToBytes(msg)
  119. testCases := []testCase{
  120. {
  121. msg,
  122. uint32(len(size)),
  123. int64(len(size) * 100),
  124. int64(len(size) * -100),
  125. },
  126. {
  127. &perBytesMsgSenderPays{Content: "testBalance"},
  128. uint32(len(size)),
  129. int64(len(size) * -100),
  130. int64(len(size) * 100),
  131. },
  132. {
  133. &perUnitMsgSenderPays{},
  134. 0,
  135. int64(-99),
  136. int64(99),
  137. },
  138. {
  139. &perUnitMsgReceiverPays{},
  140. 0,
  141. int64(99),
  142. int64(-99),
  143. },
  144. {
  145. &zeroPriceMsg{},
  146. 0,
  147. int64(0),
  148. int64(0),
  149. },
  150. {
  151. &nilPriceMsg{},
  152. 0,
  153. int64(0),
  154. int64(0),
  155. },
  156. }
  157. checkAccountingTestCases(t, testCases, acc, peer, balance, true)
  158. checkAccountingTestCases(t, testCases, acc, peer, balance, false)
  159. }
  160. func checkAccountingTestCases(t *testing.T, cases []testCase, acc *Accounting, peer *Peer, balance *dummyBalance, send bool) {
  161. for _, c := range cases {
  162. var err error
  163. var expectedResult int64
  164. //reset balance before every check
  165. balance.amount = 0
  166. if send {
  167. err = acc.Send(peer, c.size, c.msg)
  168. expectedResult = c.sendResult
  169. } else {
  170. err = acc.Receive(peer, c.size, c.msg)
  171. expectedResult = c.recvResult
  172. }
  173. checkResults(t, err, balance, peer, expectedResult)
  174. }
  175. }
  176. func checkResults(t *testing.T, err error, balance *dummyBalance, peer *Peer, result int64) {
  177. if err != nil {
  178. t.Fatal(err)
  179. }
  180. if balance.peer != peer {
  181. t.Fatalf("expected Add to be called with peer %v, got %v", peer, balance.peer)
  182. }
  183. if balance.amount != result {
  184. t.Fatalf("Expected balance to be %d but is %d", result, balance.amount)
  185. }
  186. }
  187. //create a test spec
  188. func createTestSpec() *Spec {
  189. spec := &Spec{
  190. Name: "test",
  191. Version: 42,
  192. MaxMsgSize: 10 * 1024,
  193. Messages: []interface{}{
  194. &perBytesMsgReceiverPays{},
  195. &perBytesMsgSenderPays{},
  196. &perUnitMsgReceiverPays{},
  197. &perUnitMsgSenderPays{},
  198. &zeroPriceMsg{},
  199. &nilPriceMsg{},
  200. },
  201. }
  202. return spec
  203. }