dione/blockchain/types/block.go

93 lines
1.8 KiB
Go

package types
import (
"time"
"github.com/libp2p/go-libp2p-core/crypto"
"github.com/ethereum/go-ethereum/common"
"github.com/wealdtech/go-merkletree"
"github.com/wealdtech/go-merkletree/keccak256"
"github.com/libp2p/go-libp2p-core/peer"
)
type Block struct {
Header *BlockHeader
Data []*Transaction
}
type BlockHeader struct {
Timestamp int64
Height uint64
Hash []byte
LastHash []byte
LastHashProof *merkletree.Proof
Proposer peer.ID
ProposerEth common.Address
Signature []byte
}
func GenesisBlock() *Block {
return &Block{
Header: &BlockHeader{
Timestamp: 1620845070,
Height: 0,
Hash: []byte("DIMICANDUM"),
},
Data: []*Transaction{},
}
}
func CreateBlock(lastBlockHeader *BlockHeader, txs []*Transaction, minerEth common.Address, privateKey crypto.PrivKey) (*Block, error) {
timestamp := time.Now().Unix()
// extract hashes from transactions
var txHashes [][]byte
for _, tx := range txs {
txHashes = append(txHashes, tx.Hash)
}
txHashes = append(txHashes, lastBlockHeader.Hash)
tree, err := merkletree.NewUsing(txHashes, keccak256.New(), false)
if err != nil {
return nil, err
}
// fetch merkle tree root hash (block hash)
blockHash := tree.Root()
// sign the block hash
s, err := privateKey.Sign(blockHash)
if err != nil {
return nil, err
}
lastHashProof, err := tree.GenerateProof(lastBlockHeader.Hash, 0)
if err != nil {
return nil, err
}
proposer, err := peer.IDFromPrivateKey(privateKey)
if err != nil {
return nil, err
}
block := &Block{
Header: &BlockHeader{
Timestamp: timestamp,
Height: lastBlockHeader.Height + 1,
Proposer: proposer,
ProposerEth: minerEth,
Signature: s,
Hash: blockHash,
LastHash: lastBlockHeader.Hash,
LastHashProof: lastHashProof,
},
Data: txs,
}
return block, nil
}