admin.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. package main
  2. import (
  3. "errors"
  4. "fmt"
  5. "strconv"
  6. "time"
  7. "github.com/ethereum/go-ethereum/cmd/utils"
  8. "github.com/ethereum/go-ethereum/common"
  9. "github.com/ethereum/go-ethereum/core/state"
  10. "github.com/ethereum/go-ethereum/core/types"
  11. "github.com/ethereum/go-ethereum/core/vm"
  12. "github.com/ethereum/go-ethereum/logger/glog"
  13. "github.com/ethereum/go-ethereum/rlp"
  14. "github.com/ethereum/go-ethereum/rpc"
  15. "github.com/ethereum/go-ethereum/xeth"
  16. "github.com/robertkrimen/otto"
  17. "gopkg.in/fatih/set.v0"
  18. )
  19. /*
  20. node admin bindings
  21. */
  22. func (js *jsre) adminBindings() {
  23. ethO, _ := js.re.Get("eth")
  24. eth := ethO.Object()
  25. eth.Set("pendingTransactions", js.pendingTransactions)
  26. eth.Set("resend", js.resend)
  27. js.re.Set("admin", struct{}{})
  28. t, _ := js.re.Get("admin")
  29. admin := t.Object()
  30. admin.Set("addPeer", js.addPeer)
  31. admin.Set("startRPC", js.startRPC)
  32. admin.Set("stopRPC", js.stopRPC)
  33. admin.Set("nodeInfo", js.nodeInfo)
  34. admin.Set("peers", js.peers)
  35. admin.Set("newAccount", js.newAccount)
  36. admin.Set("unlock", js.unlock)
  37. admin.Set("import", js.importChain)
  38. admin.Set("export", js.exportChain)
  39. admin.Set("verbosity", js.verbosity)
  40. admin.Set("progress", js.downloadProgress)
  41. admin.Set("miner", struct{}{})
  42. t, _ = admin.Get("miner")
  43. miner := t.Object()
  44. miner.Set("start", js.startMining)
  45. miner.Set("stop", js.stopMining)
  46. miner.Set("hashrate", js.hashrate)
  47. miner.Set("setExtra", js.setExtra)
  48. admin.Set("debug", struct{}{})
  49. t, _ = admin.Get("debug")
  50. debug := t.Object()
  51. debug.Set("backtrace", js.backtrace)
  52. debug.Set("printBlock", js.printBlock)
  53. debug.Set("dumpBlock", js.dumpBlock)
  54. debug.Set("getBlockRlp", js.getBlockRlp)
  55. debug.Set("setHead", js.setHead)
  56. debug.Set("processBlock", js.debugBlock)
  57. }
  58. func (js *jsre) getBlock(call otto.FunctionCall) (*types.Block, error) {
  59. var block *types.Block
  60. if len(call.ArgumentList) > 0 {
  61. if call.Argument(0).IsNumber() {
  62. num, _ := call.Argument(0).ToInteger()
  63. block = js.ethereum.ChainManager().GetBlockByNumber(uint64(num))
  64. } else if call.Argument(0).IsString() {
  65. hash, _ := call.Argument(0).ToString()
  66. block = js.ethereum.ChainManager().GetBlock(common.HexToHash(hash))
  67. } else {
  68. return nil, errors.New("invalid argument for dump. Either hex string or number")
  69. }
  70. return block, nil
  71. }
  72. return nil, errors.New("requires block number or block hash as argument")
  73. }
  74. func (js *jsre) pendingTransactions(call otto.FunctionCall) otto.Value {
  75. txs := js.ethereum.TxPool().GetTransactions()
  76. // grab the accounts from the account manager. This will help with determening which
  77. // transactions should be returned.
  78. accounts, err := js.ethereum.AccountManager().Accounts()
  79. if err != nil {
  80. fmt.Println(err)
  81. return otto.UndefinedValue()
  82. }
  83. // Add the accouns to a new set
  84. accountSet := set.New()
  85. for _, account := range accounts {
  86. accountSet.Add(common.BytesToAddress(account.Address))
  87. }
  88. //ltxs := make([]*tx, len(txs))
  89. var ltxs []*tx
  90. for _, tx := range txs {
  91. // no need to check err
  92. if from, _ := tx.From(); accountSet.Has(from) {
  93. ltxs = append(ltxs, newTx(tx))
  94. }
  95. }
  96. return js.re.ToVal(ltxs)
  97. }
  98. func (js *jsre) resend(call otto.FunctionCall) otto.Value {
  99. if len(call.ArgumentList) == 0 {
  100. fmt.Println("first argument must be a transaction")
  101. return otto.FalseValue()
  102. }
  103. v, err := call.Argument(0).Export()
  104. if err != nil {
  105. fmt.Println(err)
  106. return otto.FalseValue()
  107. }
  108. if tx, ok := v.(*tx); ok {
  109. gl, gp := tx.GasLimit, tx.GasPrice
  110. if len(call.ArgumentList) > 1 {
  111. gp = call.Argument(1).String()
  112. }
  113. if len(call.ArgumentList) > 2 {
  114. gl = call.Argument(2).String()
  115. }
  116. ret, err := js.xeth.Transact(tx.From, tx.To, tx.Nonce, tx.Value, gl, gp, tx.Data)
  117. if err != nil {
  118. fmt.Println(err)
  119. return otto.FalseValue()
  120. }
  121. js.ethereum.TxPool().RemoveTransactions(types.Transactions{tx.tx})
  122. return js.re.ToVal(ret)
  123. }
  124. fmt.Println("first argument must be a transaction")
  125. return otto.FalseValue()
  126. }
  127. func (js *jsre) debugBlock(call otto.FunctionCall) otto.Value {
  128. block, err := js.getBlock(call)
  129. if err != nil {
  130. fmt.Println(err)
  131. return otto.UndefinedValue()
  132. }
  133. if block == nil {
  134. fmt.Println("block not found")
  135. return otto.UndefinedValue()
  136. }
  137. old := vm.Debug
  138. vm.Debug = true
  139. _, err = js.ethereum.BlockProcessor().RetryProcess(block)
  140. if err != nil {
  141. glog.Infoln(err)
  142. }
  143. vm.Debug = old
  144. return otto.UndefinedValue()
  145. }
  146. func (js *jsre) setHead(call otto.FunctionCall) otto.Value {
  147. block, err := js.getBlock(call)
  148. if err != nil {
  149. fmt.Println(err)
  150. return otto.UndefinedValue()
  151. }
  152. if block == nil {
  153. fmt.Println("block not found")
  154. return otto.UndefinedValue()
  155. }
  156. js.ethereum.ChainManager().SetHead(block)
  157. return otto.UndefinedValue()
  158. }
  159. func (js *jsre) downloadProgress(call otto.FunctionCall) otto.Value {
  160. current, max := js.ethereum.Downloader().Stats()
  161. return js.re.ToVal(fmt.Sprintf("%d/%d", current, max))
  162. }
  163. func (js *jsre) getBlockRlp(call otto.FunctionCall) otto.Value {
  164. block, err := js.getBlock(call)
  165. if err != nil {
  166. fmt.Println(err)
  167. return otto.UndefinedValue()
  168. }
  169. if block == nil {
  170. fmt.Println("block not found")
  171. return otto.UndefinedValue()
  172. }
  173. encoded, _ := rlp.EncodeToBytes(block)
  174. return js.re.ToVal(fmt.Sprintf("%x", encoded))
  175. }
  176. func (js *jsre) setExtra(call otto.FunctionCall) otto.Value {
  177. extra, err := call.Argument(0).ToString()
  178. if err != nil {
  179. fmt.Println(err)
  180. return otto.UndefinedValue()
  181. }
  182. if len(extra) > 1024 {
  183. fmt.Println("error: cannot exceed 1024 bytes")
  184. return otto.UndefinedValue()
  185. }
  186. js.ethereum.Miner().SetExtra([]byte(extra))
  187. return otto.UndefinedValue()
  188. }
  189. func (js *jsre) hashrate(otto.FunctionCall) otto.Value {
  190. return js.re.ToVal(js.ethereum.Miner().HashRate())
  191. }
  192. func (js *jsre) backtrace(call otto.FunctionCall) otto.Value {
  193. tracestr, err := call.Argument(0).ToString()
  194. if err != nil {
  195. fmt.Println(err)
  196. return otto.UndefinedValue()
  197. }
  198. glog.GetTraceLocation().Set(tracestr)
  199. return otto.UndefinedValue()
  200. }
  201. func (js *jsre) verbosity(call otto.FunctionCall) otto.Value {
  202. v, err := call.Argument(0).ToInteger()
  203. if err != nil {
  204. fmt.Println(err)
  205. return otto.UndefinedValue()
  206. }
  207. glog.SetV(int(v))
  208. return otto.UndefinedValue()
  209. }
  210. func (js *jsre) startMining(call otto.FunctionCall) otto.Value {
  211. _, err := call.Argument(0).ToInteger()
  212. if err != nil {
  213. fmt.Println(err)
  214. return otto.FalseValue()
  215. }
  216. // threads now ignored
  217. err = js.ethereum.StartMining()
  218. if err != nil {
  219. fmt.Println(err)
  220. return otto.FalseValue()
  221. }
  222. return otto.TrueValue()
  223. }
  224. func (js *jsre) stopMining(call otto.FunctionCall) otto.Value {
  225. js.ethereum.StopMining()
  226. return otto.TrueValue()
  227. }
  228. func (js *jsre) startRPC(call otto.FunctionCall) otto.Value {
  229. addr, err := call.Argument(0).ToString()
  230. if err != nil {
  231. fmt.Println(err)
  232. return otto.FalseValue()
  233. }
  234. port, err := call.Argument(1).ToInteger()
  235. if err != nil {
  236. fmt.Println(err)
  237. return otto.FalseValue()
  238. }
  239. corsDomain := js.corsDomain
  240. if len(call.ArgumentList) > 2 {
  241. corsDomain, err = call.Argument(2).ToString()
  242. if err != nil {
  243. fmt.Println(err)
  244. return otto.FalseValue()
  245. }
  246. }
  247. config := rpc.RpcConfig{
  248. ListenAddress: addr,
  249. ListenPort: uint(port),
  250. CorsDomain: corsDomain,
  251. }
  252. xeth := xeth.New(js.ethereum, nil)
  253. err = rpc.Start(xeth, config)
  254. if err != nil {
  255. fmt.Printf(err.Error())
  256. return otto.FalseValue()
  257. }
  258. return otto.TrueValue()
  259. }
  260. func (js *jsre) stopRPC(call otto.FunctionCall) otto.Value {
  261. if rpc.Stop() == nil {
  262. return otto.TrueValue()
  263. }
  264. return otto.FalseValue()
  265. }
  266. func (js *jsre) addPeer(call otto.FunctionCall) otto.Value {
  267. nodeURL, err := call.Argument(0).ToString()
  268. if err != nil {
  269. fmt.Println(err)
  270. return otto.FalseValue()
  271. }
  272. err = js.ethereum.AddPeer(nodeURL)
  273. if err != nil {
  274. fmt.Println(err)
  275. return otto.FalseValue()
  276. }
  277. return otto.TrueValue()
  278. }
  279. func (js *jsre) unlock(call otto.FunctionCall) otto.Value {
  280. addr, err := call.Argument(0).ToString()
  281. if err != nil {
  282. fmt.Println(err)
  283. return otto.FalseValue()
  284. }
  285. seconds, err := call.Argument(2).ToInteger()
  286. if err != nil {
  287. fmt.Println(err)
  288. return otto.FalseValue()
  289. }
  290. arg := call.Argument(1)
  291. var passphrase string
  292. if arg.IsUndefined() {
  293. fmt.Println("Please enter a passphrase now.")
  294. passphrase, err = readPassword("Passphrase: ", true)
  295. if err != nil {
  296. utils.Fatalf("%v", err)
  297. }
  298. } else {
  299. passphrase, err = arg.ToString()
  300. if err != nil {
  301. fmt.Println(err)
  302. return otto.FalseValue()
  303. }
  304. }
  305. am := js.ethereum.AccountManager()
  306. err = am.TimedUnlock(common.FromHex(addr), passphrase, time.Duration(seconds)*time.Second)
  307. if err != nil {
  308. fmt.Printf("Unlock account failed '%v'\n", err)
  309. return otto.FalseValue()
  310. }
  311. return otto.TrueValue()
  312. }
  313. func (js *jsre) newAccount(call otto.FunctionCall) otto.Value {
  314. arg := call.Argument(0)
  315. var passphrase string
  316. if arg.IsUndefined() {
  317. fmt.Println("The new account will be encrypted with a passphrase.")
  318. fmt.Println("Please enter a passphrase now.")
  319. auth, err := readPassword("Passphrase: ", true)
  320. if err != nil {
  321. utils.Fatalf("%v", err)
  322. }
  323. confirm, err := readPassword("Repeat Passphrase: ", false)
  324. if err != nil {
  325. utils.Fatalf("%v", err)
  326. }
  327. if auth != confirm {
  328. utils.Fatalf("Passphrases did not match.")
  329. }
  330. passphrase = auth
  331. } else {
  332. var err error
  333. passphrase, err = arg.ToString()
  334. if err != nil {
  335. fmt.Println(err)
  336. return otto.FalseValue()
  337. }
  338. }
  339. acct, err := js.ethereum.AccountManager().NewAccount(passphrase)
  340. if err != nil {
  341. fmt.Printf("Could not create the account: %v", err)
  342. return otto.UndefinedValue()
  343. }
  344. return js.re.ToVal("0x" + common.Bytes2Hex(acct.Address))
  345. }
  346. func (js *jsre) nodeInfo(call otto.FunctionCall) otto.Value {
  347. return js.re.ToVal(js.ethereum.NodeInfo())
  348. }
  349. func (js *jsre) peers(call otto.FunctionCall) otto.Value {
  350. return js.re.ToVal(js.ethereum.PeersInfo())
  351. }
  352. func (js *jsre) importChain(call otto.FunctionCall) otto.Value {
  353. if len(call.ArgumentList) == 0 {
  354. fmt.Println("err: require file name")
  355. return otto.FalseValue()
  356. }
  357. fn, err := call.Argument(0).ToString()
  358. if err != nil {
  359. fmt.Println(err)
  360. return otto.FalseValue()
  361. }
  362. if err := utils.ImportChain(js.ethereum.ChainManager(), fn); err != nil {
  363. fmt.Println("Import error: ", err)
  364. return otto.FalseValue()
  365. }
  366. return otto.TrueValue()
  367. }
  368. func (js *jsre) exportChain(call otto.FunctionCall) otto.Value {
  369. if len(call.ArgumentList) == 0 {
  370. fmt.Println("err: require file name")
  371. return otto.FalseValue()
  372. }
  373. fn, err := call.Argument(0).ToString()
  374. if err != nil {
  375. fmt.Println(err)
  376. return otto.FalseValue()
  377. }
  378. if err := utils.ExportChain(js.ethereum.ChainManager(), fn); err != nil {
  379. fmt.Println(err)
  380. return otto.FalseValue()
  381. }
  382. return otto.TrueValue()
  383. }
  384. func (js *jsre) printBlock(call otto.FunctionCall) otto.Value {
  385. var block *types.Block
  386. if len(call.ArgumentList) > 0 {
  387. if call.Argument(0).IsNumber() {
  388. num, _ := call.Argument(0).ToInteger()
  389. block = js.ethereum.ChainManager().GetBlockByNumber(uint64(num))
  390. } else if call.Argument(0).IsString() {
  391. hash, _ := call.Argument(0).ToString()
  392. block = js.ethereum.ChainManager().GetBlock(common.HexToHash(hash))
  393. } else {
  394. fmt.Println("invalid argument for dump. Either hex string or number")
  395. }
  396. } else {
  397. block = js.ethereum.ChainManager().CurrentBlock()
  398. }
  399. if block == nil {
  400. fmt.Println("block not found")
  401. return otto.UndefinedValue()
  402. }
  403. fmt.Println(block)
  404. return otto.UndefinedValue()
  405. }
  406. func (js *jsre) dumpBlock(call otto.FunctionCall) otto.Value {
  407. var block *types.Block
  408. if len(call.ArgumentList) > 0 {
  409. if call.Argument(0).IsNumber() {
  410. num, _ := call.Argument(0).ToInteger()
  411. block = js.ethereum.ChainManager().GetBlockByNumber(uint64(num))
  412. } else if call.Argument(0).IsString() {
  413. hash, _ := call.Argument(0).ToString()
  414. block = js.ethereum.ChainManager().GetBlock(common.HexToHash(hash))
  415. } else {
  416. fmt.Println("invalid argument for dump. Either hex string or number")
  417. }
  418. } else {
  419. block = js.ethereum.ChainManager().CurrentBlock()
  420. }
  421. if block == nil {
  422. fmt.Println("block not found")
  423. return otto.UndefinedValue()
  424. }
  425. statedb := state.New(block.Root(), js.ethereum.StateDb())
  426. dump := statedb.RawDump()
  427. return js.re.ToVal(dump)
  428. }
  429. // internal transaction type which will allow us to resend transactions using `eth.resend`
  430. type tx struct {
  431. tx *types.Transaction
  432. To string
  433. From string
  434. Nonce string
  435. Value string
  436. Data string
  437. GasLimit string
  438. GasPrice string
  439. }
  440. func newTx(t *types.Transaction) *tx {
  441. from, _ := t.From()
  442. var to string
  443. if t := t.To(); t != nil {
  444. to = t.Hex()
  445. }
  446. return &tx{
  447. tx: t,
  448. To: to,
  449. From: from.Hex(),
  450. Value: t.Amount.String(),
  451. Nonce: strconv.Itoa(int(t.Nonce())),
  452. Data: "0x" + common.Bytes2Hex(t.Data()),
  453. GasLimit: t.GasLimit.String(),
  454. GasPrice: t.GasPrice().String(),
  455. }
  456. }