api.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. package rpc
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "math/big"
  6. "strings"
  7. "sync"
  8. "time"
  9. "github.com/ethereum/go-ethereum/core"
  10. "github.com/ethereum/go-ethereum/core/types"
  11. "github.com/ethereum/go-ethereum/crypto"
  12. "github.com/ethereum/go-ethereum/ethdb"
  13. "github.com/ethereum/go-ethereum/ethutil"
  14. "github.com/ethereum/go-ethereum/event"
  15. "github.com/ethereum/go-ethereum/event/filter"
  16. "github.com/ethereum/go-ethereum/state"
  17. "github.com/ethereum/go-ethereum/ui"
  18. "github.com/ethereum/go-ethereum/xeth"
  19. )
  20. var (
  21. defaultGasPrice = big.NewInt(10000000000000)
  22. defaultGas = big.NewInt(10000)
  23. filterTickerTime = 15 * time.Second
  24. )
  25. type EthereumApi struct {
  26. eth *xeth.XEth
  27. xethMu sync.RWMutex
  28. mux *event.TypeMux
  29. quit chan struct{}
  30. filterManager *filter.FilterManager
  31. logMut sync.RWMutex
  32. logs map[int]*logFilter
  33. messagesMut sync.RWMutex
  34. messages map[int]*whisperFilter
  35. // Register keeps a list of accounts and transaction data
  36. regmut sync.Mutex
  37. register map[string][]*NewTxArgs
  38. db ethutil.Database
  39. // defaultBlockAge int64
  40. }
  41. func NewEthereumApi(eth *xeth.XEth) *EthereumApi {
  42. db, _ := ethdb.NewLDBDatabase("dapps")
  43. api := &EthereumApi{
  44. eth: eth,
  45. mux: eth.Backend().EventMux(),
  46. quit: make(chan struct{}),
  47. filterManager: filter.NewFilterManager(eth.Backend().EventMux()),
  48. logs: make(map[int]*logFilter),
  49. messages: make(map[int]*whisperFilter),
  50. db: db,
  51. // defaultBlockAge: -1,
  52. }
  53. go api.filterManager.Start()
  54. go api.start()
  55. return api
  56. }
  57. // func (self *EthereumApi) setStateByBlockNumber(num int64) {
  58. // chain := self.xeth().Backend().ChainManager()
  59. // var block *types.Block
  60. // if self.defaultBlockAge < 0 {
  61. // num = chain.CurrentBlock().Number().Int64() + num + 1
  62. // }
  63. // block = chain.GetBlockByNumber(uint64(num))
  64. // if block != nil {
  65. // self.useState(state.New(block.Root(), self.xeth().Backend().Db()))
  66. // } else {
  67. // self.useState(chain.State())
  68. // }
  69. // }
  70. func (self *EthereumApi) start() {
  71. timer := time.NewTicker(filterTickerTime)
  72. // events := self.mux.Subscribe(core.ChainEvent{})
  73. done:
  74. for {
  75. select {
  76. // case ev := <-events.Chan():
  77. // switch ev.(type) {
  78. // case core.ChainEvent:
  79. // if self.defaultBlockAge < 0 {
  80. // self.setStateByBlockNumber(self.defaultBlockAge)
  81. // }
  82. // }
  83. case <-timer.C:
  84. self.logMut.Lock()
  85. self.messagesMut.Lock()
  86. for id, filter := range self.logs {
  87. if time.Since(filter.timeout) > 20*time.Second {
  88. self.filterManager.UninstallFilter(id)
  89. delete(self.logs, id)
  90. }
  91. }
  92. for id, filter := range self.messages {
  93. if time.Since(filter.timeout) > 20*time.Second {
  94. self.xeth().Whisper().Unwatch(id)
  95. delete(self.messages, id)
  96. }
  97. }
  98. self.logMut.Unlock()
  99. self.messagesMut.Unlock()
  100. case <-self.quit:
  101. break done
  102. }
  103. }
  104. }
  105. func (self *EthereumApi) stop() {
  106. close(self.quit)
  107. }
  108. // func (self *EthereumApi) Register(args string, reply *interface{}) error {
  109. // self.regmut.Lock()
  110. // defer self.regmut.Unlock()
  111. // if _, ok := self.register[args]; ok {
  112. // self.register[args] = nil // register with empty
  113. // }
  114. // return nil
  115. // }
  116. // func (self *EthereumApi) Unregister(args string, reply *interface{}) error {
  117. // self.regmut.Lock()
  118. // defer self.regmut.Unlock()
  119. // delete(self.register, args)
  120. // return nil
  121. // }
  122. // func (self *EthereumApi) WatchTx(args string, reply *interface{}) error {
  123. // self.regmut.Lock()
  124. // defer self.regmut.Unlock()
  125. // txs := self.register[args]
  126. // self.register[args] = nil
  127. // *reply = txs
  128. // return nil
  129. // }
  130. func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) error {
  131. var id int
  132. filter := core.NewFilter(self.xeth().Backend())
  133. filter.SetOptions(toFilterOptions(args))
  134. filter.LogsCallback = func(logs state.Logs) {
  135. self.logMut.Lock()
  136. defer self.logMut.Unlock()
  137. self.logs[id].add(logs...)
  138. }
  139. id = self.filterManager.InstallFilter(filter)
  140. self.logs[id] = &logFilter{timeout: time.Now()}
  141. *reply = id
  142. return nil
  143. }
  144. func (self *EthereumApi) UninstallFilter(id int, reply *interface{}) error {
  145. delete(self.logs, id)
  146. self.filterManager.UninstallFilter(id)
  147. *reply = true
  148. return nil
  149. }
  150. func (self *EthereumApi) NewFilterString(args string, reply *interface{}) error {
  151. var id int
  152. filter := core.NewFilter(self.xeth().Backend())
  153. callback := func(block *types.Block) {
  154. self.logMut.Lock()
  155. defer self.logMut.Unlock()
  156. self.logs[id].add(&state.StateLog{})
  157. }
  158. if args == "pending" {
  159. filter.PendingCallback = callback
  160. } else if args == "chain" {
  161. filter.BlockCallback = callback
  162. }
  163. id = self.filterManager.InstallFilter(filter)
  164. self.logs[id] = &logFilter{timeout: time.Now()}
  165. *reply = id
  166. return nil
  167. }
  168. func (self *EthereumApi) FilterChanged(id int, reply *interface{}) error {
  169. self.logMut.Lock()
  170. defer self.logMut.Unlock()
  171. if self.logs[id] != nil {
  172. *reply = toLogs(self.logs[id].get())
  173. }
  174. return nil
  175. }
  176. func (self *EthereumApi) Logs(id int, reply *interface{}) error {
  177. self.logMut.Lock()
  178. defer self.logMut.Unlock()
  179. filter := self.filterManager.GetFilter(id)
  180. if filter != nil {
  181. *reply = toLogs(filter.Find())
  182. }
  183. return nil
  184. }
  185. func (self *EthereumApi) AllLogs(args *FilterOptions, reply *interface{}) error {
  186. filter := core.NewFilter(self.xeth().Backend())
  187. filter.SetOptions(toFilterOptions(args))
  188. *reply = toLogs(filter.Find())
  189. return nil
  190. }
  191. func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error {
  192. if args.Gas == ethutil.Big0 {
  193. args.Gas = defaultGas
  194. }
  195. if args.GasPrice == ethutil.Big0 {
  196. args.GasPrice = defaultGasPrice
  197. }
  198. // TODO if no_private_key then
  199. //if _, exists := p.register[args.From]; exists {
  200. // p.register[args.From] = append(p.register[args.From], args)
  201. //} else {
  202. /*
  203. account := accounts.Get(fromHex(args.From))
  204. if account != nil {
  205. if account.Unlocked() {
  206. if !unlockAccount(account) {
  207. return
  208. }
  209. }
  210. result, _ := account.Transact(fromHex(args.To), fromHex(args.Value), fromHex(args.Gas), fromHex(args.GasPrice), fromHex(args.Data))
  211. if len(result) > 0 {
  212. *reply = toHex(result)
  213. }
  214. } else if _, exists := p.register[args.From]; exists {
  215. p.register[ags.From] = append(p.register[args.From], args)
  216. }
  217. */
  218. result, err := p.xeth().Transact( /* TODO specify account */ args.To, args.Value.String(), args.Gas.String(), args.GasPrice.String(), args.Data)
  219. if err != nil {
  220. return err
  221. }
  222. *reply = result
  223. //}
  224. return nil
  225. }
  226. func (p *EthereumApi) Call(args *NewTxArgs, reply *interface{}) error {
  227. result, err := p.xeth().Call( /* TODO specify account */ args.To, args.Value.String(), args.Gas.String(), args.GasPrice.String(), args.Data)
  228. if err != nil {
  229. return err
  230. }
  231. *reply = result
  232. return nil
  233. }
  234. func (p *EthereumApi) GetBalance(args *GetBalanceArgs, reply *interface{}) error {
  235. if err := args.requirements(); err != nil {
  236. return err
  237. }
  238. state := p.xeth().State().SafeGet(args.Address)
  239. *reply = toHex(state.Balance().Bytes())
  240. return nil
  241. }
  242. func (p *EthereumApi) GetStorage(args *GetStorageArgs, reply *interface{}) error {
  243. if err := args.requirements(); err != nil {
  244. return err
  245. }
  246. *reply = p.xeth().State().SafeGet(args.Address).Storage()
  247. return nil
  248. }
  249. func (p *EthereumApi) GetStorageAt(args *GetStorageAtArgs, reply *interface{}) error {
  250. if err := args.requirements(); err != nil {
  251. return err
  252. }
  253. state := p.xeth().State().SafeGet(args.Address)
  254. value := state.StorageString(args.Key)
  255. var hx string
  256. if strings.Index(args.Key, "0x") == 0 {
  257. hx = string([]byte(args.Key)[2:])
  258. } else {
  259. // Convert the incoming string (which is a bigint) into hex
  260. i, _ := new(big.Int).SetString(args.Key, 10)
  261. hx = ethutil.Bytes2Hex(i.Bytes())
  262. }
  263. rpclogger.Debugf("GetStateAt(%s, %s)\n", args.Address, hx)
  264. *reply = map[string]string{args.Key: value.Str()}
  265. return nil
  266. }
  267. func (p *EthereumApi) GetTxCountAt(args *GetTxCountArgs, reply *interface{}) error {
  268. err := args.requirements()
  269. if err != nil {
  270. return err
  271. }
  272. *reply = p.xeth().TxCountAt(args.Address)
  273. return nil
  274. }
  275. func (p *EthereumApi) GetData(args *GetDataArgs, reply *interface{}) error {
  276. if err := args.requirements(); err != nil {
  277. return err
  278. }
  279. *reply = p.xeth().CodeAt(args.Address)
  280. return nil
  281. }
  282. func (p *EthereumApi) GetCompilers(reply *interface{}) error {
  283. c := []string{"serpent"}
  284. *reply = c
  285. return nil
  286. }
  287. func (p *EthereumApi) CompileSerpent(args *CompileArgs, reply *interface{}) error {
  288. res, err := ethutil.Compile(args.Source, false)
  289. if err != nil {
  290. return err
  291. }
  292. *reply = res
  293. return nil
  294. }
  295. func (p *EthereumApi) DbPut(args *DbArgs, reply *interface{}) error {
  296. if err := args.requirements(); err != nil {
  297. return err
  298. }
  299. p.db.Put([]byte(args.Database+args.Key), []byte(args.Value))
  300. *reply = true
  301. return nil
  302. }
  303. func (p *EthereumApi) DbGet(args *DbArgs, reply *interface{}) error {
  304. if err := args.requirements(); err != nil {
  305. return err
  306. }
  307. res, _ := p.db.Get([]byte(args.Database + args.Key))
  308. *reply = string(res)
  309. return nil
  310. }
  311. func (p *EthereumApi) NewWhisperIdentity(reply *interface{}) error {
  312. *reply = p.xeth().Whisper().NewIdentity()
  313. return nil
  314. }
  315. func (p *EthereumApi) NewWhisperFilter(args *WhisperFilterArgs, reply *interface{}) error {
  316. var id int
  317. opts := new(xeth.Options)
  318. opts.From = args.From
  319. opts.To = args.To
  320. opts.Topics = args.Topics
  321. opts.Fn = func(msg xeth.WhisperMessage) {
  322. p.messagesMut.Lock()
  323. defer p.messagesMut.Unlock()
  324. p.messages[id].add(msg) // = append(p.messages[id], msg)
  325. }
  326. id = p.xeth().Whisper().Watch(opts)
  327. p.messages[id] = &whisperFilter{timeout: time.Now()}
  328. *reply = id
  329. return nil
  330. }
  331. func (self *EthereumApi) MessagesChanged(id int, reply *interface{}) error {
  332. self.messagesMut.Lock()
  333. defer self.messagesMut.Unlock()
  334. if self.messages[id] != nil {
  335. *reply = self.messages[id].get()
  336. }
  337. return nil
  338. }
  339. func (p *EthereumApi) WhisperPost(args *WhisperMessageArgs, reply *interface{}) error {
  340. err := p.xeth().Whisper().Post(args.Payload, args.To, args.From, args.Topic, args.Priority, args.Ttl)
  341. if err != nil {
  342. return err
  343. }
  344. *reply = true
  345. return nil
  346. }
  347. func (p *EthereumApi) HasWhisperIdentity(args string, reply *interface{}) error {
  348. *reply = p.xeth().Whisper().HasIdentity(args)
  349. return nil
  350. }
  351. func (p *EthereumApi) WhisperMessages(id int, reply *interface{}) error {
  352. *reply = p.xeth().Whisper().Messages(id)
  353. return nil
  354. }
  355. func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error {
  356. // Spec at https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC
  357. rpclogger.DebugDetailf("%T %s", req.Params, req.Params)
  358. switch req.Method {
  359. case "web3_sha3":
  360. args := new(Sha3Args)
  361. if err := json.Unmarshal(req.Params, &args); err != nil {
  362. return err
  363. }
  364. *reply = toHex(crypto.Sha3(fromHex(args.Data)))
  365. case "net_listening":
  366. *reply = p.xeth().IsListening()
  367. case "net_peerCount":
  368. *reply = toHex(big.NewInt(int64(p.xeth().PeerCount())).Bytes())
  369. case "eth_coinbase":
  370. *reply = p.xeth().Coinbase()
  371. case "eth_mining":
  372. *reply = p.xeth().IsMining()
  373. case "eth_gasPrice":
  374. *reply = toHex(defaultGasPrice.Bytes())
  375. case "eth_accounts":
  376. *reply = p.xeth().Accounts()
  377. case "eth_blockNumber":
  378. *reply = toHex(p.xeth().Backend().ChainManager().CurrentBlock().Number().Bytes())
  379. case "eth_getBalance":
  380. // TODO handle BlockNumber
  381. args := new(GetBalanceArgs)
  382. if err := json.Unmarshal(req.Params, &args); err != nil {
  383. return err
  384. }
  385. return p.GetBalance(args, reply)
  386. case "eth_getStorage":
  387. // TODO handle BlockNumber
  388. args := new(GetStorageArgs)
  389. if err := json.Unmarshal(req.Params, &args); err != nil {
  390. return err
  391. }
  392. return p.GetStorage(args, reply)
  393. case "eth_getStorageAt":
  394. // TODO handle BlockNumber
  395. args := new(GetStorageAtArgs)
  396. if err := json.Unmarshal(req.Params, &args); err != nil {
  397. return err
  398. }
  399. return p.GetStorageAt(args, reply)
  400. case "eth_getTransactionCount":
  401. // TODO handle BlockNumber
  402. args := new(GetTxCountArgs)
  403. if err := json.Unmarshal(req.Params, &args); err != nil {
  404. return err
  405. }
  406. return p.GetTxCountAt(args, reply)
  407. case "eth_getBlockTransactionCountByHash":
  408. case "eth_getBlockTransactionCountByNumber":
  409. case "eth_getUncleCountByBlockHash":
  410. case "eth_getUncleCountByBlockNumber":
  411. return errNotImplemented
  412. case "eth_getData":
  413. // TODO handle BlockNumber
  414. args := new(GetDataArgs)
  415. if err := json.Unmarshal(req.Params, &args); err != nil {
  416. return err
  417. }
  418. return p.GetData(args, reply)
  419. case "eth_sendTransaction":
  420. args := new(NewTxArgs)
  421. if err := json.Unmarshal(req.Params, &args); err != nil {
  422. return err
  423. }
  424. return p.Transact(args, reply)
  425. case "eth_call":
  426. args := new(NewTxArgs)
  427. if err := json.Unmarshal(req.Params, &args); err != nil {
  428. return err
  429. }
  430. return p.Call(args, reply)
  431. case "eth_flush":
  432. return errNotImplemented
  433. case "eth_getBlockByHash":
  434. // TODO handle second param for "include transaction objects"
  435. args := new(GetBlockByHashArgs)
  436. if err := json.Unmarshal(req.Params, &args); err != nil {
  437. return err
  438. }
  439. *reply = p.xeth().BlockByHash(args.BlockHash)
  440. case "eth_getBlockByNumber":
  441. // TODO handle second param for "include transaction objects"
  442. args := new(GetBlockByNumberArgs)
  443. if err := json.Unmarshal(req.Params, &args); err != nil {
  444. return err
  445. }
  446. *reply = p.xeth().BlockByNumber(args.BlockNumber)
  447. case "eth_getTransactionByHash":
  448. case "eth_getTransactionByBlockHashAndIndex":
  449. case "eth_getTransactionByBlockNumberAndIndex":
  450. case "eth_getUncleByBlockHashAndIndex":
  451. case "eth_getUncleByBlockNumberAndIndex":
  452. return errNotImplemented
  453. case "eth_getCompilers":
  454. return p.GetCompilers(reply)
  455. case "eth_compileSolidity":
  456. case "eth_compileLLL":
  457. return errNotImplemented
  458. case "eth_compileSerpent":
  459. args := new(CompileArgs)
  460. if err := json.Unmarshal(req.Params, &args); err != nil {
  461. return err
  462. }
  463. return p.CompileSerpent(args, reply)
  464. case "eth_newFilter":
  465. args := new(FilterOptions)
  466. if err := json.Unmarshal(req.Params, &args); err != nil {
  467. return err
  468. }
  469. return p.NewFilter(args, reply)
  470. case "eth_newBlockFilter":
  471. args := new(FilterStringArgs)
  472. if err := json.Unmarshal(req.Params, &args); err != nil {
  473. return err
  474. }
  475. return p.NewFilterString(args.Word, reply)
  476. case "eth_uninstallFilter":
  477. args := new(FilterIdArgs)
  478. if err := json.Unmarshal(req.Params, &args); err != nil {
  479. return err
  480. }
  481. return p.UninstallFilter(args.Id, reply)
  482. case "eth_getFilterChanges":
  483. args := new(FilterIdArgs)
  484. if err := json.Unmarshal(req.Params, &args); err != nil {
  485. return err
  486. }
  487. return p.FilterChanged(args.Id, reply)
  488. case "eth_getFilterLogs":
  489. args := new(FilterIdArgs)
  490. if err := json.Unmarshal(req.Params, &args); err != nil {
  491. return err
  492. }
  493. return p.Logs(args.Id, reply)
  494. case "eth_getLogs":
  495. args := new(FilterOptions)
  496. if err := json.Unmarshal(req.Params, &args); err != nil {
  497. return err
  498. }
  499. return p.AllLogs(args, reply)
  500. case "eth_getWork":
  501. case "eth_submitWork":
  502. return errNotImplemented
  503. case "db_put":
  504. args := new(DbArgs)
  505. if err := json.Unmarshal(req.Params, &args); err != nil {
  506. return err
  507. }
  508. return p.DbPut(args, reply)
  509. case "db_get":
  510. args := new(DbArgs)
  511. if err := json.Unmarshal(req.Params, &args); err != nil {
  512. return err
  513. }
  514. return p.DbGet(args, reply)
  515. case "shh_post":
  516. args := new(WhisperMessageArgs)
  517. if err := json.Unmarshal(req.Params, &args); err != nil {
  518. return err
  519. }
  520. return p.WhisperPost(args, reply)
  521. case "shh_newIdentity":
  522. return p.NewWhisperIdentity(reply)
  523. case "shh_hasIdentity":
  524. args := new(WhisperIdentityArgs)
  525. if err := json.Unmarshal(req.Params, &args); err != nil {
  526. return err
  527. }
  528. return p.HasWhisperIdentity(args.Identity, reply)
  529. case "shh_newGroup":
  530. case "shh_addToGroup":
  531. return errNotImplemented
  532. case "shh_newFilter":
  533. args := new(WhisperFilterArgs)
  534. if err := json.Unmarshal(req.Params, &args); err != nil {
  535. return err
  536. }
  537. return p.NewWhisperFilter(args, reply)
  538. case "shh_uninstallFilter":
  539. return errNotImplemented
  540. case "shh_getFilterChanges":
  541. args := new(FilterIdArgs)
  542. if err := json.Unmarshal(req.Params, &args); err != nil {
  543. return err
  544. }
  545. return p.MessagesChanged(args.Id, reply)
  546. case "shh_getMessages":
  547. args := new(FilterIdArgs)
  548. if err := json.Unmarshal(req.Params, &args); err != nil {
  549. return err
  550. }
  551. return p.WhisperMessages(args.Id, reply)
  552. case "client_version":
  553. *reply = p.eth.GetClientVersion()
  554. // case "eth_register":
  555. // args, err := req.ToRegisterArgs()
  556. // if err != nil {
  557. // return err
  558. // }
  559. // return p.Register(args, reply)
  560. // case "eth_unregister":
  561. // args, err := req.ToRegisterArgs()
  562. // if err != nil {
  563. // return err
  564. // }
  565. // return p.Unregister(args, reply)
  566. // case "eth_watchTx":
  567. // args, err := req.ToWatchTxArgs()
  568. // if err != nil {
  569. // return err
  570. // }
  571. // return p.WatchTx(args, reply)
  572. default:
  573. return NewErrorWithMessage(errNotImplemented, req.Method)
  574. }
  575. rpclogger.DebugDetailf("Reply: %T %s", reply, reply)
  576. return nil
  577. }
  578. func (self *EthereumApi) xeth() *xeth.XEth {
  579. self.xethMu.RLock()
  580. defer self.xethMu.RUnlock()
  581. return self.eth
  582. }
  583. func (self *EthereumApi) useState(statedb *state.StateDB) {
  584. self.xethMu.Lock()
  585. defer self.xethMu.Unlock()
  586. self.eth = self.eth.UseState(statedb)
  587. }
  588. func t(f ui.Frontend) {
  589. // Call the password dialog
  590. ret, err := f.Call("PasswordDialog")
  591. if err != nil {
  592. fmt.Println(err)
  593. }
  594. // Get the first argument
  595. t, _ := ret.Get(0)
  596. fmt.Println("return:", t)
  597. }
  598. func toFilterOptions(options *FilterOptions) core.FilterOptions {
  599. var opts core.FilterOptions
  600. // Convert optional address slice/string to byte slice
  601. if str, ok := options.Address.(string); ok {
  602. opts.Address = [][]byte{fromHex(str)}
  603. } else if slice, ok := options.Address.([]interface{}); ok {
  604. bslice := make([][]byte, len(slice))
  605. for i, addr := range slice {
  606. if saddr, ok := addr.(string); ok {
  607. bslice[i] = fromHex(saddr)
  608. }
  609. }
  610. opts.Address = bslice
  611. }
  612. opts.Earliest = options.Earliest
  613. opts.Latest = options.Latest
  614. opts.Topics = make([][]byte, len(options.Topic))
  615. for i, topic := range options.Topic {
  616. opts.Topics[i] = fromHex(topic)
  617. }
  618. return opts
  619. }