js_test.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. package main
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "os"
  6. "path"
  7. "path/filepath"
  8. "regexp"
  9. "runtime"
  10. "strconv"
  11. "testing"
  12. "github.com/ethereum/go-ethereum/accounts"
  13. "github.com/ethereum/go-ethereum/common"
  14. "github.com/ethereum/go-ethereum/common/compiler"
  15. "github.com/ethereum/go-ethereum/common/docserver"
  16. "github.com/ethereum/go-ethereum/common/natspec"
  17. "github.com/ethereum/go-ethereum/common/resolver"
  18. "github.com/ethereum/go-ethereum/core"
  19. "github.com/ethereum/go-ethereum/core/state"
  20. "github.com/ethereum/go-ethereum/crypto"
  21. "github.com/ethereum/go-ethereum/eth"
  22. )
  23. const (
  24. testSolcPath = ""
  25. testKey = "e6fab74a43941f82d89cb7faa408e227cdad3153c4720e540e855c19b15e6674"
  26. testAddress = "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182"
  27. testBalance = "10000000000000000000"
  28. )
  29. var (
  30. testGenesis = `{"` + testAddress[2:] + `": {"balance": "` + testBalance + `"}}`
  31. )
  32. type testjethre struct {
  33. *jsre
  34. stateDb *state.StateDB
  35. lastConfirm string
  36. ds *docserver.DocServer
  37. }
  38. func (self *testjethre) UnlockAccount(acc []byte) bool {
  39. err := self.ethereum.AccountManager().Unlock(acc, "")
  40. if err != nil {
  41. panic("unable to unlock")
  42. }
  43. return true
  44. }
  45. func (self *testjethre) ConfirmTransaction(tx string) bool {
  46. if self.ethereum.NatSpec {
  47. self.lastConfirm = natspec.GetNotice(self.xeth, tx, self.ds)
  48. }
  49. return true
  50. }
  51. func testJEthRE(t *testing.T) (string, *testjethre, *eth.Ethereum) {
  52. tmp, err := ioutil.TempDir("", "geth-test")
  53. if err != nil {
  54. t.Fatal(err)
  55. }
  56. // set up mock genesis with balance on the testAddress
  57. core.GenesisData = []byte(testGenesis)
  58. ks := crypto.NewKeyStorePassphrase(filepath.Join(tmp, "keys"))
  59. am := accounts.NewManager(ks)
  60. ethereum, err := eth.New(&eth.Config{
  61. DataDir: tmp,
  62. AccountManager: am,
  63. MaxPeers: 0,
  64. Name: "test",
  65. })
  66. if err != nil {
  67. t.Fatal("%v", err)
  68. }
  69. keyb, err := crypto.HexToECDSA(testKey)
  70. if err != nil {
  71. t.Fatal(err)
  72. }
  73. key := crypto.NewKeyFromECDSA(keyb)
  74. err = ks.StoreKey(key, "")
  75. if err != nil {
  76. t.Fatal(err)
  77. }
  78. err = am.Unlock(key.Address, "")
  79. if err != nil {
  80. t.Fatal(err)
  81. }
  82. assetPath := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist", "assets", "ext")
  83. ds, err := docserver.New("/")
  84. if err != nil {
  85. t.Errorf("Error creating DocServer: %v", err)
  86. }
  87. tf := &testjethre{ds: ds, stateDb: ethereum.ChainManager().State().Copy()}
  88. repl := newJSRE(ethereum, assetPath, testSolcPath, "", false, tf)
  89. tf.jsre = repl
  90. return tmp, tf, ethereum
  91. }
  92. // this line below is needed for transaction to be applied to the state in testing
  93. // the heavy lifing is done in XEth.ApplyTestTxs
  94. // this is fragile, overwriting xeth will result in
  95. // process leaking since xeth loops cannot quit safely
  96. // should be replaced by proper mining with testDAG for easy full integration tests
  97. // txc, self.xeth = self.xeth.ApplyTestTxs(self.xeth.repl.stateDb, coinbase, txc)
  98. func TestNodeInfo(t *testing.T) {
  99. tmp, repl, ethereum := testJEthRE(t)
  100. if err := ethereum.Start(); err != nil {
  101. t.Fatalf("error starting ethereum: %v", err)
  102. }
  103. defer ethereum.Stop()
  104. defer os.RemoveAll(tmp)
  105. want := `{"DiscPort":0,"IP":"0.0.0.0","ListenAddr":"","Name":"test","NodeID":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","NodeUrl":"enode://00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000@0.0.0.0:0","TCPPort":0,"Td":"0"}`
  106. checkEvalJSON(t, repl, `admin.nodeInfo()`, want)
  107. }
  108. func TestAccounts(t *testing.T) {
  109. tmp, repl, ethereum := testJEthRE(t)
  110. if err := ethereum.Start(); err != nil {
  111. t.Fatalf("error starting ethereum: %v", err)
  112. }
  113. defer ethereum.Stop()
  114. defer os.RemoveAll(tmp)
  115. checkEvalJSON(t, repl, `eth.accounts`, `["`+testAddress+`"]`)
  116. checkEvalJSON(t, repl, `eth.coinbase`, `"`+testAddress+`"`)
  117. val, err := repl.re.Run(`admin.newAccount("password")`)
  118. if err != nil {
  119. t.Errorf("expected no error, got %v", err)
  120. }
  121. addr := val.String()
  122. if !regexp.MustCompile(`0x[0-9a-f]{40}`).MatchString(addr) {
  123. t.Errorf("address not hex: %q", addr)
  124. }
  125. // skip until order fixed #824
  126. // checkEvalJSON(t, repl, `eth.accounts`, `["`+testAddress+`", "`+addr+`"]`)
  127. // checkEvalJSON(t, repl, `eth.coinbase`, `"`+testAddress+`"`)
  128. }
  129. func TestBlockChain(t *testing.T) {
  130. tmp, repl, ethereum := testJEthRE(t)
  131. if err := ethereum.Start(); err != nil {
  132. t.Fatalf("error starting ethereum: %v", err)
  133. }
  134. defer ethereum.Stop()
  135. defer os.RemoveAll(tmp)
  136. // get current block dump before export/import.
  137. val, err := repl.re.Run("JSON.stringify(admin.debug.dumpBlock())")
  138. if err != nil {
  139. t.Errorf("expected no error, got %v", err)
  140. }
  141. beforeExport := val.String()
  142. // do the export
  143. extmp, err := ioutil.TempDir("", "geth-test-export")
  144. if err != nil {
  145. t.Fatal(err)
  146. }
  147. defer os.RemoveAll(extmp)
  148. tmpfile := filepath.Join(extmp, "export.chain")
  149. tmpfileq := strconv.Quote(tmpfile)
  150. checkEvalJSON(t, repl, `admin.export(`+tmpfileq+`)`, `true`)
  151. if _, err := os.Stat(tmpfile); err != nil {
  152. t.Fatal(err)
  153. }
  154. // check import, verify that dumpBlock gives the same result.
  155. checkEvalJSON(t, repl, `admin.import(`+tmpfileq+`)`, `true`)
  156. checkEvalJSON(t, repl, `admin.debug.dumpBlock()`, beforeExport)
  157. }
  158. func TestMining(t *testing.T) {
  159. tmp, repl, ethereum := testJEthRE(t)
  160. if err := ethereum.Start(); err != nil {
  161. t.Fatalf("error starting ethereum: %v", err)
  162. }
  163. defer ethereum.Stop()
  164. defer os.RemoveAll(tmp)
  165. checkEvalJSON(t, repl, `eth.mining`, `false`)
  166. }
  167. func TestRPC(t *testing.T) {
  168. tmp, repl, ethereum := testJEthRE(t)
  169. if err := ethereum.Start(); err != nil {
  170. t.Errorf("error starting ethereum: %v", err)
  171. return
  172. }
  173. defer ethereum.Stop()
  174. defer os.RemoveAll(tmp)
  175. checkEvalJSON(t, repl, `admin.startRPC("127.0.0.1", 5004)`, `true`)
  176. }
  177. func TestCheckTestAccountBalance(t *testing.T) {
  178. tmp, repl, ethereum := testJEthRE(t)
  179. if err := ethereum.Start(); err != nil {
  180. t.Errorf("error starting ethereum: %v", err)
  181. return
  182. }
  183. defer ethereum.Stop()
  184. defer os.RemoveAll(tmp)
  185. repl.re.Run(`primary = "` + testAddress + `"`)
  186. checkEvalJSON(t, repl, `eth.getBalance(primary)`, `"`+testBalance+`"`)
  187. }
  188. func TestContract(t *testing.T) {
  189. tmp, repl, ethereum := testJEthRE(t)
  190. if err := ethereum.Start(); err != nil {
  191. t.Errorf("error starting ethereum: %v", err)
  192. return
  193. }
  194. defer ethereum.Stop()
  195. defer os.RemoveAll(tmp)
  196. var txc uint64
  197. coinbase := common.HexToAddress(testAddress)
  198. resolver.New(repl.xeth).CreateContracts(coinbase)
  199. source := `contract test {\n` +
  200. " /// @notice Will multiply `a` by 7." + `\n` +
  201. ` function multiply(uint a) returns(uint d) {\n` +
  202. ` return a * 7;\n` +
  203. ` }\n` +
  204. `}\n`
  205. checkEvalJSON(t, repl, `admin.contractInfo.stop()`, `true`)
  206. contractInfo, err := ioutil.ReadFile("info_test.json")
  207. if err != nil {
  208. t.Fatalf("%v", err)
  209. }
  210. checkEvalJSON(t, repl, `primary = eth.accounts[0]`, `"`+testAddress+`"`)
  211. checkEvalJSON(t, repl, `source = "`+source+`"`, `"`+source+`"`)
  212. _, err = compiler.New("")
  213. if err != nil {
  214. t.Logf("solc not found: skipping compiler test")
  215. info, err := ioutil.ReadFile("info_test.json")
  216. if err != nil {
  217. t.Fatalf("%v", err)
  218. }
  219. _, err = repl.re.Run(`contract = JSON.parse(` + strconv.Quote(string(info)) + `)`)
  220. if err != nil {
  221. t.Errorf("%v", err)
  222. }
  223. } else {
  224. checkEvalJSON(t, repl, `contract = eth.compile.solidity(source)`, string(contractInfo))
  225. }
  226. checkEvalJSON(t, repl, `contract.code`, `"605280600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b60376004356041565b8060005260206000f35b6000600782029050604d565b91905056"`)
  227. checkEvalJSON(
  228. t, repl,
  229. `contractaddress = eth.sendTransaction({from: primary, data: contract.code })`,
  230. `"0x5dcaace5982778b409c524873b319667eba5d074"`,
  231. )
  232. callSetup := `abiDef = JSON.parse('[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}]');
  233. Multiply7 = eth.contract(abiDef);
  234. multiply7 = new Multiply7(contractaddress);
  235. `
  236. _, err = repl.re.Run(callSetup)
  237. if err != nil {
  238. t.Errorf("unexpected error registering, got %v", err)
  239. }
  240. // updatespec
  241. // why is this sometimes failing?
  242. // checkEvalJSON(t, repl, `multiply7.multiply.call(6)`, `42`)
  243. expNotice := ""
  244. if repl.lastConfirm != expNotice {
  245. t.Errorf("incorrect confirmation message: expected %v, got %v", expNotice, repl.lastConfirm)
  246. }
  247. // why 0?
  248. checkEvalJSON(t, repl, `eth.getBlock("pending", true).transactions.length`, `0`)
  249. txc, repl.xeth = repl.xeth.ApplyTestTxs(repl.stateDb, coinbase, txc)
  250. checkEvalJSON(t, repl, `admin.contractInfo.start()`, `true`)
  251. checkEvalJSON(t, repl, `multiply7.multiply.sendTransaction(6, { from: primary, gas: "1000000", gasPrice: "100000" })`, `undefined`)
  252. expNotice = `About to submit transaction (no NatSpec info found for contract: content hash not found for '0x4a6c99e127191d2ee302e42182c338344b39a37a47cdbb17ab0f26b6802eb4d1'): {"params":[{"to":"0x5dcaace5982778b409c524873b319667eba5d074","data": "0xc6888fa10000000000000000000000000000000000000000000000000000000000000006"}]}`
  253. if repl.lastConfirm != expNotice {
  254. t.Errorf("incorrect confirmation message: expected %v, got %v", expNotice, repl.lastConfirm)
  255. }
  256. checkEvalJSON(t, repl, `filename = "/tmp/info.json"`, `"/tmp/info.json"`)
  257. checkEvalJSON(t, repl, `contenthash = admin.contractInfo.register(primary, contractaddress, contract, filename)`, `"0x57e577316ccee6514797d9de9823af2004fdfe22bcfb6e39bbb8f92f57dcc421"`)
  258. checkEvalJSON(t, repl, `admin.contractInfo.registerUrl(primary, contenthash, "file://"+filename)`, `true`)
  259. if err != nil {
  260. t.Errorf("unexpected error registering, got %v", err)
  261. }
  262. checkEvalJSON(t, repl, `admin.contractInfo.start()`, `true`)
  263. // update state
  264. txc, repl.xeth = repl.xeth.ApplyTestTxs(repl.stateDb, coinbase, txc)
  265. checkEvalJSON(t, repl, `multiply7.multiply.sendTransaction(6, { from: primary, gas: "1000000", gasPrice: "100000" })`, `undefined`)
  266. expNotice = "Will multiply 6 by 7."
  267. if repl.lastConfirm != expNotice {
  268. t.Errorf("incorrect confirmation message: expected %v, got %v", expNotice, repl.lastConfirm)
  269. }
  270. }
  271. func checkEvalJSON(t *testing.T, re *testjethre, expr, want string) error {
  272. val, err := re.re.Run("JSON.stringify(" + expr + ")")
  273. if err == nil && val.String() != want {
  274. err = fmt.Errorf("Output mismatch for `%s`:\ngot: %s\nwant: %s", expr, val.String(), want)
  275. }
  276. if err != nil {
  277. _, file, line, _ := runtime.Caller(1)
  278. file = path.Base(file)
  279. fmt.Printf("\t%s:%d: %v\n", file, line, err)
  280. t.Fail()
  281. }
  282. return err
  283. }