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.

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