aboutsummaryrefslogtreecommitdiffstats
path: root/block_manager.go
blob: 968d9a1392baa25ed2219d28e361c96e0a4d87be (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package main

import (
    "fmt"
    "github.com/ethereum/ethutil-go"
)

type BlockChain struct {
    lastBlock *ethutil.Block

    genesisBlock *ethutil.Block
}

func NewBlockChain() *BlockChain {
    bc := &BlockChain{}
    bc.genesisBlock = ethutil.NewBlock(ethutil.Encode(ethutil.Genesis))

    return bc
}

type BlockManager struct {
    vm *Vm

    blockChain *BlockChain
}

func NewBlockManager() *BlockManager {
    bm := &BlockManager{vm: NewVm()}

    return bm
}

// Process a block.
func (bm *BlockManager) ProcessBlock(block *ethutil.Block) error {
    // TODO Validation (Or move to other part of the application)
    if err := bm.ValidateBlock(block); err != nil {
        return err
    }

    // Get the tx count. Used to create enough channels to 'join' the go routines
    txCount := len(block.Transactions())
    // Locking channel. When it has been fully buffered this method will return
    lockChan := make(chan bool, txCount)

    // Process each transaction/contract
    for _, tx := range block.Transactions() {
        // If there's no recipient, it's a contract
        if tx.IsContract() {
            go bm.ProcessContract(tx, block, lockChan)
        } else {
            // "finish" tx which isn't a contract
            lockChan <- true
        }
    }

    // Wait for all Tx to finish processing
    for i := 0; i < txCount; i++ {
        <-lockChan
    }

    return nil
}

func (bm *BlockManager) ValidateBlock(block *ethutil.Block) error {
    return nil
}

func (bm *BlockManager) ProcessContract(tx *ethutil.Transaction, block *ethutil.Block, lockChan chan bool) {
    // Recovering function in case the VM had any errors
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered from VM execution with err =", r)
            // Let the channel know where done even though it failed (so the execution may resume normally)
            lockChan <- true
        }
    }()

    // Process contract
    bm.vm.ProcContract(tx, block, func(opType OpType) bool {
        // TODO turn on once big ints are in place
        //if !block.PayFee(tx.Hash(), StepFee.Uint64()) {
        //  return false
        //}

        return true // Continue
    })

    // Broadcast we're done
    lockChan <- true
}