Initial code to read/create the users blockchain database on the file system.

This commit is contained in:
Kleissner
2021-08-11 22:36:47 +02:00
parent afef726aaf
commit 5d01fc6c72
2 changed files with 109 additions and 0 deletions

View File

@@ -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 ----

View File

@@ -10,6 +10,7 @@ package core
func Init() {
initFilters()
initPeerID()
initUserBlockchain()
initKademlia()
initMessageSequence()
initSeedList()