aboutsummaryrefslogblamecommitdiff
path: root/examples/chain/main.go
blob: 26fc5ce1e50b308014b3d98e3b7d57c82e297c90 (plain) (tree)
1
2
3
4
5
6
7
8
9





                                    

                                               
                                        
                                           

                                                        
                                             

                                             
              














                                            
                                  















                                                                       
                                                                      


                                                  






                                                            

                                                                 



















                                                                               
                                   










                                                                         


                                                                 





















                                                                                                                
                                         





                                                                      
                                   
                                   
                                   


         
                                                  



                                       

                                                                                  

                     
                                   
                                                      
                                     
                            
                                 


                                                                                               
                                     










                                                                                             
                                     




























                                                                                                        



                                   
                                     




































                                                                                                                            
package main

import (
	"crypto/rand"
	"fmt"
	"github.com/ava-labs/coreth"
	"github.com/ava-labs/coreth/core"
	"github.com/ava-labs/coreth/core/types"
	"github.com/ava-labs/coreth/eth"
	"github.com/ava-labs/coreth/params"
	"github.com/ava-labs/go-ethereum/common"
	"github.com/ava-labs/go-ethereum/common/hexutil"
	"github.com/ava-labs/go-ethereum/log"
	"github.com/ava-labs/go-ethereum/rlp"
	"math/big"
	"sync"
)

func checkError(err error) {
	if err != nil {
		panic(err)
	}
}

type TestChain struct {
	hasBlock    map[common.Hash]struct{}
	blocks      []common.Hash
	blkCount    uint32
	chain       *coreth.ETHChain
	parentBlock common.Hash
	outBlockCh  chan<- []byte
	blockWait   sync.WaitGroup
}

func (tc *TestChain) insertBlock(block *types.Block) {
	if _, ok := tc.hasBlock[block.Hash()]; !ok {
		tc.hasBlock[block.Hash()] = struct{}{}
		tc.blocks = append(tc.blocks, block.Hash())
	}
}

func NewTestChain(name string, config *eth.Config,
	inBlockCh <-chan []byte, outBlockCh chan<- []byte,
	inAckCh <-chan struct{}, outAckCh chan<- struct{}) *TestChain {
	tc := &TestChain{
		hasBlock:   make(map[common.Hash]struct{}),
		blocks:     make([]common.Hash, 0),
		blkCount:   0,
		chain:      coreth.NewETHChain(config, nil, nil, nil),
		outBlockCh: outBlockCh,
	}
	tc.insertBlock(tc.chain.GetGenesisBlock())
	tc.chain.SetOnHeaderNew(func(header *types.Header) {
		hid := make([]byte, 32)
		_, err := rand.Read(hid)
		if err != nil {
			panic("cannot generate hid")
		}
		header.Extra = append(header.Extra, hid...)
	})
	tc.chain.SetOnSealFinish(func(block *types.Block) error {
		blkID := tc.blkCount
		tc.blkCount++
		if len(block.Uncles()) != 0 {
			panic("#uncles should be zero")
		}
		if tc.parentBlock != block.ParentHash() {
			panic("mismatching parent hash")
		}
		log.Info(fmt.Sprintf("%s: create %s <= (%d = %s)",
			name, tc.parentBlock.Hex(), blkID, block.Hash().Hex()))
		tc.insertBlock(block)
		if tc.outBlockCh != nil {
			serialized, err := rlp.EncodeToBytes(block)
			if err != nil {
				panic(err)
			}
			tc.outBlockCh <- serialized
			<-inAckCh
			log.Info(fmt.Sprintf("%s: got ack", name))
		}
		tc.blockWait.Done()
		return nil
	})
	go func() {
		for {
			select {
			case serialized := <-inBlockCh:
				block := new(types.Block)
				err := rlp.DecodeBytes(serialized, block)
				if err != nil {
					panic(err)
				}
				if !tc.chain.VerifyBlock(block) {
					panic("invalid block")
				}
				tc.chain.InsertChain([]*types.Block{block})
				tc.insertBlock(block)
				log.Info(fmt.Sprintf("%s: got block %s, sending ack", name, block.Hash().Hex()))
				outAckCh <- struct{}{}
			}
		}
	}()
	return tc
}

func (tc *TestChain) Start() {
	tc.chain.Start()
}

func (tc *TestChain) Stop() {
	tc.chain.Stop()
}

func (tc *TestChain) GenRandomTree(n int, max int) {
	for i := 0; i < n; i++ {
		nblocks := len(tc.blocks)
		m := max
		if m < 0 || nblocks < m {
			m = nblocks
		}
		pb, _ := rand.Int(rand.Reader, big.NewInt((int64)(m)))
		pn := pb.Int64()
		tc.parentBlock = tc.blocks[nblocks-1-(int)(pn)]
		tc.chain.SetTail(tc.parentBlock)
		tc.blockWait.Add(1)
		tc.chain.GenBlock()
		tc.blockWait.Wait()
	}
}

func run(config *eth.Config, a1, a2, b1, b2 int) {
	aliceBlk := make(chan []byte)
	bobBlk := make(chan []byte)
	aliceAck := make(chan struct{})
	bobAck := make(chan struct{})
	alice := NewTestChain("alice", config, bobBlk, aliceBlk, bobAck, aliceAck)
	bob := NewTestChain("bob", config, aliceBlk, bobBlk, aliceAck, bobAck)
	alice.Start()
	bob.Start()
	alice