コード例 #1
0
ファイル: block_tree.go プロジェクト: skycoin/skycoin
// 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)
	})
}
コード例 #2
0
ファイル: blockchain.go プロジェクト: skycoin/skycoin
// 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
}
コード例 #3
0
ファイル: blockchain_test.go プロジェクト: skycoin/skycoin
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())
}
コード例 #4
0
ファイル: visor.go プロジェクト: keepwalking1234/skycoin
// 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
}
コード例 #5
0
ファイル: blockchain.go プロジェクト: up4k/skycoin
// 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
}
コード例 #6
0
ファイル: block_tree.go プロジェクト: skycoin/skycoin
// 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
}
コード例 #7
0
ファイル: block_tree_test.go プロジェクト: skycoin/skycoin
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)
			}
		}
	}

}
コード例 #8
0
ファイル: blockchain.go プロジェクト: skycoin/skycoin
// 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
}
コード例 #9
0
ファイル: block_tree.go プロジェクト: skycoin/skycoin
// 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)
	})
}
コード例 #10
0
ファイル: blockchain.go プロジェクト: skycoin/skycoin
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++
	}
}
コード例 #11
0
ファイル: blockchain.go プロジェクト: skycoin/skycoin
// 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
}
コード例 #12
0
ファイル: block_tree.go プロジェクト: skycoin/skycoin
func setBlock(bkt *bolt.Bucket, b *coin.Block) error {
	bin := encoder.Serialize(b)
	key := b.HashHeader()
	return bkt.Put(key[:], bin)
}