mirror of
https://github.com/arnaucube/hermez-node.git
synced 2026-02-07 11:26:44 +01:00
Add Transakcio new parser for the new lang spec
This commit is contained in:
195
test/lang.go
195
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 {
|
||||
|
||||
@@ -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: A-B(1):10256, err: Fee 256 can not be bigger than 255", err.Error())
|
||||
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: >, err: Unexpected '> btch', expected '> batch' or '> block'", err.Error())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user