Ejemplo n.º 1
0
func TestNewBlock(t *testing.T) {
	// TODO -- update this test for newBlock changes
	prev := coin.Block{Head: coin.BlockHeader{Version: 0x02, Time: 100, BkSeq: 98}}
	unsp := coin.NewUnspentPool()
	unsp.XorHash = randSHA256()
	txns := coin.Transactions{coin.Transaction{}}
	// invalid txn fees panics
	assert.Panics(t, func() { coin.NewBlock(prev, 133, unsp, txns, _badFeeCalc) })
	// no txns panics
	assert.Panics(t, func() {
		coin.NewBlock(prev, 133, unsp, nil, _feeCalc)
	})
	assert.Panics(t, func() {
		coin.NewBlock(prev, 133, unsp, coin.Transactions{}, _feeCalc)
	})
	// valid block is fine
	fee := uint64(121)
	currentTime := uint64(133)
	b := coin.NewBlock(prev, currentTime, unsp, txns, _makeFeeCalc(fee))
	assert.Equal(t, b.Body.Transactions, txns)
	assert.Equal(t, b.Head.Fee, fee*uint64(len(txns)))
	assert.Equal(t, b.Body, coin.BlockBody{txns})
	assert.Equal(t, b.Head.PrevHash, prev.HashHeader())
	assert.Equal(t, b.Head.Time, currentTime)
	assert.Equal(t, b.Head.BkSeq, prev.Head.BkSeq+1)
	assert.Equal(t, b.Head.UxHash,
		unsp.GetUxHash())
}
Ejemplo n.º 2
0
// ExecuteBlock Attempts to append block to blockchain.  Returns the UxOuts created,
// and an error if the block is invalid.
func (bc *Blockchain) ExecuteBlock(b *coin.Block) (coin.UxArray, error) {
	var uxs coin.UxArray
	err := bc.verifyBlock(*b)
	if err != nil {
		return nil, err
	}
	txns := b.Body.Transactions
	for _, tx := range txns {
		// Remove spent outputs
		bc.unspent.DelMultiple(tx.In)
		// Create new outputs
		txUxs := coin.CreateUnspents(b.Head, tx)
		for i := range txUxs {
			bc.unspent.Add(txUxs[i])
		}
		uxs = append(uxs, txUxs...)
	}

	b.Head.PrevHash = bc.head
	bc.addBlock(b)

	// update the head
	bc.head = b.HashHeader()
	bc.notify(*b)
	return uxs, nil
}
Ejemplo n.º 3
0
// Signs a block for master.  Will panic if anything is invalid
func (self *Blockchain) signBlock(b coin.Block) SignedBlock {
	if !self.IsMaster {
		log.Panic("Only master chain can sign blocks")
	}
	sig := coin.SignHash(b.HashHeader(), self.SecKey)
	sb := SignedBlock{
		Block: b,
		Sig:   sig,
	}
	return sb
}
Ejemplo n.º 4
0
// Signs a block for master.  Will panic if anything is invalid
func (self *Visor) SignBlock(b coin.Block) SignedBlock {
	if !self.Config.IsMaster {
		log.Panic("Only master chain can sign blocks")
	}
	sig := cipher.SignHash(b.HashHeader(), self.Config.BlockchainSeckey)
	sb := SignedBlock{
		Block: b,
		Sig:   sig,
	}
	return sb
}
Ejemplo n.º 5
0
// check if this block has children
func hasChild(bkt *bolt.Bucket, b coin.Block) (bool, error) {
	// get the child block hash pair, whose pre hash point to current block.
	childHashPair, err := getHashPairInDepth(bkt, b.Head.BkSeq+1, func(hp coin.HashPair) bool {
		return hp.PreHash == b.HashHeader()
	})

	if err != nil {
		return false, nil
	}

	return len(childHashPair) > 0, nil
}
Ejemplo n.º 6
0
func testCase(t *testing.T, cases []blockCase) {
	_, teardown, err := setup(t)
	if err != nil {
		t.Fatal(err)
	}

	defer teardown()

	btree := NewBlockTree()
	blocks := make([]coin.Block, len(cases))
	for i, d := range cases {
		var preHash cipher.SHA256
		if d.BInfo.Pre != -1 {
			preHash = blocks[d.BInfo.Pre].HashHeader()
		}

		b := coin.Block{
			Head: coin.BlockHeader{
				BkSeq:    d.BInfo.Seq,
				Time:     d.BInfo.Time,
				Fee:      d.BInfo.Fee,
				PrevHash: preHash,
			},
		}
		blocks[i] = b

		switch d.Action {
		case "add":
			err := btree.AddBlock(&b)
			if err != d.Err {
				t.Fatal(fmt.Sprintf("expect err:%v, but get err:%v", d.Err, err))
			}

			if err == nil {
				b1 := btree.GetBlock(b.HashHeader())
				assert.Equal(t, *b1, b)
			}
		case "remove":
			err := btree.RemoveBlock(&b)
			if err != d.Err {
				t.Fatal(fmt.Sprintf("expect err:%v, but get err:%v", d.Err, err))
			}
			if err == nil {
				b1 := btree.GetBlock(b.HashHeader())
				assert.Nil(t, b1)
			}
		}
	}

}
Ejemplo n.º 7
0
func NewReadableBlockBody(b *coin.Block) ReadableBlockBody {
	txns := make([]ReadableTransaction, len(b.Body.Transactions))
	for i := range b.Body.Transactions {
		if b.Seq() == uint64(0) {
			// genesis block
			txns[i] = NewGenesisReadableTransaction(&Transaction{Txn: b.Body.Transactions[i]})
		} else {
			txns[i] = NewReadableTransaction(&Transaction{Txn: b.Body.Transactions[i]})
		}
	}
	return ReadableBlockBody{
		Transactions: txns,
	}
}
Ejemplo n.º 8
0
// VerifyBlock verifies the BlockHeader and BlockBody
func (bc Blockchain) verifyBlock(b coin.Block) error {
	gb := bc.GetGenesisBlock()
	if gb.HashHeader() != b.HashHeader() {
		if err := bc.verifyBlockHeader(b); err != nil {
			return err
		}

		if err := bc.verifyTransactions(b.Body.Transactions); err != nil {
			return err
		}
	}

	if err := bc.verifyUxHash(b); err != nil {
		return err
	}
	return nil
}
Ejemplo n.º 9
0
// VerifyBlockHeader Returns error if the BlockHeader is not valid
func (bc Blockchain) verifyBlockHeader(b coin.Block) error {
	//check BkSeq
	head := bc.Head()
	if b.Head.BkSeq != head.Head.BkSeq+1 {
		return errors.New("BkSeq invalid")
	}
	//check Time, only requirement is that its monotonely increasing
	if b.Head.Time <= head.Head.Time {
		return errors.New("Block time must be > head time")
	}
	// Check block hash against previous head
	if b.Head.PrevHash != head.HashHeader() {
		return errors.New("PrevHash does not match current head")
	}
	if b.HashBody() != b.Head.BodyHash {
		return errors.New("Computed body hash does not match")
	}
	return nil
}
Ejemplo n.º 10
0
// RemoveBlock remove block from blocks bucket and tree bucket.
// can't remove block if it has children.
func (bt *BlockTree) RemoveBlock(b *coin.Block) error {
	return UpdateTx(func(tx *bolt.Tx) error {
		// delete block in blocks bucket.
		blocks := tx.Bucket(bt.blocks.Name)
		hash := b.HashHeader()
		if err := blocks.Delete(hash[:]); err != nil {
			return err
		}

		// get tree bucket.
		tree := tx.Bucket(bt.tree.Name)

		// check if this block has children
		has, err := hasChild(tree, *b)
		if err != nil {
			return err
		}
		if has {
			return errHasChild
		}

		// get block hash pairs in depth
		hashPairs, err := getHashPairInDepth(tree, b.Seq(), func(hp coin.HashPair) bool {
			return true
		})
		if err != nil {
			return err
		}

		// remove block hash pair in tree.
		ps := removePairs(hashPairs, coin.HashPair{hash, b.PreHashHeader()})
		if len(ps) == 0 {
			tree.Delete(itob(b.Seq()))
			return nil
		}

		// update the hash pairs in tree.
		return setHashPairInDepth(tree, b.Seq(), ps)
	})
}
Ejemplo n.º 11
0
// GetAddressTransactions returns the Transactions whose unspents give coins to a cipher.Address.
// This includes unconfirmed txns' predicted unspents.
func (vs *Visor) GetAddressTransactions(a cipher.Address) []Transaction {
	var txns []Transaction
	// Look in the blockchain
	uxs := vs.Blockchain.GetUnspent().AllForAddress(a)
	mxSeq := vs.HeadBkSeq()
	var bk *coin.Block
	for _, ux := range uxs {
		if bk = vs.GetBlockBySeq(ux.Head.BkSeq); bk == nil {
			return txns
		}

		tx, ok := bk.GetTransaction(ux.Body.SrcTransaction)
		if ok {
			h := mxSeq - bk.Head.BkSeq + 1
			txns = append(txns, Transaction{
				Txn:    tx,
				Status: NewConfirmedTransactionStatus(h),
				Time:   bk.Time(),
			})
		}
	}

	// Look in the unconfirmed pool
	uxs = vs.Unconfirmed.Unspent.AllForAddress(a)
	for _, ux := range uxs {
		tx, ok := vs.Unconfirmed.Txns[ux.Body.SrcTransaction]
		if !ok {
			logger.Critical("Unconfirmed unspent missing unconfirmed txn")
			continue
		}
		txns = append(txns, Transaction{
			Txn:    tx.Txn,
			Status: NewUnconfirmedTransactionStatus(),
			Time:   uint64(tx.Received.Unix()),
		})
	}

	return txns
}
Ejemplo n.º 12
0
func (bc *Blockchain) walkTree() {
	var dep uint64
	var preBlock *coin.Block

	for {
		b := bc.tree.GetBlockInDepth(dep, bc.walker)
		if b == nil {
			break
		}
		if dep > 0 {
			if b.PreHashHeader() != preBlock.HashHeader() {
				logger.Panicf("walk tree failed, pre hash header not match")
			}
		}
		preBlock = b
		if err := bc.updateUnspent(*b); err != nil {
			logger.Panicf("update unspent failed, err: %v", err.Error())
		}

		bc.head = b.HashHeader()
		dep++
	}
}
Ejemplo n.º 13
0
// CreateGenesisBlock creates genesis block in blockchain.
func (bc *Blockchain) CreateGenesisBlock(genesisAddr cipher.Address, genesisCoins, timestamp uint64) coin.Block {
	txn := coin.Transaction{}
	txn.PushOutput(genesisAddr, genesisCoins, genesisCoins)
	body := coin.BlockBody{coin.Transactions{txn}}
	prevHash := cipher.SHA256{}
	head := coin.BlockHeader{
		Time:     timestamp,
		BodyHash: body.Hash(),
		PrevHash: prevHash,
		BkSeq:    0,
		Version:  0,
		Fee:      0,
		UxHash:   coin.NewUnspentPool().GetUxHash(),
	}
	b := coin.Block{
		Head: head,
		Body: body,
	}
	// b.Body.Transactions[0].UpdateHeader()
	bc.addBlock(&b)
	bc.head = b.HashHeader()
	ux := coin.UxOut{
		Head: coin.UxHead{
			Time:  timestamp,
			BkSeq: 0,
		},
		Body: coin.UxBody{
			SrcTransaction: txn.InnerHash, //user inner hash
			Address:        genesisAddr,
			Coins:          genesisCoins,
			Hours:          genesisCoins, // Allocate 1 coin hour per coin
		},
	}
	bc.unspent.Add(ux)
	bc.notify(b)
	return b
}
Ejemplo n.º 14
0
func TestVerifyBlockHeader(t *testing.T) {
	ft := FakeTree{}
	bc := NewBlockchain(&ft, nil)
	gb := bc.CreateGenesisBlock(genAddress, _genCoins, _genTime)
	b := coin.Block{Body: coin.BlockBody{}}
	b.Body.Transactions = append(b.Body.Transactions, makeTransaction(t))
	h := coin.BlockHeader{}

	h.BkSeq = 1
	h.Time = gb.Head.Time + 1
	h.PrevHash = gb.HashHeader()
	h.BodyHash = b.HashBody()

	// Valid header
	b.Head = h
	assert.Nil(t, bc.verifyBlockHeader(b))

	// Invalid bkSeq
	i := h
	i.BkSeq++
	b.Head = i
	assertError(t, bc.verifyBlockHeader(b), "BkSeq invalid")

	// Invalid time
	i = h
	i.Time = gb.Head.Time
	b.Head = i
	assertError(t, bc.verifyBlockHeader(b),
		"Block time must be > head time")
	b.Head.Time--
	assertError(t, bc.verifyBlockHeader(b),
		"Block time must be > head time")

	// Invalid prevHash
	i = h
	i.PrevHash = cipher.SHA256{}
	b.Head = i
	assertError(t, bc.verifyBlockHeader(b),
		"PrevHash does not match current head")

	// Invalid bodyHash
	i = h
	i.BodyHash = cipher.SHA256{}
	b.Head = i
	assertError(t, bc.verifyBlockHeader(b),
		"Computed body hash does not match")
}
Ejemplo n.º 15
0
// GetLastTxs returns last confirmed transactions, return nil if empty
func (vs *Visor) GetLastTxs() ([]*Transaction, error) {
	ltxs, err := vs.history.GetLastTxs()
	if err != nil {
		return nil, err
	}

	txs := make([]*Transaction, len(ltxs))
	var confirms uint64
	bh := vs.GetHeadBlock().Seq()
	var b *coin.Block
	for i, tx := range ltxs {
		confirms = bh - tx.BlockSeq + 1
		if b = vs.GetBlockBySeq(tx.BlockSeq); b == nil {
			return nil, fmt.Errorf("found no block in seq %v", tx.BlockSeq)
		}

		txs[i] = &Transaction{
			Txn:    tx.Tx,
			Status: NewConfirmedTransactionStatus(confirms),
			Time:   b.Time(),
		}
	}
	return txs, nil
}
Ejemplo n.º 16
0
// ProcessBlock will index the transaction, outputs,etc.
func (hd *HistoryDB) ProcessBlock(b *coin.Block) error {
	// index the transactions
	for _, t := range b.Body.Transactions {
		tx := Transaction{
			Tx:       t,
			BlockSeq: b.Seq(),
		}
		if err := hd.txns.Add(&tx); err != nil {
			return err
		}

		// handle tx in, genesis transaction's vin is empty, so should be ignored.
		if b.Seq() > 0 {
			for _, in := range t.In {
				o, err := hd.outputs.Get(in)
				if err != nil {
					return err
				}
				// update output's spent block seq and txid.
				o.SpentBlockSeq = b.Seq()
				o.SpentTxID = t.Hash()
				if err := hd.outputs.Set(*o); err != nil {
					return err
				}
			}
		}

		// handle the tx out
		uxArray := coin.CreateUnspents(b.Head, t)
		for _, ux := range uxArray {
			uxOut := UxOut{
				Out: ux,
			}
			if err := hd.outputs.Set(uxOut); err != nil {
				return err
			}

			if err := hd.addrUx.Add(ux.Body.Address, ux.Hash()); err != nil {
				return err
			}
		}
	}
	return nil
}
Ejemplo n.º 17
0
func setBlock(bkt *bolt.Bucket, b *coin.Block) error {
	bin := encoder.Serialize(b)
	key := b.HashHeader()
	return bkt.Put(key[:], bin)
}
Ejemplo n.º 18
0
// AddBlock write the block into blocks bucket, add the pair of block hash and pre block hash into
// tree in the block depth.
func (bt *BlockTree) AddBlock(b *coin.Block) error {
	return UpdateTx(func(tx *bolt.Tx) error {
		blocks := tx.Bucket(bt.blocks.Name)

		// can't store block if it's not genesis block and has no parent.
		if b.Seq() > 0 && b.PreHashHeader() == emptyHash {
			return errNoParent
		}

		// check if the block already exist.
		hash := b.HashHeader()
		if blk := blocks.Get(hash[:]); blk != nil {
			return errBlockExist
		}

		// write block into blocks bucket.
		if err := setBlock(blocks, b); err != nil {
			return err
		}

		// get tree bucket.
		tree := tx.Bucket(bt.tree.Name)

		// the pre hash must be in depth - 1.
		if b.Seq() > 0 {
			preHash := b.PreHashHeader()
			parentHashPair, err := getHashPairInDepth(tree, b.Seq()-1, func(hp coin.HashPair) bool {
				return hp.Hash == preHash
			})
			if err != nil {
				return err
			}
			if len(parentHashPair) == 0 {
				return errWrongParent
			}
		}

		hp := coin.HashPair{hash, b.Head.PrevHash}

		// get block pairs in the depth
		hashPairs, err := getHashPairInDepth(tree, b.Seq(), allPairs)
		if err != nil {
			return err
		}

		if len(hashPairs) == 0 {
			// no hash pair exist in the depth.
			// write the hash pair into tree.
			return setHashPairInDepth(tree, b.Seq(), []coin.HashPair{hp})
		}

		// check dup block
		if containHash(hashPairs, hp) {
			return errBlockExist
		}

		hashPairs = append(hashPairs, hp)
		return setHashPairInDepth(tree, b.Seq(), hashPairs)
	})
}