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.

564 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, tracerr.Wrap(fmt.Errorf("Invalid set type: '%s'. Valid set types: 'Blockchain', 'PoolL2'", lit))
  271. }
  272. } else if lit == "AddToken" {
  273. if err := p.expectChar(c, "("); err != nil {
  274. return c, tracerr.Wrap(err)
  275. }
  276. _, lit = p.scanIgnoreWhitespace()
  277. c.Literal += lit
  278. tidI, err := strconv.Atoi(lit)
  279. if err != nil {
  280. line, _ := p.s.r.ReadString('\n')
  281. c.Literal += line
  282. return c, tracerr.Wrap(err)
  283. }
  284. c.TokenID = common.TokenID(tidI)
  285. if err := p.expectChar(c, ")"); err != nil {
  286. return c, tracerr.Wrap(err)
  287. }
  288. c.Typ = TypeAddToken
  289. line, _ := p.s.r.ReadString('\n')
  290. c.Literal += line
  291. return c, newEventLine
  292. }
  293. if setType == "" {
  294. return c, tracerr.Wrap(fmt.Errorf("Set type not defined"))
  295. }
  296. transferring := false
  297. fee := false
  298. if setType == SetTypeBlockchain {
  299. switch lit {
  300. case "Deposit":
  301. c.Typ = common.TxTypeDeposit
  302. case "Exit":
  303. c.Typ = common.TxTypeExit
  304. fee = true
  305. case "Transfer":
  306. c.Typ = common.TxTypeTransfer
  307. transferring = true
  308. fee = true
  309. case "CreateAccountDeposit":
  310. c.Typ = common.TxTypeCreateAccountDeposit
  311. case "CreateAccountDepositTransfer":
  312. c.Typ = common.TxTypeCreateAccountDepositTransfer
  313. transferring = true
  314. case "CreateAccountCoordinator":
  315. c.Typ = TxTypeCreateAccountDepositCoordinator
  316. // transferring is false, as the Coordinator tx transfer will be 0
  317. case "DepositTransfer":
  318. c.Typ = common.TxTypeDepositTransfer
  319. transferring = true
  320. case "ForceTransfer":
  321. c.Typ = common.TxTypeForceTransfer
  322. transferring = true
  323. case "ForceExit":
  324. c.Typ = common.TxTypeForceExit
  325. default:
  326. return c, tracerr.Wrap(fmt.Errorf("Unexpected Blockchain tx type: %s", lit))
  327. }
  328. } else if setType == SetTypePoolL2 {
  329. switch lit {
  330. case "PoolTransfer":
  331. c.Typ = common.TxTypeTransfer
  332. transferring = true
  333. fee = true
  334. case "PoolTransferToEthAddr":
  335. c.Typ = common.TxTypeTransferToEthAddr
  336. transferring = true
  337. fee = true
  338. case "PoolTransferToBJJ":
  339. c.Typ = common.TxTypeTransferToBJJ
  340. transferring = true
  341. fee = true
  342. case "PoolExit":
  343. c.Typ = common.TxTypeExit
  344. fee = true
  345. default:
  346. return c, tracerr.Wrap(fmt.Errorf("Unexpected PoolL2 tx type: %s", lit))
  347. }
  348. } else {
  349. return c, tracerr.Wrap(fmt.Errorf("Invalid set type: '%s'. Valid set types: 'Blockchain', 'PoolL2'", setType))
  350. }
  351. if err := p.expectChar(c, "("); err != nil {
  352. return c, tracerr.Wrap(err)
  353. }
  354. _, lit = p.scanIgnoreWhitespace()
  355. c.Literal += lit
  356. tidI, err := strconv.Atoi(lit)
  357. if err != nil {
  358. line, _ := p.s.r.ReadString('\n')
  359. c.Literal += line
  360. return c, tracerr.Wrap(err)
  361. }
  362. c.TokenID = common.TokenID(tidI)
  363. if err := p.expectChar(c, ")"); err != nil {
  364. return c, tracerr.Wrap(err)
  365. }
  366. _, lit = p.scanIgnoreWhitespace()
  367. c.Literal += lit
  368. c.From = lit
  369. if c.Typ == TxTypeCreateAccountDepositCoordinator {
  370. line, _ := p.s.r.ReadString('\n')
  371. c.Literal += line
  372. return c, nil
  373. }
  374. _, lit = p.scanIgnoreWhitespace()
  375. c.Literal += lit
  376. if transferring {
  377. if lit != "-" {
  378. return c, tracerr.Wrap(fmt.Errorf("Expected '-', found '%s'", lit))
  379. }
  380. _, lit = p.scanIgnoreWhitespace()
  381. c.Literal += lit
  382. c.To = lit
  383. _, lit = p.scanIgnoreWhitespace()
  384. c.Literal += lit
  385. }
  386. if lit != ":" {
  387. line, _ := p.s.r.ReadString('\n')
  388. c.Literal += line
  389. return c, tracerr.Wrap(fmt.Errorf("Expected ':', found '%s'", lit))
  390. }
  391. if c.Typ == common.TxTypeDepositTransfer ||
  392. c.Typ == common.TxTypeCreateAccountDepositTransfer {
  393. // deposit case
  394. _, lit = p.scanIgnoreWhitespace()
  395. c.Literal += lit
  396. depositAmount, ok := new(big.Int).SetString(lit, 10)
  397. if !ok {
  398. line, _ := p.s.r.ReadString('\n')
  399. c.Literal += line
  400. return c, tracerr.Wrap(fmt.Errorf("Can not parse number for DepositAmount"))
  401. }
  402. c.DepositAmount = depositAmount
  403. if err := p.expectChar(c, ","); err != nil {
  404. return c, tracerr.Wrap(err)
  405. }
  406. }
  407. _, lit = p.scanIgnoreWhitespace()
  408. c.Literal += lit
  409. amount, ok := new(big.Int).SetString(lit, 10)
  410. if !ok {
  411. line, _ := p.s.r.ReadString('\n')
  412. c.Literal += line
  413. return c, tracerr.Wrap(fmt.Errorf("Can not parse number for Amount: %s", lit))
  414. }
  415. if c.Typ == common.TxTypeDeposit ||
  416. c.Typ == common.TxTypeCreateAccountDeposit {
  417. c.DepositAmount = amount
  418. } else {
  419. c.Amount = amount
  420. }
  421. if fee {
  422. if err := p.expectChar(c, "("); err != nil {
  423. return c, tracerr.Wrap(err)
  424. }
  425. _, lit = p.scanIgnoreWhitespace()
  426. c.Literal += lit
  427. fee, err := strconv.Atoi(lit)
  428. if err != nil {
  429. line, _ := p.s.r.ReadString('\n')
  430. c.Literal += line
  431. return c, tracerr.Wrap(err)
  432. }
  433. if fee > common.MaxFeePlan-1 {
  434. line, _ := p.s.r.ReadString('\n')
  435. c.Literal += line
  436. return c, tracerr.Wrap(fmt.Errorf("Fee %d can not be bigger than 255", fee))
  437. }
  438. c.Fee = uint8(fee)
  439. if err := p.expectChar(c, ")"); err != nil {
  440. return c, tracerr.Wrap(err)
  441. }
  442. }
  443. if tok == EOF {
  444. return nil, tracerr.Wrap(errof)
  445. }
  446. return c, nil
  447. }
  448. func (p *parser) expectChar(c *Instruction, ch string) error {
  449. _, lit := p.scanIgnoreWhitespace()
  450. c.Literal += lit
  451. if lit != ch {
  452. line, _ := p.s.r.ReadString('\n')
  453. c.Literal += line
  454. return tracerr.Wrap(fmt.Errorf("Expected '%s', found '%s'", ch, lit))
  455. }
  456. return nil
  457. }
  458. func idxTokenIDToString(idx string, tid common.TokenID) string {
  459. return idx + strconv.Itoa(int(tid))
  460. }
  461. // parse parses through reader
  462. func (p *parser) parse() (*parsedSet, error) {
  463. ps := &parsedSet{}
  464. i := 0 // lines will start counting at line 1
  465. users := make(map[string]bool)
  466. for {
  467. i++
  468. instruction, err := p.parseLine(ps.typ)
  469. if tracerr.Unwrap(err) == errof {
  470. break
  471. }
  472. if tracerr.Unwrap(err) == setTypeLine {
  473. if ps.typ != "" {
  474. return ps, tracerr.Wrap(fmt.Errorf("Line %d: Instruction of 'Type: %s' when there is already a previous instruction 'Type: %s' defined", i, instruction.Typ, ps.typ))
  475. }
  476. if instruction.Typ == "PoolL2" {
  477. ps.typ = SetTypePoolL2
  478. } else if instruction.Typ == "Blockchain" {
  479. ps.typ = SetTypeBlockchain
  480. } else {
  481. log.Fatalf("Line %d: Invalid set type: '%s'. Valid set types: 'Blockchain', 'PoolL2'", i, instruction.Typ)
  482. }
  483. continue
  484. }
  485. if tracerr.Unwrap(err) == commentLine {
  486. continue
  487. }
  488. instruction.LineNum = i
  489. if tracerr.Unwrap(err) == newEventLine {
  490. if instruction.Typ == TypeAddToken && instruction.TokenID == common.TokenID(0) {
  491. return ps, tracerr.Wrap(fmt.Errorf("Line %d: AddToken can not register TokenID 0", i))
  492. }
  493. ps.instructions = append(ps.instructions, *instruction)
  494. continue
  495. }
  496. if err != nil {
  497. return ps, tracerr.Wrap(fmt.Errorf("Line %d: %s, err: %s", i, instruction.Literal, err.Error()))
  498. }
  499. if ps.typ == "" {
  500. return ps, tracerr.Wrap(fmt.Errorf("Line %d: Set type not defined", i))
  501. }
  502. ps.instructions = append(ps.instructions, *instruction)
  503. users[instruction.From] = true
  504. if instruction.Typ == common.TxTypeTransfer || instruction.Typ == common.TxTypeTransferToEthAddr || instruction.Typ == common.TxTypeTransferToBJJ { // type: Transfer
  505. users[instruction.To] = true
  506. }
  507. }
  508. for u := range users {
  509. ps.users = append(ps.users, u)
  510. }
  511. sort.Strings(ps.users)
  512. return ps, nil
  513. }