Guest User

Untitled

a guest
Feb 18th, 2018
154
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.57 KB | None | 0 0
  1. package blockchain
  2.  
  3. import (
  4. "context"
  5. "errors"
  6. "fmt"
  7. "log"
  8. "strconv"
  9.  
  10. "github.com/KyberNetwork/reserve-data/common"
  11. ether "github.com/ethereum/go-ethereum"
  12. "github.com/ethereum/go-ethereum/accounts/abi/bind"
  13. ethereum "github.com/ethereum/go-ethereum/common"
  14. "github.com/ethereum/go-ethereum/common/hexutil"
  15. "github.com/ethereum/go-ethereum/core/types"
  16. "github.com/ethereum/go-ethereum/ethclient"
  17. "github.com/ethereum/go-ethereum/rpc"
  18. "math/big"
  19. )
  20.  
  21. type tbindex struct {
  22. BulkIndex uint64
  23. IndexInBulk uint64
  24. }
  25.  
  26. const (
  27. FeeToWalletEvent string = "0x366bc34352215bf0bd3b527cfd6718605e1f5938777e42bcd8ed92f578368f52"
  28. BurnFeeEvent string = "0xf838f6ddc89706878e3c3e698e9b5cbfbf2c0e3d3dcd0bd2e00f1ccf313e0185"
  29. TradeEvent string = "0x1849bd6a030a1bca28b83437fd3de96f3d27a5d172fa7e9c78e7b61468928a39"
  30. )
  31.  
  32. type Blockchain struct {
  33. rpcClient *rpc.Client
  34. client *ethclient.Client
  35. wrapper *ContractWrapper
  36. pricing *Pricing
  37. reserve *ReserveContract
  38. rm ethereum.Address
  39. wrapperAddr ethereum.Address
  40. pricingAddr ethereum.Address
  41. burnerAddr ethereum.Address
  42. networkAddr ethereum.Address
  43. signer Signer
  44. tokens []common.Token
  45. tokenIndices map[string]tbindex
  46. nonce NonceCorpus
  47. rebroadcaster *Rebroadcaster
  48. }
  49.  
  50. func (self *Blockchain) AddToken(t common.Token) {
  51. self.tokens = append(self.tokens, t)
  52. }
  53.  
  54. func (self *Blockchain) GetAddresses() *common.Addresses {
  55. exs := map[common.ExchangeID]common.TokenAddresses{}
  56. for _, ex := range common.SupportedExchanges {
  57. exs[ex.ID()] = ex.TokenAddresses()
  58. }
  59. tokens := map[string]ethereum.Address{}
  60. for _, t := range self.tokens {
  61. tokens[t.ID] = ethereum.HexToAddress(t.Address)
  62. }
  63. return &common.Addresses{
  64. Tokens: tokens,
  65. Exchanges: exs,
  66. WrapperAddress: self.wrapperAddr,
  67. PricingAddress: self.pricingAddr,
  68. ReserveAddress: self.rm,
  69. FeeBurnerAddress: self.burnerAddr,
  70. NetworkAddress: self.networkAddr,
  71. }
  72. }
  73.  
  74. func (self *Blockchain) LoadAndSetTokenIndices() error {
  75. tokens := []ethereum.Address{}
  76. for _, tok := range self.tokens {
  77. if tok.ID != "ETH" {
  78. tokens = append(tokens, ethereum.HexToAddress(tok.Address))
  79. }
  80. }
  81. bulkIndices, indicesInBulk, err := self.wrapper.GetTokenIndicies(
  82. nil,
  83. self.pricingAddr,
  84. tokens,
  85. )
  86. if err != nil {
  87. log.Println(err)
  88. return err
  89. }
  90. self.tokenIndices = map[string]tbindex{}
  91.  
  92. for i, tok := range tokens {
  93. self.tokenIndices[tok.Hex()] = tbindex{
  94. bulkIndices[i].Uint64(),
  95. indicesInBulk[i].Uint64(),
  96. }
  97. }
  98.  
  99. for _, tok := range self.tokens {
  100. if tok.ID == "ETH" {
  101. eth := ethereum.HexToAddress(tok.Address)
  102. self.tokenIndices[eth.Hex()] = tbindex{0, 0}
  103. break
  104. }
  105. }
  106. log.Printf("Token indices: %+v", self.tokenIndices)
  107. return nil
  108. }
  109.  
  110. func (self *Blockchain) getTransactOpts() (*bind.TransactOpts, error) {
  111. shared := self.signer.GetTransactOpts()
  112. nonce, err := self.nonce.GetNextNonce()
  113. if err != nil {
  114. return nil, err
  115. } else {
  116. result := bind.TransactOpts{
  117. shared.From,
  118. nonce,
  119. shared.Signer,
  120. shared.Value,
  121. shared.GasPrice,
  122. shared.GasLimit,
  123. shared.Context,
  124. }
  125. return &result, nil
  126. }
  127. }
  128.  
  129. func toBlockNumArg(number *big.Int) string {
  130. if number == nil {
  131. return "latest"
  132. }
  133. return hexutil.EncodeBig(number)
  134. }
  135.  
  136. func toFilterArg(q ether.FilterQuery) interface{} {
  137. arg := map[string]interface{}{
  138. "fromBlock": toBlockNumArg(q.FromBlock),
  139. "toBlock": toBlockNumArg(q.ToBlock),
  140. "address": q.Addresses,
  141. "topics": q.Topics,
  142. }
  143. if q.FromBlock == nil {
  144. arg["fromBlock"] = "0x0"
  145. }
  146. return arg
  147. }
  148.  
  149. func (self *Blockchain) rebroadcast(tx *types.Transaction, err error) (ethereum.Hash, error) {
  150. failures, ok := self.rebroadcaster.Broadcast(tx)
  151. log.Printf("Rebroadcasting failures: %s", failures)
  152. if err != nil && !ok {
  153. log.Printf("Broadcasting transaction failed!!!!!!!, err: %s, retry failures: %s", err, failures)
  154. if tx != nil {
  155. return ethereum.Hash{}, errors.New(fmt.Sprintf("Broadcasting transaction %s failed, err: %s, retry failures: %s", tx.Hash().Hex(), err, failures))
  156. } else {
  157. return ethereum.Hash{}, errors.New(fmt.Sprintf("Broadcasting transaction failed, err: %s, retry failures: %s", err, failures))
  158. }
  159. } else {
  160. return tx.Hash(), err
  161. }
  162. }
  163.  
  164. //====================== Write calls ===============================
  165.  
  166. func (self *Blockchain) SetRates(
  167. tokens []ethereum.Address,
  168. buys []*big.Int,
  169. sells []*big.Int,
  170. block *big.Int) (ethereum.Hash, error) {
  171.  
  172. opts, err := self.getTransactOpts()
  173. // fix to 50.1 gwei
  174. opts.GasPrice = big.NewInt(50100000000)
  175. block.Add(block, big.NewInt(1))
  176. if err != nil {
  177. log.Printf("Getting transaction opts failed!!!!!!!\n")
  178. return ethereum.Hash{}, err
  179. } else {
  180. baseBuys, baseSells, compactBuys, compactSells, _, err := self.wrapper.GetTokenRates(
  181. nil, self.pricingAddr, tokens,
  182. )
  183. if err != nil {
  184. return ethereum.Hash{}, err
  185. }
  186. baseTokens := []ethereum.Address{}
  187. newBSells := []*big.Int{}
  188. newBBuys := []*big.Int{}
  189. newCSells := map[ethereum.Address]byte{}
  190. newCBuys := map[ethereum.Address]byte{}
  191. for i, token := range tokens {
  192. compactSell, overflow1 := BigIntToCompactRate(sells[i], baseSells[i])
  193. compactBuy, overflow2 := BigIntToCompactRate(buys[i], baseBuys[i])
  194. if overflow1 || overflow2 {
  195. baseTokens = append(baseTokens, token)
  196. newBSells = append(newBSells, compactSell.Base)
  197. newBBuys = append(newBBuys, compactBuy.Base)
  198. } else {
  199. if compactSell.Compact != byte(compactSells[i]) ||
  200. compactBuy.Compact != byte(compactBuys[i]) {
  201. newCSells[token] = compactSell.Compact
  202. newCBuys[token] = compactBuy.Compact
  203. }
  204. }
  205. }
  206. buys, sells, indices := BuildCompactBulk(
  207. newCBuys,
  208. newCSells,
  209. self.tokenIndices,
  210. )
  211. var tx *types.Transaction
  212. if len(baseTokens) > 0 {
  213. // set base tx
  214. tx, err = self.pricing.SetBaseRate(
  215. opts, baseTokens, newBBuys, newBSells,
  216. buys, sells, block, indices)
  217. // log.Printf("Setting base rates: tx(%s), err(%v) with baseTokens(%+v), basebuys(%+v), basesells(%+v), buys(%+v), sells(%+v), block(%s), indices(%+v)",
  218. // tx.Hash().Hex(), err, baseTokens, newBBuys, newBSells, buys, sells, block.Text(10), indices,
  219. // )
  220. } else {
  221. // update compact tx
  222. tx, err = self.pricing.SetCompactData(
  223. opts, buys, sells, block, indices)
  224. // log.Printf("Setting compact rates: tx(%s), err(%v) with basesells(%+v), buys(%+v), sells(%+v), block(%s), indices(%+v)",
  225. // tx.Hash().Hex(), err, baseTokens, buys, sells, block.Text(10), indices,
  226. // )
  227. }
  228. return self.rebroadcast(tx, err)
  229. }
  230. }
  231.  
  232. func (self *Blockchain) Send(
  233. token common.Token,
  234. amount *big.Int,
  235. dest ethereum.Address) (ethereum.Hash, error) {
  236.  
  237. opts, err := self.getTransactOpts()
  238. if err != nil {
  239. return ethereum.Hash{}, err
  240. } else {
  241. tx, err := self.reserve.Withdraw(
  242. opts,
  243. ethereum.HexToAddress(token.Address),
  244. amount, dest)
  245. return self.rebroadcast(tx, err)
  246. }
  247. }
  248.  
  249. func (self *Blockchain) SetImbalanceStepFunction(token ethereum.Address, xBuy []*big.Int, yBuy []*big.Int, xSell []*big.Int, ySell []*big.Int) (ethereum.Hash, error) {
  250. opts, err := self.getTransactOpts()
  251. if err != nil {
  252. log.Printf("Getting transaction opts failed!!!!!!!\n")
  253. return ethereum.Hash{}, err
  254. } else {
  255. tx, err := self.pricing.SetImbalanceStepFunction(opts, token, xBuy, yBuy, xSell, ySell)
  256. return self.rebroadcast(tx, err)
  257. }
  258. }
  259.  
  260. func (self *Blockchain) SetQtyStepFunction(token ethereum.Address, xBuy []*big.Int, yBuy []*big.Int, xSell []*big.Int, ySell []*big.Int) (ethereum.Hash, error) {
  261. opts, err := self.getTransactOpts()
  262. if err != nil {
  263. log.Printf("Getting transaction opts failed!!!!!!!\n")
  264. return ethereum.Hash{}, err
  265. } else {
  266. tx, err := self.pricing.SetQtyStepFunction(opts, token, xBuy, yBuy, xSell, ySell)
  267. return self.rebroadcast(tx, err)
  268. }
  269. }
  270.  
  271. //====================== Readonly calls ============================
  272. func (self *Blockchain) CurrentBlock() (uint64, error) {
  273. var blockno string
  274. err := self.rpcClient.Call(&blockno, "eth_blockNumber")
  275. if err != nil {
  276. return 0, err
  277. }
  278. result, err := strconv.ParseUint(blockno, 0, 64)
  279. return result, err
  280. }
  281.  
  282. func (self *Blockchain) TxStatus(hash ethereum.Hash) (string, error) {
  283. option := context.Background()
  284. _, pending, err := self.client.TransactionByHash(option, hash)
  285. if err == nil {
  286. // tx exist
  287. if pending {
  288. return "", nil
  289. } else {
  290. return "mined", nil
  291. }
  292. } else {
  293. if err == ether.NotFound {
  294. // tx doesn't exist. it failed
  295. return "lost", nil
  296. } else {
  297. // networking issue
  298. return "", err
  299. }
  300. }
  301. }
  302.  
  303. func (self *Blockchain) FetchBalanceData(reserve ethereum.Address, timepoint uint64) (map[string]common.BalanceEntry, error) {
  304. result := map[string]common.BalanceEntry{}
  305. tokens := []ethereum.Address{}
  306. for _, tok := range self.tokens {
  307. tokens = append(tokens, ethereum.HexToAddress(tok.Address))
  308. }
  309. timestamp := common.GetTimestamp()
  310. balances, err := self.wrapper.GetBalances(nil, reserve, tokens)
  311. returnTime := common.GetTimestamp()
  312. log.Printf("Fetcher ------> balances: %v, err: %s", balances, err)
  313. if err != nil {
  314. for tokenID, _ := range common.SupportedTokens {
  315. result[tokenID] = common.BalanceEntry{
  316. Valid: false,
  317. Error: err.Error(),
  318. Timestamp: timestamp,
  319. ReturnTime: returnTime,
  320. }
  321. }
  322. } else {
  323. for i, tok := range self.tokens {
  324. result[tok.ID] = common.BalanceEntry{
  325. Valid: true,
  326. Timestamp: timestamp,
  327. ReturnTime: returnTime,
  328. Balance: common.RawBalance(*balances[i]),
  329. }
  330. }
  331. }
  332. return result, nil
  333. }
  334.  
  335. func (self *Blockchain) FetchRates(timepoint uint64) (common.AllRateEntry, error) {
  336. result := common.AllRateEntry{}
  337. tokenAddrs := []ethereum.Address{}
  338. for _, s := range self.tokens {
  339. tokenAddrs = append(tokenAddrs, ethereum.HexToAddress(s.Address))
  340. }
  341. timestamp := common.GetTimestamp()
  342. baseBuys, baseSells, compactBuys, compactSells, blocks, err := self.wrapper.GetTokenRates(
  343. nil, self.pricingAddr, tokenAddrs,
  344. )
  345. returnTime := common.GetTimestamp()
  346. result.Timestamp = timestamp
  347. result.ReturnTime = returnTime
  348. if err != nil {
  349. result.Valid = false
  350. result.Error = err.Error()
  351. return result, err
  352. } else {
  353. result.Valid = true
  354. result.Data = map[string]common.RateEntry{}
  355. for i, token := range self.tokens {
  356. result.Data[token.ID] = common.RateEntry{
  357. baseBuys[i],
  358. int8(compactBuys[i]),
  359. baseSells[i],
  360. int8(compactSells[i]),
  361. blocks[i].Uint64(),
  362. }
  363. }
  364. return result, nil
  365. }
  366. }
  367.  
  368. func (self *Blockchain) GetPrice(token ethereum.Address, block *big.Int, priceType string, qty *big.Int) (*big.Int, error) {
  369. if priceType == "buy" {
  370. return self.pricing.GetRate(nil, token, block, true, qty)
  371. } else {
  372. return self.pricing.GetRate(nil, token, block, false, qty)
  373. }
  374. }
  375.  
  376. func (self *Blockchain) GetRawLogs(fromBlock uint64, toBlock uint64, timepoint uint64) ([]types.Log, error) {
  377. result := []types.Log{}
  378. var to *big.Int
  379. if toBlock != 0 {
  380. to = big.NewInt(int64(toBlock))
  381. }
  382. param := ether.FilterQuery{
  383. big.NewInt(int64(fromBlock)),
  384. to,
  385. []ethereum.Address{
  386. self.networkAddr,
  387. self.burnerAddr,
  388. },
  389. [][]ethereum.Hash{
  390. []ethereum.Hash{
  391. ethereum.HexToHash(TradeEvent),
  392. ethereum.HexToHash(BurnFeeEvent),
  393. ethereum.HexToHash(FeeToWalletEvent),
  394. },
  395. },
  396. }
  397. err := self.rpcClient.Call(&result, "eth_getLogs", toFilterArg(param))
  398. return result, err
  399. }
  400.  
  401. // return timestamp increasing array of trade log
  402. func (self *Blockchain) GetLogs(fromBlock uint64, timepoint uint64) ([]common.TradeLog, error) {
  403. result := []common.TradeLog{}
  404. // get all logs from fromBlock to best block
  405. logs, err := self.GetRawLogs(fromBlock, 0, timepoint)
  406. if err != nil {
  407. return result, err
  408. }
  409. var prevLog *types.Log
  410. var tradeLog *common.TradeLog
  411. for i, l := range logs {
  412. if l.Removed {
  413. log.Printf("Log is ignored because it is removed due to chain reorg")
  414. } else {
  415. if prevLog == nil || l.TxHash != prevLog.TxHash {
  416. if tradeLog != nil {
  417. result = append(result, *tradeLog)
  418. }
  419. // start new TradeLog
  420. tradeLog = &common.TradeLog{}
  421. tradeLog.BlockNumber = l.BlockNumber
  422. tradeLog.TransactionHash = l.TxHash
  423. tradeLog.TransactionIndex = l.TxIndex
  424. tradeLog.Timestamp, err = self.InterpretTimestamp(
  425. tradeLog.BlockNumber,
  426. tradeLog.TransactionIndex,
  427. )
  428. if err != nil {
  429. return result, err
  430. }
  431. }
  432. if len(l.Topics) == 0 {
  433. log.Printf("Getting empty zero topic list. This shouldn't happen and is Ethereum responsibility.")
  434. } else {
  435. topic := l.Topics[0]
  436. switch topic.Hex() {
  437. case FeeToWalletEvent:
  438. reserveAddr, walletAddr, walletFee := LogDataToFeeWalletParams(l.Data)
  439. tradeLog.ReserveAddress = reserveAddr
  440. tradeLog.WalletAddress = walletAddr
  441. tradeLog.WalletFee = walletFee.Big()
  442. case BurnFeeEvent:
  443. reserveAddr, burnFees := LogDataToBurnFeeParams(l.Data)
  444. tradeLog.ReserveAddress = reserveAddr
  445. tradeLog.BurnFee = burnFees.Big()
  446. case TradeEvent:
  447. srcAddr, destAddr, srcAmount, destAmount := LogDataToTradeParams(l.Data)
  448. tradeLog.SrcAddress = srcAddr
  449. tradeLog.DestAddress = destAddr
  450. tradeLog.SrcAmount = srcAmount.Big()
  451. tradeLog.DestAmount = destAmount.Big()
  452. }
  453. }
  454. prevLog = &logs[i]
  455. }
  456. }
  457. if tradeLog != nil {
  458. result = append(result, *tradeLog)
  459. }
  460. return result, nil
  461. }
  462.  
  463. // func (self *Blockchain) sendToken(token common.Token, amount *big.Int, address ethereum.Address) (ethereum.Hash, error) {
  464. // erc20, err := NewErc20Contract(
  465. // ethereum.HexToAddress(token.Address),
  466. // self.ethclient,
  467. // )
  468. // fmt.Printf("address: %s\n", token.Address)
  469. // if err != nil {
  470. // return ethereum.Hash{}, err
  471. // }
  472. // tx, err := erc20.Transfer(
  473. // self.signer.GetTransactOpts(),
  474. // address, amount)
  475. // if err != nil {
  476. // return ethereum.Hash{}, err
  477. // } else {
  478. // return tx.Hash(), nil
  479. // }
  480. // }
  481. //
  482. // func (self *Blockchain) sendETH(
  483. // amount *big.Int,
  484. // address ethereum.Address) (ethereum.Hash, error) {
  485. // // nonce, gasLimit, gasPrice gets from ethclient
  486. //
  487. // option := context.Background()
  488. // rm := self.signer.GetAddress()
  489. // nonce, err := self.ethclient.PendingNonceAt(
  490. // option, rm)
  491. // if err != nil {
  492. // return ethereum.Hash{}, err
  493. // }
  494. // gasLimit := big.NewInt(1000000)
  495. // gasPrice := big.NewInt(20000000000)
  496. // rawTx := types.NewTransaction(
  497. // nonce, address, amount, gasLimit, gasPrice, []byte{})
  498. // signedTx, err := self.signer.Sign(rm, rawTx)
  499. // if err != nil {
  500. // return ethereum.Hash{}, err
  501. // }
  502. // if err = self.ethclient.SendTransaction(option, signedTx); err != nil {
  503. // return ethereum.Hash{}, err
  504. // }
  505. // return signedTx.Hash(), nil
  506. // }
  507.  
  508. func NewBlockchain(
  509. client *rpc.Client,
  510. ethereum *ethclient.Client,
  511. clients map[string]*ethclient.Client,
  512. wrapperAddr, pricingAddr, burnerAddr, networkAddr, reserveAddr ethereum.Address,
  513. signer Signer, nonceCorpus NonceCorpus) (*Blockchain, error) {
  514. log.Printf("wrapper address: %s", wrapperAddr.Hex())
  515. wrapper, err := NewContractWrapper(wrapperAddr, ethereum)
  516. if err != nil {
  517. return nil, err
  518. }
  519. log.Printf("reserve owner address: %s", signer.GetAddress().Hex())
  520. log.Printf("reserve address: %s", reserveAddr.Hex())
  521. reserve, err := NewReserveContract(reserveAddr, ethereum)
  522. if err != nil {
  523. return nil, err
  524. }
  525. log.Printf("pricing address: %s", pricingAddr.Hex())
  526. pricing, err := NewPricing(pricingAddr, ethereum)
  527. if err != nil {
  528. return nil, err
  529. }
  530. log.Printf("burner address: %s", burnerAddr.Hex())
  531. log.Printf("network address: %s", networkAddr.Hex())
  532. return &Blockchain{
  533. rpcClient: client,
  534. client: ethereum,
  535. wrapper: wrapper,
  536. pricing: pricing,
  537. reserve: reserve,
  538. rm: reserveAddr,
  539. wrapperAddr: wrapperAddr,
  540. pricingAddr: pricingAddr,
  541. burnerAddr: burnerAddr,
  542. networkAddr: networkAddr,
  543. signer: signer,
  544. tokens: []common.Token{},
  545. nonce: nonceCorpus,
  546. rebroadcaster: NewRebroadcaster(clients),
  547. }, nil
  548. }
Add Comment
Please, Sign In to add comment