You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

573 lines
14 KiB

Update missing parts, improve til, and more - Node - Updated configuration to initialize the interface to all the smart contracts - Common - Moved BlockData and BatchData types to common so that they can be shared among: historydb, til and synchronizer - Remove hash.go (it was never used) - Remove slot.go (it was never used) - Remove smartcontractparams.go (it was never used, and appropriate structs are defined in `eth/`) - Comment state / status method until requirements of this method are properly defined, and move it to Synchronizer - Synchronizer - Simplify `Sync` routine to only sync one block per call, and return useful information. - Use BlockData and BatchData from common - Check that events belong to the expected block hash - In L1Batch, query L1UserTxs from HistoryDB - Fill ERC20 token information - Test AddTokens with test.Client - HistryDB - Use BlockData and BatchData from common - Add `GetAllTokens` method - Uncomment and update GetL1UserTxs (with corresponding tests) - Til - Rename all instances of RegisterToken to AddToken (to follow the smart contract implementation naming) - Use BlockData and BatchData from common - Move testL1CoordinatorTxs and testL2Txs to a separate struct from BatchData in Context - Start Context with BatchNum = 1 (which the protocol defines to be the first batchNum) - In every Batch, set StateRoot and ExitRoot to a non-nil big.Int (zero). - In all L1Txs, if LoadAmount is not used, set it to 0; if Amount is not used, set it to 0; so that no *big.Int is nil. - In L1UserTx, don't set BatchNum, because when L1UserTxs are created and obtained by the synchronizer, the BatchNum is not known yet (it's a synchronizer job to set it) - In L1UserTxs, set `UserOrigin` and set `ToForgeL1TxsNum`.
4 years ago
  1. package til
  2. import (
  3. "bufio"
  4. "bytes"
  5. "fmt"
  6. "io"
  7. "math/big"
  8. "sort"
  9. "strconv"
  10. "github.com/hermeznetwork/hermez-node/common"
  11. "github.com/hermeznetwork/hermez-node/log"
  12. "github.com/hermeznetwork/tracerr"
  13. )
  14. var eof = rune(0)
  15. var errof = fmt.Errorf("eof in parseline")
  16. var commentLine = fmt.Errorf("comment in parseline") //nolint:golint
  17. var newEventLine = fmt.Errorf("newEventLine") //nolint:golint
  18. var setTypeLine = fmt.Errorf("setTypeLine") //nolint:golint
  19. // setType defines the type of the set
  20. type setType string
  21. // SetTypeBlockchain defines the type 'Blockchain' of the set
  22. var SetTypeBlockchain = setType("Blockchain")
  23. // SetTypePoolL2 defines the type 'PoolL2' of the set
  24. var SetTypePoolL2 = setType("PoolL2")
  25. // TypeNewBatch is used for testing purposes only, and represents the
  26. // common.TxType of a new batch
  27. var TypeNewBatch common.TxType = "InstrTypeNewBatch"
  28. // TypeNewBatchL1 is used for testing purposes only, and represents the
  29. // common.TxType of a new batch
  30. var TypeNewBatchL1 common.TxType = "InstrTypeNewBatchL1"
  31. // TypeNewBlock is used for testing purposes only, and represents the
  32. // common.TxType of a new ethereum block
  33. var TypeNewBlock common.TxType = "InstrTypeNewBlock"
  34. // TypeAddToken is used for testing purposes only, and represents the
  35. // common.TxType of a new Token regsitration.
  36. // It has 'nolint:gosec' as the string 'Token' triggers gosec as a potential
  37. // leaked Token (which is not the case).
  38. var TypeAddToken common.TxType = "InstrTypeAddToken" //nolint:gosec
  39. // TxTypeCreateAccountDepositCoordinator is used for testing purposes only,
  40. // and represents the common.TxType of a create acount deposit made by the
  41. // coordinator
  42. var TxTypeCreateAccountDepositCoordinator common.TxType = "TypeCreateAccountDepositCoordinator"
  43. //nolint
  44. const (
  45. ILLEGAL token = iota
  46. WS
  47. EOF
  48. IDENT // val
  49. )
  50. // Instruction is the data structure that represents one line of code
  51. type Instruction struct {
  52. LineNum int
  53. Literal string
  54. From string
  55. To string
  56. Amount *big.Int
  57. DepositAmount *big.Int
  58. Fee uint8
  59. TokenID common.TokenID
  60. Typ common.TxType // D: Deposit, T: Transfer, E: ForceExit
  61. }
  62. // parsedSet contains the full Set of Instructions representing a full code
  63. type parsedSet struct {
  64. typ setType
  65. instructions []Instruction
  66. users []string
  67. }
  68. func (i Instruction) String() string {
  69. buf := bytes.NewBufferString("")
  70. fmt.Fprintf(buf, "Type: %s, ", i.Typ)
  71. fmt.Fprintf(buf, "From: %s, ", i.From)
  72. if i.Typ == common.TxTypeTransfer ||
  73. i.Typ == common.TxTypeDepositTransfer ||
  74. i.Typ == common.TxTypeCreateAccountDepositTransfer {
  75. fmt.Fprintf(buf, "To: %s, ", i.To)
  76. }
  77. if i.Typ == common.TxTypeDeposit ||
  78. i.Typ == common.TxTypeDepositTransfer ||
  79. i.Typ == common.TxTypeCreateAccountDepositTransfer {
  80. fmt.Fprintf(buf, "DepositAmount: %d, ", i.DepositAmount)
  81. }
  82. if i.Typ != common.TxTypeDeposit {
  83. fmt.Fprintf(buf, "Amount: %d, ", i.Amount)
  84. }
  85. if i.Typ == common.TxTypeTransfer ||
  86. i.Typ == common.TxTypeDepositTransfer ||
  87. i.Typ == common.TxTypeCreateAccountDepositTransfer {
  88. fmt.Fprintf(buf, "Fee: %d, ", i.Fee)
  89. }
  90. fmt.Fprintf(buf, "TokenID: %d\n", i.TokenID)
  91. return buf.String()
  92. }
  93. // Raw returns a string with the raw representation of the Instruction
  94. func (i Instruction) raw() string {
  95. buf := bytes.NewBufferString("")
  96. fmt.Fprintf(buf, "%s", i.Typ)
  97. fmt.Fprintf(buf, "(%d)", i.TokenID)
  98. fmt.Fprintf(buf, "%s", i.From)
  99. if i.Typ == common.TxTypeTransfer ||
  100. i.Typ == common.TxTypeDepositTransfer ||
  101. i.Typ == common.TxTypeCreateAccountDepositTransfer {
  102. fmt.Fprintf(buf, "-%s", i.To)
  103. }
  104. fmt.Fprintf(buf, ":")
  105. if i.Typ == common.TxTypeDeposit ||
  106. i.Typ == common.TxTypeDepositTransfer ||
  107. i.Typ == common.TxTypeCreateAccountDepositTransfer {
  108. fmt.Fprintf(buf, "%d", i.DepositAmount)
  109. }
  110. if i.Typ != common.TxTypeDeposit {
  111. fmt.Fprintf(buf, "%d", i.Amount)
  112. }
  113. if i.Typ == common.TxTypeTransfer {
  114. fmt.Fprintf(buf, "(%d)", i.Fee)
  115. }
  116. return buf.String()
  117. }
  118. type token int
  119. type scanner struct {
  120. r *bufio.Reader
  121. }
  122. func isWhitespace(ch rune) bool {
  123. return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '\v' || ch == '\f'
  124. }
  125. func isLetter(ch rune) bool {
  126. return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
  127. }
  128. func isComment(ch rune) bool {
  129. return ch == '/'
  130. }
  131. func isDigit(ch rune) bool {
  132. return (ch >= '0' && ch <= '9')
  133. }
  134. // newScanner creates a new scanner with the given io.Reader
  135. func newScanner(r io.Reader) *scanner {
  136. return &scanner{r: bufio.NewReader(r)}
  137. }
  138. func (s *scanner) read() rune {
  139. ch, _, err := s.r.ReadRune()
  140. if err != nil {
  141. return eof
  142. }
  143. return ch
  144. }
  145. func (s *scanner) unread() {
  146. _ = s.r.UnreadRune()
  147. }
  148. // scan returns the token and literal string of the current value
  149. func (s *scanner) scan() (tok token, lit string) {
  150. ch := s.read()
  151. if isWhitespace(ch) {
  152. // space
  153. s.unread()
  154. return s.scanWhitespace()
  155. } else if isLetter(ch) || isDigit(ch) {
  156. // letter/digit
  157. s.unread()
  158. return s.scanIndent()
  159. } else if isComment(ch) {
  160. // comment
  161. s.unread()
  162. return s.scanIndent()
  163. }
  164. if ch == eof {
  165. return EOF, ""
  166. }
  167. return ILLEGAL, string(ch)
  168. }
  169. func (s *scanner) scanWhitespace() (token token, lit string) {
  170. var buf bytes.Buffer
  171. buf.WriteRune(s.read())
  172. for {
  173. if ch := s.read(); ch == eof {
  174. break
  175. } else if !isWhitespace(ch) {
  176. s.unread()
  177. break
  178. } else {
  179. _, _ = buf.WriteRune(ch)
  180. }
  181. }
  182. return WS, buf.String()
  183. }
  184. func (s *scanner) scanIndent() (tok token, lit string) {
  185. var buf bytes.Buffer
  186. buf.WriteRune(s.read())
  187. for {
  188. if ch := s.read(); ch == eof {
  189. break
  190. } else if !isLetter(ch) && !isDigit(ch) {
  191. s.unread()
  192. break
  193. } else {
  194. _, _ = buf.WriteRune(ch)
  195. }
  196. }
  197. if len(buf.String()) == 1 {
  198. return token(rune(buf.String()[0])), buf.String()
  199. }
  200. return IDENT, buf.String()
  201. }
  202. // parser defines the parser
  203. type parser struct {
  204. s *scanner
  205. buf struct {
  206. tok token
  207. lit string
  208. n int
  209. }
  210. }
  211. // newParser creates a new parser from a io.Reader
  212. func newParser(r io.Reader) *parser {
  213. return &parser{s: newScanner(r)}
  214. }
  215. func (p *parser) scan() (tok token, lit string) {
  216. // if there is a token in the buffer return it
  217. if p.buf.n != 0 {
  218. p.buf.n = 0
  219. return p.buf.tok, p.buf.lit
  220. }
  221. tok, lit = p.s.scan()
  222. p.buf.tok, p.buf.lit = tok, lit
  223. return
  224. }
  225. func (p *parser) scanIgnoreWhitespace() (tok token, lit string) {
  226. tok, lit = p.scan()
  227. if tok == WS {
  228. tok, lit = p.scan()
  229. }
  230. return
  231. }
  232. // parseLine parses the current line
  233. func (p *parser) parseLine(setType setType) (*Instruction, error) {
  234. c := &Instruction{}
  235. tok, lit := p.scanIgnoreWhitespace()
  236. if tok == EOF {
  237. return nil, tracerr.Wrap(errof)
  238. }
  239. c.Literal += lit
  240. if lit == "/" {
  241. _, _ = p.s.r.ReadString('\n')
  242. return nil, commentLine
  243. } else if lit == ">" {
  244. if setType == SetTypePoolL2 {
  245. return c, tracerr.Wrap(fmt.Errorf("Unexpected '>' at PoolL2Txs set"))
  246. }
  247. _, lit = p.scanIgnoreWhitespace()
  248. if lit == "batch" {
  249. _, _ = p.s.r.ReadString('\n')
  250. return &Instruction{Typ: TypeNewBatch}, newEventLine
  251. } else if lit == "batchL1" {
  252. _, _ = p.s.r.ReadString('\n')
  253. return &Instruction{Typ: TypeNewBatchL1}, newEventLine
  254. } else if lit == "block" {
  255. _, _ = p.s.r.ReadString('\n')
  256. return &Instruction{Typ: TypeNewBlock}, newEventLine
  257. } else {
  258. return c, tracerr.Wrap(fmt.Errorf("Unexpected '> %s', expected '> batch' or '> block'", lit))
  259. }
  260. } else if lit == "Type" {
  261. if err := p.expectChar(c, ":"); err != nil {
  262. return c, tracerr.Wrap(err)
  263. }
  264. _, lit = p.scanIgnoreWhitespace()
  265. if lit == "Blockchain" {
  266. return &Instruction{Typ: "Blockchain"}, setTypeLine
  267. } else if lit == "PoolL2" {
  268. return &Instruction{Typ: "PoolL2"}, setTypeLine
  269. } else {
  270. return c,
  271. tracerr.Wrap(fmt.Errorf("Invalid set type: '%s'. Valid set types: 'Blockchain', 'PoolL2'", lit))
  272. }
  273. } else if lit == "AddToken" {
  274. if err := p.expectChar(c, "("); err != nil {
  275. return c, tracerr.Wrap(err)
  276. }
  277. _, lit = p.scanIgnoreWhitespace()
  278. c.Literal += lit
  279. tidI, err := strconv.Atoi(lit)
  280. if err != nil {
  281. line, _ := p.s.r.ReadString('\n')
  282. c.Literal += line
  283. return c, tracerr.Wrap(err)
  284. }
  285. c.TokenID = common.TokenID(tidI)
  286. if err := p.expectChar(c, ")"); err != nil {
  287. return c, tracerr.Wrap(err)
  288. }
  289. c.Typ = TypeAddToken
  290. line, _ := p.s.r.ReadString('\n')
  291. c.Literal += line
  292. return c, newEventLine
  293. }
  294. if setType == "" {
  295. return c, tracerr.Wrap(fmt.Errorf("Set type not defined"))
  296. }
  297. transferring := false
  298. fee := false
  299. if setType == SetTypeBlockchain {
  300. switch lit {
  301. case "Deposit":
  302. c.Typ = common.TxTypeDeposit
  303. case "Exit":
  304. c.Typ = common.TxTypeExit
  305. fee = true
  306. case "Transfer":
  307. c.Typ = common.TxTypeTransfer
  308. transferring = true
  309. fee = true
  310. case "CreateAccountDeposit":
  311. c.Typ = common.TxTypeCreateAccountDeposit
  312. case "CreateAccountDepositTransfer":
  313. c.Typ = common.TxTypeCreateAccountDepositTransfer
  314. transferring = true
  315. case "CreateAccountCoordinator":
  316. c.Typ = TxTypeCreateAccountDepositCoordinator
  317. // transferring is false, as the Coordinator tx transfer will be 0
  318. case "DepositTransfer":
  319. c.Typ = common.TxTypeDepositTransfer
  320. transferring = true
  321. case "ForceTransfer":
  322. c.Typ = common.TxTypeForceTransfer
  323. transferring = true
  324. case "ForceExit":
  325. c.Typ = common.TxTypeForceExit
  326. default:
  327. return c, tracerr.Wrap(fmt.Errorf("Unexpected Blockchain tx type: %s", lit))
  328. }
  329. } else if setType == SetTypePoolL2 {
  330. switch lit {
  331. case "PoolTransfer":
  332. c.Typ = common.TxTypeTransfer
  333. transferring = true
  334. fee = true
  335. case "PoolTransferToEthAddr":
  336. c.Typ = common.TxTypeTransferToEthAddr
  337. transferring = true
  338. fee = true
  339. case "PoolTransferToBJJ":
  340. c.Typ = common.TxTypeTransferToBJJ
  341. transferring = true
  342. fee = true
  343. case "PoolExit":
  344. c.Typ = common.TxTypeExit
  345. fee = true
  346. default:
  347. return c, tracerr.Wrap(fmt.Errorf("Unexpected PoolL2 tx type: %s", lit))
  348. }
  349. } else {
  350. return c,
  351. tracerr.Wrap(fmt.Errorf("Invalid set type: '%s'. Valid set types: 'Blockchain', 'PoolL2'",
  352. setType))
  353. }
  354. if err := p.expectChar(c, "("); err != nil {
  355. return c, tracerr.Wrap(err)
  356. }
  357. _, lit = p.scanIgnoreWhitespace()
  358. c.Literal += lit
  359. tidI, err := strconv.Atoi(lit)
  360. if err != nil {
  361. line, _ := p.s.r.ReadString('\n')
  362. c.Literal += line
  363. return c, tracerr.Wrap(err)
  364. }
  365. c.TokenID = common.TokenID(tidI)
  366. if err := p.expectChar(c, ")"); err != nil {
  367. return c, tracerr.Wrap(err)
  368. }
  369. _, lit = p.scanIgnoreWhitespace()
  370. c.Literal += lit
  371. c.From = lit
  372. if c.Typ == TxTypeCreateAccountDepositCoordinator {
  373. line, _ := p.s.r.ReadString('\n')
  374. c.Literal += line
  375. return c, nil
  376. }
  377. _, lit = p.scanIgnoreWhitespace()
  378. c.Literal += lit
  379. if transferring {
  380. if lit != "-" {
  381. return c, tracerr.Wrap(fmt.Errorf("Expected '-', found '%s'", lit))
  382. }
  383. _, lit = p.scanIgnoreWhitespace()
  384. c.Literal += lit
  385. c.To = lit
  386. _, lit = p.scanIgnoreWhitespace()
  387. c.Literal += lit
  388. }
  389. if lit != ":" {
  390. line, _ := p.s.r.ReadString('\n')
  391. c.Literal += line
  392. return c, tracerr.Wrap(fmt.Errorf("Expected ':', found '%s'", lit))
  393. }
  394. if c.Typ == common.TxTypeDepositTransfer ||
  395. c.Typ == common.TxTypeCreateAccountDepositTransfer {
  396. // deposit case
  397. _, lit = p.scanIgnoreWhitespace()
  398. c.Literal += lit
  399. depositAmount, ok := new(big.Int).SetString(lit, 10)
  400. if !ok {
  401. line, _ := p.s.r.ReadString('\n')
  402. c.Literal += line
  403. return c, tracerr.Wrap(fmt.Errorf("Can not parse number for DepositAmount"))
  404. }
  405. c.DepositAmount = depositAmount
  406. if err := p.expectChar(c, ","); err != nil {
  407. return c, tracerr.Wrap(err)
  408. }
  409. }
  410. _, lit = p.scanIgnoreWhitespace()
  411. c.Literal += lit
  412. amount, ok := new(big.Int).SetString(lit, 10)
  413. if !ok {
  414. line, _ := p.s.r.ReadString('\n')
  415. c.Literal += line
  416. return c, tracerr.Wrap(fmt.Errorf("Can not parse number for Amount: %s", lit))
  417. }
  418. if c.Typ == common.TxTypeDeposit ||
  419. c.Typ == common.TxTypeCreateAccountDeposit {
  420. c.DepositAmount = amount
  421. } else {
  422. c.Amount = amount
  423. }
  424. if fee {
  425. if err := p.expectChar(c, "("); err != nil {
  426. return c, tracerr.Wrap(err)
  427. }
  428. _, lit = p.scanIgnoreWhitespace()
  429. c.Literal += lit
  430. fee, err := strconv.Atoi(lit)
  431. if err != nil {
  432. line, _ := p.s.r.ReadString('\n')
  433. c.Literal += line
  434. return c, tracerr.Wrap(err)
  435. }
  436. if fee > common.MaxFeePlan-1 {
  437. line, _ := p.s.r.ReadString('\n')
  438. c.Literal += line
  439. return c, tracerr.Wrap(fmt.Errorf("Fee %d can not be bigger than 255", fee))
  440. }
  441. c.Fee = uint8(fee)
  442. if err := p.expectChar(c, ")"); err != nil {
  443. return c, tracerr.Wrap(err)
  444. }
  445. }
  446. if tok == EOF {
  447. return nil, tracerr.Wrap(errof)
  448. }
  449. return c, nil
  450. }
  451. func (p *parser) expectChar(c *Instruction, ch string) error {
  452. _, lit := p.scanIgnoreWhitespace()
  453. c.Literal += lit
  454. if lit != ch {
  455. line, _ := p.s.r.ReadString('\n')
  456. c.Literal += line
  457. return tracerr.Wrap(fmt.Errorf("Expected '%s', found '%s'", ch, lit))
  458. }
  459. return nil
  460. }
  461. func idxTokenIDToString(idx string, tid common.TokenID) string {
  462. return idx + strconv.Itoa(int(tid))
  463. }
  464. // parse parses through reader
  465. func (p *parser) parse() (*parsedSet, error) {
  466. ps := &parsedSet{}
  467. i := 0 // lines will start counting at line 1
  468. users := make(map[string]bool)
  469. for {
  470. i++
  471. instruction, err := p.parseLine(ps.typ)
  472. if tracerr.Unwrap(err) == errof {
  473. break
  474. }
  475. if tracerr.Unwrap(err) == setTypeLine {
  476. if ps.typ != "" {
  477. return ps,
  478. tracerr.Wrap(fmt.Errorf("Line %d: Instruction of 'Type: %s' when "+
  479. "there is already a previous instruction 'Type: %s' defined",
  480. i, instruction.Typ, ps.typ))
  481. }
  482. if instruction.Typ == "PoolL2" {
  483. ps.typ = SetTypePoolL2
  484. } else if instruction.Typ == "Blockchain" {
  485. ps.typ = SetTypeBlockchain
  486. } else {
  487. log.Fatalf("Line %d: Invalid set type: '%s'. Valid set types: "+
  488. "'Blockchain', 'PoolL2'", i, instruction.Typ)
  489. }
  490. continue
  491. }
  492. if tracerr.Unwrap(err) == commentLine {
  493. continue
  494. }
  495. instruction.LineNum = i
  496. if tracerr.Unwrap(err) == newEventLine {
  497. if instruction.Typ == TypeAddToken && instruction.TokenID == common.TokenID(0) {
  498. return ps, tracerr.Wrap(fmt.Errorf("Line %d: AddToken can not register TokenID 0", i))
  499. }
  500. ps.instructions = append(ps.instructions, *instruction)
  501. continue
  502. }
  503. if err != nil {
  504. return ps, tracerr.Wrap(fmt.Errorf("Line %d: %s, err: %s", i, instruction.Literal, err.Error()))
  505. }
  506. if ps.typ == "" {
  507. return ps, tracerr.Wrap(fmt.Errorf("Line %d: Set type not defined", i))
  508. }
  509. ps.instructions = append(ps.instructions, *instruction)
  510. users[instruction.From] = true
  511. if instruction.Typ == common.TxTypeTransfer ||
  512. instruction.Typ == common.TxTypeTransferToEthAddr ||
  513. instruction.Typ == common.TxTypeTransferToBJJ { // type: Transfer
  514. users[instruction.To] = true
  515. }
  516. }
  517. for u := range users {
  518. ps.users = append(ps.users, u)
  519. }
  520. sort.Strings(ps.users)
  521. return ps, nil
  522. }