request_test.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  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 feed
  17. import (
  18. "bytes"
  19. "encoding/binary"
  20. "encoding/json"
  21. "fmt"
  22. "reflect"
  23. "testing"
  24. "github.com/ethereum/go-ethereum/crypto"
  25. "github.com/ethereum/go-ethereum/swarm/storage"
  26. "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup"
  27. )
  28. func areEqualJSON(s1, s2 string) (bool, error) {
  29. //credit for the trick: turtlemonvh https://gist.github.com/turtlemonvh/e4f7404e28387fadb8ad275a99596f67
  30. var o1 interface{}
  31. var o2 interface{}
  32. err := json.Unmarshal([]byte(s1), &o1)
  33. if err != nil {
  34. return false, fmt.Errorf("Error mashalling string 1 :: %s", err.Error())
  35. }
  36. err = json.Unmarshal([]byte(s2), &o2)
  37. if err != nil {
  38. return false, fmt.Errorf("Error mashalling string 2 :: %s", err.Error())
  39. }
  40. return reflect.DeepEqual(o1, o2), nil
  41. }
  42. // TestEncodingDecodingUpdateRequests ensures that requests are serialized properly
  43. // while also checking cryptographically that only the owner of a feed can update it.
  44. func TestEncodingDecodingUpdateRequests(t *testing.T) {
  45. charlie := newCharlieSigner() //Charlie
  46. bob := newBobSigner() //Bob
  47. // Create a feed to our good guy Charlie's name
  48. topic, _ := NewTopic("a good topic name", nil)
  49. firstRequest := NewFirstRequest(topic)
  50. firstRequest.User = charlie.Address()
  51. // We now encode the create message to simulate we send it over the wire
  52. messageRawData, err := firstRequest.MarshalJSON()
  53. if err != nil {
  54. t.Fatalf("Error encoding first feed update request: %s", err)
  55. }
  56. // ... the message arrives and is decoded...
  57. var recoveredFirstRequest Request
  58. if err := recoveredFirstRequest.UnmarshalJSON(messageRawData); err != nil {
  59. t.Fatalf("Error decoding first feed update request: %s", err)
  60. }
  61. // ... but verification should fail because it is not signed!
  62. if err := recoveredFirstRequest.Verify(); err == nil {
  63. t.Fatal("Expected Verify to fail since the message is not signed")
  64. }
  65. // We now assume that the feed ypdate was created and propagated.
  66. const expectedSignature = "0x7235b27a68372ddebcf78eba48543fa460864b0b0e99cb533fcd3664820e603312d29426dd00fb39628f5299480a69bf6e462838d78de49ce0704c754c9deb2601"
  67. const expectedJSON = `{"feed":{"topic":"0x6120676f6f6420746f706963206e616d65000000000000000000000000000000","user":"0x876a8936a7cd0b79ef0735ad0896c1afe278781c"},"epoch":{"time":1000,"level":1},"protocolVersion":0,"data":"0x5468697320686f75722773207570646174653a20537761726d2039392e3020686173206265656e2072656c656173656421"}`
  68. //Put together an unsigned update request that we will serialize to send it to the signer.
  69. data := []byte("This hour's update: Swarm 99.0 has been released!")
  70. request := &Request{
  71. Update: Update{
  72. ID: ID{
  73. Epoch: lookup.Epoch{
  74. Time: 1000,
  75. Level: 1,
  76. },
  77. Feed: firstRequest.Update.Feed,
  78. },
  79. data: data,
  80. },
  81. }
  82. messageRawData, err = request.MarshalJSON()
  83. if err != nil {
  84. t.Fatalf("Error encoding update request: %s", err)
  85. }
  86. equalJSON, err := areEqualJSON(string(messageRawData), expectedJSON)
  87. if err != nil {
  88. t.Fatalf("Error decoding update request JSON: %s", err)
  89. }
  90. if !equalJSON {
  91. t.Fatalf("Received a different JSON message. Expected %s, got %s", expectedJSON, string(messageRawData))
  92. }
  93. // now the encoded message messageRawData is sent over the wire and arrives to the signer
  94. //Attempt to extract an UpdateRequest out of the encoded message
  95. var recoveredRequest Request
  96. if err := recoveredRequest.UnmarshalJSON(messageRawData); err != nil {
  97. t.Fatalf("Error decoding update request: %s", err)
  98. }
  99. //sign the request and see if it matches our predefined signature above.
  100. if err := recoveredRequest.Sign(charlie); err != nil {
  101. t.Fatalf("Error signing request: %s", err)
  102. }
  103. compareByteSliceToExpectedHex(t, "signature", recoveredRequest.Signature[:], expectedSignature)
  104. // mess with the signature and see what happens. To alter the signature, we briefly decode it as JSON
  105. // to alter the signature field.
  106. var j updateRequestJSON
  107. if err := json.Unmarshal([]byte(expectedJSON), &j); err != nil {
  108. t.Fatal("Error unmarshalling test json, check expectedJSON constant")
  109. }
  110. j.Signature = "Certainly not a signature"
  111. corruptMessage, _ := json.Marshal(j) // encode the message with the bad signature
  112. var corruptRequest Request
  113. if err = corruptRequest.UnmarshalJSON(corruptMessage); err == nil {
  114. t.Fatal("Expected DecodeUpdateRequest to fail when trying to interpret a corrupt message with an invalid signature")
  115. }
  116. // Now imagine Bob wants to create an update of his own about the same feed,
  117. // signing a message with his private key
  118. if err := request.Sign(bob); err != nil {
  119. t.Fatalf("Error signing: %s", err)
  120. }
  121. // Now Bob encodes the message to send it over the wire...
  122. messageRawData, err = request.MarshalJSON()
  123. if err != nil {
  124. t.Fatalf("Error encoding message:%s", err)
  125. }
  126. // ... the message arrives to our Swarm node and it is decoded.
  127. recoveredRequest = Request{}
  128. if err := recoveredRequest.UnmarshalJSON(messageRawData); err != nil {
  129. t.Fatalf("Error decoding message:%s", err)
  130. }
  131. // Before checking what happened with Bob's update, let's see what would happen if we mess
  132. // with the signature big time to see if Verify catches it
  133. savedSignature := *recoveredRequest.Signature // save the signature for later
  134. binary.LittleEndian.PutUint64(recoveredRequest.Signature[5:], 556845463424) // write some random data to break the signature
  135. if err = recoveredRequest.Verify(); err == nil {
  136. t.Fatal("Expected Verify to fail on corrupt signature")
  137. }
  138. // restore the Bob's signature from corruption
  139. *recoveredRequest.Signature = savedSignature
  140. // Now the signature is not corrupt
  141. if err = recoveredRequest.Verify(); err != nil {
  142. t.Fatal(err)
  143. }
  144. // Reuse object and sign with our friend Charlie's private key
  145. if err := recoveredRequest.Sign(charlie); err != nil {
  146. t.Fatalf("Error signing with the correct private key: %s", err)
  147. }
  148. // And now, Verify should work since this update now belongs to Charlie
  149. if err = recoveredRequest.Verify(); err != nil {
  150. t.Fatalf("Error verifying that Charlie, can sign a reused request object:%s", err)
  151. }
  152. // mess with the lookup key to make sure Verify fails:
  153. recoveredRequest.Time = 77999 // this will alter the lookup key
  154. if err = recoveredRequest.Verify(); err == nil {
  155. t.Fatalf("Expected Verify to fail since the lookup key has been altered")
  156. }
  157. }
  158. func getTestRequest() *Request {
  159. return &Request{
  160. Update: *getTestFeedUpdate(),
  161. }
  162. }
  163. func TestUpdateChunkSerializationErrorChecking(t *testing.T) {
  164. // Test that parseUpdate fails if the chunk is too small
  165. var r Request
  166. if err := r.fromChunk(storage.NewChunk(storage.ZeroAddr, make([]byte, minimumUpdateDataLength-1+signatureLength))); err == nil {
  167. t.Fatalf("Expected request.fromChunk to fail when chunkData contains less than %d bytes", minimumUpdateDataLength)
  168. }
  169. r = *getTestRequest()
  170. _, err := r.toChunk()
  171. if err == nil {
  172. t.Fatal("Expected request.toChunk to fail when there is no data")
  173. }
  174. r.data = []byte("Al bien hacer jamás le falta premio") // put some arbitrary length data
  175. _, err = r.toChunk()
  176. if err == nil {
  177. t.Fatal("expected request.toChunk to fail when there is no signature")
  178. }
  179. charlie := newCharlieSigner()
  180. if err := r.Sign(charlie); err != nil {
  181. t.Fatalf("error signing:%s", err)
  182. }
  183. chunk, err := r.toChunk()
  184. if err != nil {
  185. t.Fatalf("error creating update chunk:%s", err)
  186. }
  187. compareByteSliceToExpectedHex(t, "chunk", chunk.Data(), "0x0000000000000000776f726c64206e657773207265706f72742c20657665727920686f7572000000876a8936a7cd0b79ef0735ad0896c1afe278781ce803000000000019416c206269656e206861636572206a616dc3a173206c652066616c7461207072656d696f5a0ffe0bc27f207cd5b00944c8b9cee93e08b89b5ada777f123ac535189333f174a6a4ca2f43a92c4a477a49d774813c36ce8288552c58e6205b0ac35d0507eb00")
  188. var recovered Request
  189. recovered.fromChunk(chunk)
  190. if !reflect.DeepEqual(recovered, r) {
  191. t.Fatal("Expected recovered feed update request to equal the original one")
  192. }
  193. }
  194. // check that signature address matches update signer address
  195. func TestReverse(t *testing.T) {
  196. epoch := lookup.Epoch{
  197. Time: 7888,
  198. Level: 6,
  199. }
  200. // make fake timeProvider
  201. timeProvider := &fakeTimeProvider{
  202. currentTime: startTime.Time,
  203. }
  204. // signer containing private key
  205. signer := newAliceSigner()
  206. // set up rpc and create feeds handler
  207. _, _, teardownTest, err := setupTest(timeProvider, signer)
  208. if err != nil {
  209. t.Fatal(err)
  210. }
  211. defer teardownTest()
  212. topic, _ := NewTopic("Cervantes quotes", nil)
  213. fd := Feed{
  214. Topic: topic,
  215. User: signer.Address(),
  216. }
  217. data := []byte("Donde una puerta se cierra, otra se abre")
  218. request := new(Request)
  219. request.Feed = fd
  220. request.Epoch = epoch
  221. request.data = data
  222. // generate a chunk key for this request
  223. key := request.Addr()
  224. if err = request.Sign(signer); err != nil {
  225. t.Fatal(err)
  226. }
  227. chunk, err := request.toChunk()
  228. if err != nil {
  229. t.Fatal(err)
  230. }
  231. // check that we can recover the owner account from the update chunk's signature
  232. var checkUpdate Request
  233. if err := checkUpdate.fromChunk(chunk); err != nil {
  234. t.Fatal(err)
  235. }
  236. checkdigest, err := checkUpdate.GetDigest()
  237. if err != nil {
  238. t.Fatal(err)
  239. }
  240. recoveredAddr, err := getUserAddr(checkdigest, *checkUpdate.Signature)
  241. if err != nil {
  242. t.Fatalf("Retrieve address from signature fail: %v", err)
  243. }
  244. originalAddr := crypto.PubkeyToAddress(signer.PrivKey.PublicKey)
  245. // check that the metadata retrieved from the chunk matches what we gave it
  246. if recoveredAddr != originalAddr {
  247. t.Fatalf("addresses dont match: %x != %x", originalAddr, recoveredAddr)
  248. }
  249. if !bytes.Equal(key[:], chunk.Address()[:]) {
  250. t.Fatalf("Expected chunk key '%x', was '%x'", key, chunk.Address())
  251. }
  252. if epoch != checkUpdate.Epoch {
  253. t.Fatalf("Expected epoch to be '%s', was '%s'", epoch.String(), checkUpdate.Epoch.String())
  254. }
  255. if !bytes.Equal(data, checkUpdate.data) {
  256. t.Fatalf("Expected data '%x', was '%x'", data, checkUpdate.data)
  257. }
  258. }