natspec_e2e_test.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. package natspec
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "os"
  6. "strings"
  7. "testing"
  8. "github.com/ethereum/go-ethereum/accounts"
  9. "github.com/ethereum/go-ethereum/common"
  10. "github.com/ethereum/go-ethereum/common/docserver"
  11. "github.com/ethereum/go-ethereum/common/registrar"
  12. "github.com/ethereum/go-ethereum/core"
  13. "github.com/ethereum/go-ethereum/core/state"
  14. "github.com/ethereum/go-ethereum/crypto"
  15. "github.com/ethereum/go-ethereum/eth"
  16. xe "github.com/ethereum/go-ethereum/xeth"
  17. )
  18. const (
  19. testBalance = "10000000000000000000"
  20. testFileName = "long_file_name_for_testing_registration_of_URLs_longer_than_32_bytes.content"
  21. testNotice = "Register key `utils.toHex(_key)` <- content `utils.toHex(_content)`"
  22. testExpNotice = "Register key 0xadd1a7d961cff0242089674ec2ef6fca671ab15e1fe80e38859fc815b98d88ab <- content 0xb3a2dea218de5d8bbe6c4645aadbf67b5ab00ecb1a9ec95dbdad6a0eed3e41a7"
  23. testExpNotice2 = `About to submit transaction (NatSpec notice error: abi key does not match any method): {"params":[{"to":"%s","data": "0x31e12c20"}]}`
  24. testExpNotice3 = `About to submit transaction (no NatSpec info found for contract: content hash not found for '0x1392c62d05b2d149e22a339c531157ae06b44d39a674cce500064b12b9aeb019'): {"params":[{"to":"%s","data": "0x300a3bbfb3a2dea218de5d8bbe6c4645aadbf67b5ab00ecb1a9ec95dbdad6a0eed3e41a7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000066696c653a2f2f2f746573742e636f6e74656e74"}]}`
  25. )
  26. const (
  27. testUserDoc = `
  28. {
  29. "methods": {
  30. "register(uint256,uint256)": {
  31. "notice": "` + testNotice + `"
  32. }
  33. },
  34. "invariants": [
  35. { "notice": "" }
  36. ],
  37. "construction": [
  38. { "notice": "" }
  39. ]
  40. }
  41. `
  42. testAbiDefinition = `
  43. [{
  44. "name": "register",
  45. "constant": false,
  46. "type": "function",
  47. "inputs": [{
  48. "name": "_key",
  49. "type": "uint256"
  50. }, {
  51. "name": "_content",
  52. "type": "uint256"
  53. }],
  54. "outputs": []
  55. }]
  56. `
  57. testContractInfo = `
  58. {
  59. "userDoc": ` + testUserDoc + `,
  60. "abiDefinition": ` + testAbiDefinition + `
  61. }
  62. `
  63. )
  64. type testFrontend struct {
  65. t *testing.T
  66. ethereum *eth.Ethereum
  67. xeth *xe.XEth
  68. coinbase common.Address
  69. stateDb *state.StateDB
  70. txc uint64
  71. lastConfirm string
  72. wantNatSpec bool
  73. }
  74. func (self *testFrontend) UnlockAccount(acc []byte) bool {
  75. self.ethereum.AccountManager().Unlock(common.BytesToAddress(acc), "password")
  76. return true
  77. }
  78. func (self *testFrontend) ConfirmTransaction(tx string) bool {
  79. if self.wantNatSpec {
  80. ds := docserver.New("/tmp/")
  81. self.lastConfirm = GetNotice(self.xeth, tx, ds)
  82. }
  83. return true
  84. }
  85. func testEth(t *testing.T) (ethereum *eth.Ethereum, err error) {
  86. os.RemoveAll("/tmp/eth-natspec/")
  87. err = os.MkdirAll("/tmp/eth-natspec/keystore", os.ModePerm)
  88. if err != nil {
  89. panic(err)
  90. }
  91. // create a testAddress
  92. ks := crypto.NewKeyStorePassphrase("/tmp/eth-natspec/keystore")
  93. am := accounts.NewManager(ks)
  94. testAccount, err := am.NewAccount("password")
  95. if err != nil {
  96. panic(err)
  97. }
  98. testAddress := strings.TrimPrefix(testAccount.Address.Hex(), "0x")
  99. // set up mock genesis with balance on the testAddress
  100. core.GenesisAccounts = []byte(`{
  101. "` + testAddress + `": {"balance": "` + testBalance + `"}
  102. }`)
  103. // only use minimalistic stack with no networking
  104. ethereum, err = eth.New(&eth.Config{
  105. DataDir: "/tmp/eth-natspec",
  106. AccountManager: am,
  107. MaxPeers: 0,
  108. })
  109. if err != nil {
  110. panic(err)
  111. }
  112. return
  113. }
  114. func testInit(t *testing.T) (self *testFrontend) {
  115. // initialise and start minimal ethereum stack
  116. ethereum, err := testEth(t)
  117. if err != nil {
  118. t.Errorf("error creating ethereum: %v", err)
  119. return
  120. }
  121. err = ethereum.Start()
  122. if err != nil {
  123. t.Errorf("error starting ethereum: %v", err)
  124. return
  125. }
  126. // mock frontend
  127. self = &testFrontend{t: t, ethereum: ethereum}
  128. self.xeth = xe.New(ethereum, self)
  129. addr, _ := ethereum.Etherbase()
  130. self.coinbase = addr
  131. self.stateDb = self.ethereum.ChainManager().State().Copy()
  132. // initialise the registry contracts
  133. reg := registrar.New(self.xeth)
  134. err = reg.SetHashReg("", addr)
  135. if err != nil {
  136. t.Errorf("error creating HashReg: %v", err)
  137. }
  138. err = reg.SetUrlHint("", addr)
  139. if err != nil {
  140. t.Errorf("error creating UrlHint: %v", err)
  141. }
  142. self.applyTxs()
  143. return
  144. }
  145. // this is needed for transaction to be applied to the state in testing
  146. // the heavy lifing is done in XEth.ApplyTestTxs
  147. // this is fragile,
  148. // and does process leaking since xeth loops cannot quit safely
  149. // should be replaced by proper mining with testDAG for easy full integration tests
  150. func (self *testFrontend) applyTxs() {
  151. self.txc, self.xeth = self.xeth.ApplyTestTxs(self.stateDb, self.coinbase, self.txc)
  152. return
  153. }
  154. // end to end test
  155. func TestNatspecE2E(t *testing.T) {
  156. t.Skip()
  157. tf := testInit(t)
  158. defer tf.ethereum.Stop()
  159. // create a contractInfo file (mock cloud-deployed contract metadocs)
  160. // incidentally this is the info for the registry contract itself
  161. ioutil.WriteFile("/tmp/"+testFileName, []byte(testContractInfo), os.ModePerm)
  162. dochash := common.BytesToHash(crypto.Sha3([]byte(testContractInfo)))
  163. // take the codehash for the contract we wanna test
  164. // codehex := tf.xeth.CodeAt(registar.HashRegAddr)
  165. codeb := tf.xeth.CodeAtBytes(registrar.HashRegAddr)
  166. codehash := common.BytesToHash(crypto.Sha3(codeb))
  167. // use resolver to register codehash->dochash->url
  168. // test if globalregistry works
  169. // registrar.HashRefAddr = "0x0"
  170. // registrar.UrlHintAddr = "0x0"
  171. reg := registrar.New(tf.xeth)
  172. _, err := reg.SetHashToHash(tf.coinbase, codehash, dochash)
  173. if err != nil {
  174. t.Errorf("error registering: %v", err)
  175. }
  176. _, err = reg.SetUrlToHash(tf.coinbase, dochash, "file:///"+testFileName)
  177. if err != nil {
  178. t.Errorf("error registering: %v", err)
  179. }
  180. // apply txs to the state
  181. tf.applyTxs()
  182. // NatSpec info for register method of HashReg contract installed
  183. // now using the same transactions to check confirm messages
  184. tf.wantNatSpec = true // this is set so now the backend uses natspec confirmation
  185. _, err = reg.SetHashToHash(tf.coinbase, codehash, dochash)
  186. if err != nil {
  187. t.Errorf("error calling contract registry: %v", err)
  188. }
  189. fmt.Printf("GlobalRegistrar: %v, HashReg: %v, UrlHint: %v\n", registrar.GlobalRegistrarAddr, registrar.HashRegAddr, registrar.UrlHintAddr)
  190. if tf.lastConfirm != testExpNotice {
  191. t.Errorf("Wrong confirm message. expected '%v', got '%v'", testExpNotice, tf.lastConfirm)
  192. }
  193. // test unknown method
  194. exp := fmt.Sprintf(testExpNotice2, registrar.HashRegAddr)
  195. _, err = reg.SetOwner(tf.coinbase)
  196. if err != nil {
  197. t.Errorf("error setting owner: %v", err)
  198. }
  199. if tf.lastConfirm != exp {
  200. t.Errorf("Wrong confirm message, expected '%v', got '%v'", exp, tf.lastConfirm)
  201. }
  202. // test unknown contract
  203. exp = fmt.Sprintf(testExpNotice3, registrar.UrlHintAddr)
  204. _, err = reg.SetUrlToHash(tf.coinbase, dochash, "file:///test.content")
  205. if err != nil {
  206. t.Errorf("error registering: %v", err)
  207. }
  208. if tf.lastConfirm != exp {
  209. t.Errorf("Wrong confirm message, expected '%v', got '%v'", exp, tf.lastConfirm)
  210. }
  211. }