mirror of
https://github.com/PeernetOfficial/core.git
synced 2026-07-17 02:47:51 +01:00
Initial code to read/create the users blockchain database on the file system.
This commit is contained in:
108
Blockchain.go
108
Blockchain.go
@@ -6,8 +6,116 @@ Author: Peter Kleissner
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/PeernetOfficial/core/store"
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
)
|
||||
|
||||
// BlockchainHeight is the current count of blocks
|
||||
var BlockchainHeight = uint32(0)
|
||||
|
||||
// BlockchainVersion is the version of the blockchain
|
||||
var BlockchainVersion = uint64(0)
|
||||
|
||||
// filenameUserBlockchain is the filename/folder of the user's blockchain
|
||||
const filenameUserBlockchain = "self.blockchain"
|
||||
|
||||
// the key names in the key/value database are constant and must not collide with block numbers (i.e. they must be >64 bit)
|
||||
const keyHeaderHeight = "header.height"
|
||||
const keyHeaderVersion = "header.version"
|
||||
const keyHeaderSignature = "header.signature"
|
||||
|
||||
// BlockchainHeader is the virtual blockchain header. The data is not stored as single header record, but split up.
|
||||
type BlockchainHeader struct {
|
||||
Height uint64
|
||||
Version uint64
|
||||
PublicKey *btcec.PublicKey
|
||||
}
|
||||
|
||||
var userBlockchainDB store.Store
|
||||
var userBlockchainHeader BlockchainHeader
|
||||
|
||||
// initUserBlockchain initializes the users blockchain. It creates the blockchain file if it does not exist already.
|
||||
// If it is corrupted, it will log the error and exit the process.
|
||||
func initUserBlockchain() {
|
||||
// open existing blockchain file or create new one
|
||||
blockchain, err := store.NewPebbleStore(filenameUserBlockchain)
|
||||
if err != nil {
|
||||
Filters.LogError("initUserBlockchain", "error opening user blockchain: %s\n", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// verify header
|
||||
var height, version uint64
|
||||
heightB, found1 := blockchain.Get([]byte(keyHeaderHeight))
|
||||
versionB, found2 := blockchain.Get([]byte(keyHeaderVersion))
|
||||
headerSignature, isSignature := blockchain.Get([]byte(keyHeaderSignature))
|
||||
|
||||
if found1 && len(heightB) != 8 || found2 && len(versionB) != 8 || isSignature && len(headerSignature) != 65 {
|
||||
Filters.LogError("initUserBlockchain", "corrupt user blockchain database. Invalid header length. Height is '%s', version '%s' and signature '%s'.\n", hex.EncodeToString(heightB), hex.EncodeToString(versionB), hex.EncodeToString(headerSignature))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if found1 && len(heightB) == 8 {
|
||||
height = binary.BigEndian.Uint64(heightB)
|
||||
}
|
||||
if found2 && len(heightB) == 8 {
|
||||
version = binary.BigEndian.Uint64(versionB)
|
||||
}
|
||||
|
||||
if isSignature {
|
||||
// validate header signature
|
||||
headerA := strconv.FormatUint(height, 10) + "/" + strconv.FormatUint(version, 10)
|
||||
headerPublicKey, _, err := btcec.RecoverCompact(btcec.S256(), headerSignature[:], hashData([]byte(headerA)))
|
||||
if err != nil {
|
||||
Filters.LogError("initUserBlockchain", "corrupt user blockchain database. Error decoding signature. Height is '%s', version '%s', signature '%s'. %s\n", hex.EncodeToString(heightB), hex.EncodeToString(versionB), hex.EncodeToString(headerSignature), err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
if !headerPublicKey.IsEqual(peerPublicKey) {
|
||||
Filters.LogError("initUserBlockchain", "corrupt user blockchain database. Signature key mismatch. Height is '%s', version '%s', signature '%s'.\n", hex.EncodeToString(heightB), hex.EncodeToString(versionB), hex.EncodeToString(headerSignature))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
userBlockchainHeader = BlockchainHeader{Height: height, Version: version, PublicKey: headerPublicKey}
|
||||
|
||||
} else if !found1 && !found2 && !isSignature {
|
||||
// First run: create header signature!
|
||||
height = 0
|
||||
version = 0
|
||||
signature, _ := blockchainCreateHeaderSignature(height, version)
|
||||
if err := blockchain.Set([]byte(keyHeaderSignature), signature); err != nil {
|
||||
Filters.LogError("initUserBlockchain", "initializing user blockchain: %s", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
} else {
|
||||
// header signature not present, but height/version is -> corrupt data.
|
||||
Filters.LogError("initUserBlockchain", "corrupt user blockchain database. Height is '%s', version '%s' and signature '%s'.\n", hex.EncodeToString(heightB), hex.EncodeToString(versionB), hex.EncodeToString(headerSignature))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
userBlockchainDB = blockchain
|
||||
}
|
||||
|
||||
func blockchainCreateHeaderSignature(height, version uint64) (signature []byte, err error) {
|
||||
headerA := strconv.FormatUint(height, 10) + "/" + strconv.FormatUint(version, 10)
|
||||
signature, err = btcec.SignCompact(btcec.S256(), peerPrivateKey, hashData([]byte(headerA)), true)
|
||||
|
||||
if err != nil {
|
||||
Filters.LogError("blockchainCreateHeaderSignature", "creating signature of '%s': %s\n", headerA, err.Error())
|
||||
}
|
||||
|
||||
return signature, err
|
||||
}
|
||||
|
||||
// UserBlockchainHeader returns the users blockchain header which stores the height and version number.
|
||||
func UserBlockchainHeader() (header BlockchainHeader) {
|
||||
return userBlockchainHeader
|
||||
}
|
||||
|
||||
// ---- low-level blockchain manipulation functions ----
|
||||
|
||||
@@ -10,6 +10,7 @@ package core
|
||||
func Init() {
|
||||
initFilters()
|
||||
initPeerID()
|
||||
initUserBlockchain()
|
||||
initKademlia()
|
||||
initMessageSequence()
|
||||
initSeedList()
|
||||
|
||||
Reference in New Issue
Block a user