From 06ae1897d81689582d1c9bdf79bc7f4e5c15fb13 Mon Sep 17 00:00:00 2001 From: arnaucube Date: Tue, 6 Oct 2020 18:20:51 +0200 Subject: [PATCH] Add Transakcio new parser for the new lang spec --- test/lang.go | 195 +++++++++++++++++++++++++++++----------------- test/lang_test.go | 114 +++++++++++++++++++-------- 2 files changed, 202 insertions(+), 107 deletions(-) diff --git a/test/lang.go b/test/lang.go index 90a870a..f4e5eb9 100644 --- a/test/lang.go +++ b/test/lang.go @@ -14,12 +14,16 @@ import ( var eof = rune(0) var errof = fmt.Errorf("eof in parseline") var errComment = fmt.Errorf("comment in parseline") -var errNewBatch = fmt.Errorf("newbatch") +var newEvent = fmt.Errorf("newEvent") // TypeNewBatch is used for testing purposes only, and represents the // common.TxType of a new batch var TypeNewBatch common.TxType = "TxTypeNewBatch" +// TypeNewBlock is used for testing purposes only, and represents the +// common.TxType of a new ethereum block +var TypeNewBlock common.TxType = "TxTypeNewBlock" + //nolint const ( ILLEGAL token = iota @@ -31,13 +35,14 @@ const ( // Instruction is the data structure that represents one line of code type Instruction struct { - Literal string - From string - To string - Amount uint64 - Fee uint8 - TokenID common.TokenID - Type common.TxType // D: Deposit, T: Transfer, E: ForceExit + Literal string + From string + To string + Amount uint64 + LoadAmount uint64 + Fee uint8 + TokenID common.TokenID + Type common.TxType // D: Deposit, T: Transfer, E: ForceExit } // Instructions contains the full Set of Instructions representing a full code @@ -49,42 +54,46 @@ type Instructions struct { func (i Instruction) String() string { buf := bytes.NewBufferString("") - switch i.Type { - case common.TxTypeCreateAccountDeposit: - fmt.Fprintf(buf, "Type: Create&Deposit, ") - case common.TxTypeTransfer: - fmt.Fprintf(buf, "Type: Transfer, ") - case common.TxTypeForceExit: - fmt.Fprintf(buf, "Type: ForceExit, ") - default: - } + fmt.Fprintf(buf, "Type: %s, ", i.Type) fmt.Fprintf(buf, "From: %s, ", i.From) - if i.Type == common.TxTypeTransfer { + if i.Type == common.TxTypeTransfer || + i.Type == common.TxTypeDepositTransfer || + i.Type == common.TxTypeCreateAccountDepositTransfer { fmt.Fprintf(buf, "To: %s, ", i.To) } + if i.Type == common.TxTypeDepositTransfer || + i.Type == common.TxTypeCreateAccountDepositTransfer { + fmt.Fprintf(buf, "LoadAmount: %d, ", i.LoadAmount) + } fmt.Fprintf(buf, "Amount: %d, ", i.Amount) - if i.Type == common.TxTypeTransfer { + if i.Type == common.TxTypeTransfer || + i.Type == common.TxTypeDepositTransfer || + i.Type == common.TxTypeCreateAccountDepositTransfer { fmt.Fprintf(buf, "Fee: %d, ", i.Fee) } - fmt.Fprintf(buf, "TokenID: %d,\n", i.TokenID) + fmt.Fprintf(buf, "TokenID: %d\n", i.TokenID) return buf.String() } // Raw returns a string with the raw representation of the Instruction func (i Instruction) Raw() string { buf := bytes.NewBufferString("") + fmt.Fprintf(buf, "%s", i.Type) + fmt.Fprintf(buf, "(%d)", i.TokenID) fmt.Fprintf(buf, "%s", i.From) - if i.Type == common.TxTypeTransfer { + if i.Type == common.TxTypeTransfer || + i.Type == common.TxTypeDepositTransfer || + i.Type == common.TxTypeCreateAccountDepositTransfer { fmt.Fprintf(buf, "-%s", i.To) } - fmt.Fprintf(buf, " (%d)", i.TokenID) - if i.Type == common.TxTypeForceExit { - fmt.Fprintf(buf, "E") - } fmt.Fprintf(buf, ":") - fmt.Fprintf(buf, " %d", i.Amount) + if i.Type == common.TxTypeDepositTransfer || + i.Type == common.TxTypeCreateAccountDepositTransfer { + fmt.Fprintf(buf, "%d,", i.LoadAmount) + } + fmt.Fprintf(buf, "%d", i.Amount) if i.Type == common.TxTypeTransfer { - fmt.Fprintf(buf, " %d", i.Fee) + fmt.Fprintf(buf, "(%d)", i.Fee) } return buf.String() } @@ -229,15 +238,6 @@ func (p *Parser) scanIgnoreWhitespace() (tok token, lit string) { // parseLine parses the current line func (p *Parser) parseLine() (*Instruction, error) { - // line can be Deposit: - // A (1): 10 - // or Transfer: - // A-B (1): 6 - // or Withdraw: - // A (1) E: 4 - // or NextBatch: - // > and here the comment - c := &Instruction{} tok, lit := p.scanIgnoreWhitespace() if tok == EOF { @@ -248,30 +248,45 @@ func (p *Parser) parseLine() (*Instruction, error) { _, _ = p.s.r.ReadString('\n') return nil, errComment } else if lit == ">" { - _, _ = p.s.r.ReadString('\n') - return nil, errNewBatch - } - c.From = lit - - _, lit = p.scanIgnoreWhitespace() - c.Literal += lit - if lit == "-" { - // transfer _, lit = p.scanIgnoreWhitespace() - c.Literal += lit - c.To = lit - c.Type = common.TxTypeTransfer - _, lit = p.scanIgnoreWhitespace() // expect ( - c.Literal += lit - if lit != "(" { - line, _ := p.s.r.ReadString('\n') - c.Literal += line - return c, fmt.Errorf("Expected '(', found '%s'", lit) + if lit == "batch" { + _, _ = p.s.r.ReadString('\n') + return &Instruction{Type: TypeNewBatch}, newEvent + } else if lit == "block" { + _, _ = p.s.r.ReadString('\n') + return &Instruction{Type: TypeNewBlock}, newEvent + } else { + return c, fmt.Errorf("Unexpected '> %s', expected '> batch' or '> block'", lit) } - } else { + } + transfering := false + switch lit { + case "Deposit": + c.Type = common.TxTypeDeposit + case "Exit", "PoolExit": + c.Type = common.TxTypeExit + case "Transfer", "PoolTransfer": + c.Type = common.TxTypeTransfer + transfering = true + case "CreateAccountDeposit": c.Type = common.TxTypeCreateAccountDeposit + case "CreateAccountDepositTransfer": + c.Type = common.TxTypeCreateAccountDepositTransfer + transfering = true + case "DepositTransfer": + c.Type = common.TxTypeDepositTransfer + transfering = true + case "ForceTransfer": + c.Type = common.TxTypeForceTransfer + case "ForceExit": + c.Type = common.TxTypeForceExit + default: + return c, fmt.Errorf("Unexpected tx type: %s", lit) } + if err := p.expectChar(c, "("); err != nil { + return c, err + } _, lit = p.scanIgnoreWhitespace() c.Literal += lit tidI, err := strconv.Atoi(lit) @@ -281,19 +296,22 @@ func (p *Parser) parseLine() (*Instruction, error) { return c, err } c.TokenID = common.TokenID(tidI) - _, lit = p.scanIgnoreWhitespace() // expect ) - c.Literal += lit - if lit != ")" { - line, _ := p.s.r.ReadString('\n') - c.Literal += line - return c, fmt.Errorf("Expected ')', found '%s'", lit) + if err := p.expectChar(c, ")"); err != nil { + return c, err } - - _, lit = p.scanIgnoreWhitespace() // expect ':' or 'E' (Exit type) + _, lit = p.scanIgnoreWhitespace() c.Literal += lit - if lit == "E" { - c.Type = common.TxTypeForceExit - _, lit = p.scanIgnoreWhitespace() // expect ':' + c.From = lit + _, lit = p.scanIgnoreWhitespace() + c.Literal += lit + if lit == "-" { + if !transfering { + return c, fmt.Errorf("To defined, but not type {Transfer, CreateAccountDepositTransfer, DepositTransfer}") + } + _, lit = p.scanIgnoreWhitespace() + c.Literal += lit + c.To = lit + _, lit = p.scanIgnoreWhitespace() c.Literal += lit } if lit != ":" { @@ -301,7 +319,22 @@ func (p *Parser) parseLine() (*Instruction, error) { c.Literal += line return c, fmt.Errorf("Expected ':', found '%s'", lit) } - tok, lit = p.scanIgnoreWhitespace() + if c.Type == common.TxTypeDepositTransfer || + c.Type == common.TxTypeCreateAccountDepositTransfer { + _, lit = p.scanIgnoreWhitespace() + c.Literal += lit + loadAmount, err := strconv.Atoi(lit) + if err != nil { + line, _ := p.s.r.ReadString('\n') + c.Literal += line + return c, err + } + c.LoadAmount = uint64(loadAmount) + if err := p.expectChar(c, ","); err != nil { + return c, err + } + } + _, lit = p.scanIgnoreWhitespace() c.Literal += lit amount, err := strconv.Atoi(lit) if err != nil { @@ -310,9 +343,11 @@ func (p *Parser) parseLine() (*Instruction, error) { return c, err } c.Amount = uint64(amount) - - if c.Type == common.TxTypeTransfer { - tok, lit = p.scanIgnoreWhitespace() + if transfering { + if err := p.expectChar(c, "("); err != nil { + return c, err + } + _, lit = p.scanIgnoreWhitespace() c.Literal += lit fee, err := strconv.Atoi(lit) if err != nil { @@ -326,6 +361,10 @@ func (p *Parser) parseLine() (*Instruction, error) { return c, fmt.Errorf("Fee %d can not be bigger than 255", fee) } c.Fee = uint8(fee) + + if err := p.expectChar(c, ")"); err != nil { + return c, err + } } if tok == EOF { @@ -334,6 +373,17 @@ func (p *Parser) parseLine() (*Instruction, error) { return c, nil } +func (p *Parser) expectChar(c *Instruction, ch string) error { + _, lit := p.scanIgnoreWhitespace() + c.Literal += lit + if lit != ch { + line, _ := p.s.r.ReadString('\n') + c.Literal += line + return fmt.Errorf("Expected '%s', found '%s'", ch, lit) + } + return nil +} + func idxTokenIDToString(idx string, tid common.TokenID) string { return idx + strconv.Itoa(int(tid)) } @@ -353,10 +403,9 @@ func (p *Parser) Parse() (Instructions, error) { i++ continue } - if err == errNewBatch { + if err == newEvent { i++ - inst := &Instruction{Type: TypeNewBatch} - instructions.Instructions = append(instructions.Instructions, inst) + instructions.Instructions = append(instructions.Instructions, instruction) continue } if err != nil { diff --git a/test/lang_test.go b/test/lang_test.go index 57ad346..da94f1e 100644 --- a/test/lang_test.go +++ b/test/lang_test.go @@ -10,37 +10,47 @@ import ( var debug = false -func TestParse(t *testing.T) { +func TestParseBlockchainTxs(t *testing.T) { s := ` // deposits - A (1): 10 - A (2): 20 - B (1): 5 + Deposit(1) A: 10 + Deposit(2) A: 20 + Deposit(1) B: 5 + CreateAccountDeposit(1) C: 5 + CreateAccountDepositTransfer(1) D-A: 15, 10 (3) // L2 transactions - A-B (1): 6 1 - B-C (1): 3 1 + Transfer(1) A-B: 6 (1) + Transfer(1) B-D: 3 (1) - // set new batch, label does not affect - > batch1 + // set new batch + > batch - C-A (1): 3 1 - A-B (2): 15 1 + DepositTransfer(1) A-B: 15, 10 (1) + Transfer(1) C-A : 3 (1) + Transfer(2) A-B: 15 (1) - User0 (1): 20 - User1 (3) : 20 - User0-User1 (1): 15 1 - User1-User0 (3): 15 1 + Deposit(1) User0: 20 + Deposit(3) User1: 20 + Transfer(1) User0-User1: 15 (1) + Transfer(3) User1-User0: 15 (1) + + > batch + + Transfer(1) User1-User0: 1 (1) + + > batch + > block // Exits - A (1) E: 5 + Exit(1) A: 5 ` + parser := NewParser(strings.NewReader(s)) instructions, err := parser.Parse() assert.Nil(t, err) - assert.Equal(t, 13, len(instructions.Instructions)) - // assert.Equal(t, 5, len(instructions.Accounts)) - fmt.Println(instructions.Accounts) + assert.Equal(t, 20, len(instructions.Instructions)) + assert.Equal(t, 10, len(instructions.Accounts)) assert.Equal(t, 3, len(instructions.TokenIDs)) if debug { @@ -50,37 +60,73 @@ func TestParse(t *testing.T) { } } - assert.Equal(t, TypeNewBatch, instructions.Instructions[5].Type) - assert.Equal(t, "User0 (1): 20", instructions.Instructions[8].Raw()) - assert.Equal(t, "Type: Create&Deposit, From: User0, Amount: 20, TokenID: 1,\n", instructions.Instructions[8].String()) - assert.Equal(t, "User0-User1 (1): 15 1", instructions.Instructions[10].Raw()) - assert.Equal(t, "Type: Transfer, From: User0, To: User1, Amount: 15, Fee: 1, TokenID: 1,\n", instructions.Instructions[10].String()) - assert.Equal(t, "A (1)E: 5", instructions.Instructions[12].Raw()) - assert.Equal(t, "Type: ForceExit, From: A, Amount: 5, TokenID: 1,\n", instructions.Instructions[12].String()) + assert.Equal(t, TypeNewBatch, instructions.Instructions[7].Type) + assert.Equal(t, "Deposit(1)User0:20", instructions.Instructions[11].Raw()) + assert.Equal(t, "Type: DepositTransfer, From: A, To: B, LoadAmount: 15, Amount: 10, Fee: 1, TokenID: 1\n", instructions.Instructions[8].String()) + assert.Equal(t, "Type: Transfer, From: User1, To: User0, Amount: 15, Fee: 1, TokenID: 3\n", instructions.Instructions[14].String()) + assert.Equal(t, "Transfer(2)A-B:15(1)", instructions.Instructions[10].Raw()) + assert.Equal(t, "Type: Transfer, From: A, To: B, Amount: 15, Fee: 1, TokenID: 2\n", instructions.Instructions[10].String()) + assert.Equal(t, "Exit(1)A:5", instructions.Instructions[19].Raw()) + assert.Equal(t, "Type: Exit, From: A, Amount: 5, TokenID: 1\n", instructions.Instructions[19].String()) +} + +func TestParsePoolTxs(t *testing.T) { + s := ` + PoolTransfer(1) A-B: 6 (1) + PoolTransfer(2) A-B: 3 (3) + PoolTransfer(1) B-D: 3 (1) + PoolTransfer(1) C-D: 3 (1) + Exit(1) A: 5 + ` + + parser := NewParser(strings.NewReader(s)) + instructions, err := parser.Parse() + assert.Nil(t, err) + assert.Equal(t, 5, len(instructions.Instructions)) + assert.Equal(t, 6, len(instructions.Accounts)) + assert.Equal(t, 2, len(instructions.TokenIDs)) + + if debug { + fmt.Println(instructions) + for _, instruction := range instructions.Instructions { + fmt.Println(instruction.Raw()) + } + } + + assert.Equal(t, "Transfer(1)A-B:6(1)", instructions.Instructions[0].Raw()) + assert.Equal(t, "Transfer(2)A-B:3(3)", instructions.Instructions[1].Raw()) + assert.Equal(t, "Transfer(1)B-D:3(1)", instructions.Instructions[2].Raw()) + assert.Equal(t, "Transfer(1)C-D:3(1)", instructions.Instructions[3].Raw()) + assert.Equal(t, "Exit(1)A:5", instructions.Instructions[4].Raw()) } func TestParseErrors(t *testing.T) { - s := "A (1):: 10" + s := "Deposit(1) A:: 10" parser := NewParser(strings.NewReader(s)) _, err := parser.Parse() - assert.Equal(t, "error parsing line 0: A(1):: 10, err: strconv.Atoi: parsing \":\": invalid syntax", err.Error()) + assert.Equal(t, "error parsing line 0: Deposit(1)A:: 10, err: strconv.Atoi: parsing \":\": invalid syntax", err.Error()) - s = "A (1): 10 20" + s = "Deposit(1) A: 10 20" parser = NewParser(strings.NewReader(s)) _, err = parser.Parse() - assert.Equal(t, "error parsing line 1: 20, err: strconv.Atoi: parsing \"\": invalid syntax", err.Error()) + assert.Equal(t, "error parsing line 1: 20, err: Unexpected tx type: 20", err.Error()) - s = "A B (1): 10" + s = "Transfer(1) A B: 10" parser = NewParser(strings.NewReader(s)) _, err = parser.Parse() - assert.Equal(t, "error parsing line 0: AB(1): 10, err: strconv.Atoi: parsing \"(\": invalid syntax", err.Error()) + assert.Equal(t, "error parsing line 0: Transfer(1)AB: 10, err: Expected ':', found 'B'", err.Error()) - s = "A-B (1): 10 255" + s = "Transfer(1) A-B: 10 (255)" parser = NewParser(strings.NewReader(s)) _, err = parser.Parse() assert.Nil(t, err) - s = "A-B (1): 10 256" + s = "Transfer(1) A-B: 10 (256)" + parser = NewParser(strings.NewReader(s)) + _, err = parser.Parse() + assert.Equal(t, "error parsing line 0: Transfer(1)A-B:10(256), err: Fee 256 can not be bigger than 255", err.Error()) + + s = "> btch" parser = NewParser(strings.NewReader(s)) _, err = parser.Parse() - assert.Equal(t, "error parsing line 0: A-B(1):10256, err: Fee 256 can not be bigger than 255", err.Error()) + assert.Equal(t, "error parsing line 0: >, err: Unexpected '> btch', expected '> batch' or '> block'", err.Error()) }