database

package
v0.9.32 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 21, 2024 License: MIT Imports: 37 Imported by: 0

Documentation

Overview

Package database defines how to write and read data to filesystem using bolt db. It also imports stuff like block so that it knows what data it is handling. It also includes all networking-related code (because this is where lots of data comes from).

Index

Constants

View Source
const (

	// RANodeID holds the known nodeID of root authority (before production use, if you want to change RA private key ensure that this address is correctly derived from your new RA public key)
	RANodeID = "12D3KooWEYSb69dzeojEH1PygPWef9V1qQJqrGKUEMMsbA4keAyZ"

	// RendezvousString is the rendezvous string for initial node discovery
	RendezvousString = "gophypouwblockchain"

	// BlockTime is the interval at which RA broadcasts new problems and ideally creates new blocks. 86400 sec is around one day, for running tests i will use 1200 (20 min block time which is much faster than production target)
	BlockTime = 1200

	// TransactionsPerBlockCap is the Transactions per Block Upper Cap (each block can contain up to this many transactions)
	TransactionsPerBlockCap = 4757 // rough estimate rationale can be found in transaction.go

	// TransactionsPerNodePerBlockCap is an upper cap to the amount of tx each sender is allowed to have included in a singe block (avoids high fee tx spam of a rich malicious node to prevent tx of other nodes)
	TransactionsPerNodePerBlockCap = 10

	// DebugLogging affects how much data is being logged, setting it to true results in a huge log file because all state and state merkle related info is logged
	DebugLogging = false

	// MaxReferenceLength defines an upper cap for how many chars are allowed to be put in the transaction 'Reference' field
	MaxReferenceLength int = 12

	// RAMaxSizeAcceptedSolutionData defines the maximum size of solution data in bytes that can be accepted from a miner (to prevent resource-exhaustion attacks there should be an upper cap)
	RAMaxSizeAcceptedSolutionData uint64 = 1073741824 // 1 GB

	// SyncMode is an alias for int which is used as a kind of enum that does not exist in Go (remember to add new stuff also to stringer interface in transport.go)
	SyncMode_Initial_Full Mode = iota + 1 // ensure to NOT start at 0 because that is the nil value of int which could lead to confusing problems
	SyncMode_Initial_Light
	SyncMode_Initial_Mine
	SyncMode_Continuous_Full
	SyncMode_Continuous_Light
	SyncMode_Continuous_Mine
	SyncMode_Passive_Full // Miners should be in Continuous_Mine, that's why there is no Passive_Mine
	SyncMode_Passive_Light

	// TSData also is an alias for int which is used as enum to describe data types during transport (remember to add new stuff also to stringer interface in transport.go)
	TSData_Block           TSData = iota + 21 // iota ensures auto-increment for each element
	TSData_Header                             //
	TSData_StringSlice                        //
	TSData_SimulationTask                     // SimulationTask is defined in simpar.SimulationTask
	TSData_SimSol                             // this means you are sending/receiving a simsol.BlockProblemSolution
	TSData_MinerCommitment                    // defined in simsol.MinerCommitment
	TSData_RAcommitSecret                     // string that is revealed as soon as block problem expires
	TSData_ChainDBRequest                     // you want to request chaindb data from any node
	TSData_Transaction                        // transaction.Transaction
	TSData_LiveData                           // Struct that holds BlockProblemHelper and slice of pending transactions
)

Variables

View Source
var HttpPort int

HttpPort defines on which port the local websites for sending transactions and simtasks are run on

View Source
var HttpapiSimparMutex sync.Mutex

HttpapiSimparMutex is a mutex used to allow concurrency-safe access to pending simtasks (use this for writing)

View Source
var HttpapiSimparRMutex sync.RWMutex

HttpapiSimparRMutex is a mutex used to allow concurrency-safe access to pending simtasks (use this for read-only)

View Source
var HttpapiTransactionMutex sync.Mutex

HttpapiTransactionMutex is a mutex used to allow concurrency-safe access to pending transactions (use this for writing)

View Source
var HttpapiTransactionRMutex sync.RWMutex

HttpapiTransactionRMutex is a mutex used to allow concurrency-safe access to pending transactions (use this for read-only)

View Source
var IAmFullNode bool

IAmFullNode describes whether a node is a full node or not

View Source
var IAmRA bool

IAmRA describes whether a node is the RA or not

View Source
var MyDockerAlias string

MyDockerAlias specifies the name of the docker instance that runs this node. Useful for connecting the performance stat reported by a node with its docker identity (if it would report its libp2p node ID it would be a lot of manual work to see whether the given string maps to 1f or 2f or whatever)

View Source
var MyNodeIDString string

MyNodeIDString holds your own nodeID as 12D3Koo... string

View Source
var PendingSimpars = [][]simpar.SimulationParameters{} // each SimTask can consist of many simpar
View Source
var PendingTransactions = []transaction.Transaction{}

keep track of pending transactions and simpars

View Source
var PrivateKey crypto.PrivKey

PrivateKey holds your own private key. TODO: it would be better if this is only temporarily retrieved from libp2p keystore whenever its needed and then asap safely removed from memory. but for PoC demonstration this is fine for now

View Source
var PubsubTopicSlice = []*pubsub.Topic{}

PubsubTopicSlice holds all *pubsub.Topic

View Source
var RAnonce int

RAnonce is a global nonce for testing/simulation purposes

RApub is the known public key of the RA (will be dynamically set by converting RANodeID constant to PubKey)

View Source
var TopicSlice = []string{}

TopicSlice holds topics (as strings) that user wants to subscribe to

Functions

func AddPendingSimpar

func AddPendingSimpar(simparSlice []simpar.SimulationParameters)

AddPendingSimpar is used after the RA used to locally hosted website to broadcast a new simulation task to add the input values as SimulationParameters object to the slice PendingSimpars. Note 1: The 'Seed' fields (uint32) of s have not been set yet because they have to be determined in real-time whenever a new simpar slice is retrieved from the queue (Seed which depends on previous block hash which depends on when the simpar slice is retrieved). Note 2: This function assumes that the validity of each simpar in the passed slice has been checked for validity using SubproblemIsValid.

func AddPendingTransaction

func AddPendingTransaction(t transaction.Transaction)

AddPendingTransaction adds a transaction received via the transaction topic handler to the slice PendingTransactions in a concurrency-safe way. The transction is only added, if it is not already included in the slice (unique txhash). Note: A pending transaction is a transaction that is valid at the point in time that it was added to the slice. However, after choosing which transactions to include in a block the RA must re-check the validity of these transactions in the selected order (e.g. nonce might now be wrong or balance of second transaction sender is now too low)

This means that even after retrieving the transactions from the pending transactions slice you still need to ensure that the set of transactions you chose is still valid in the selected order.

func AmIInterestedInThisDirectChatData

func AmIInterestedInThisDirectChatData(syncMode Mode, recDataType TSData) bool

AmIInterestedInThisDirectChatData checks whether a node in a given sync mode is interested of received data of a given type. Returns true if the data is of interest, returns false if the data should be ignored.

func BlockGetBytesFromDb

func BlockGetBytesFromDb(chaindbKey string) ([]byte, error)

BlockGetBytesFromDb takes a db key, checks whether this value is "latest" or a valid key in the local database and if so, returns the value of this key-value pair as bytes. Note that a full node that calls this function retrieves a block.Block, while a light node that calls this function retrieves a block.Header. Mutex required because db access.

func BlockVerifyValidity

func BlockVerifyValidity(fullNode bool, prev []byte, new []byte, newBlockIsFull bool) error

BlockVerifyValidity takes a bool (iAmFullNode), and two blocks (might just be header if you are light node) in serialized form (prev and new) and another bool (newBlockIsFull is used so that light nodes can receive new full blocks broadcast by the RA and extract their header) and then checks whether the latter block or header can be a continuation of the former without affecting the state. Light nodes do not have access to the state, that's why they only do the checks that they can do. Full nodes safely determine the validity of everything that affects that state without actually affecting the state. Returns an error that is only nil if the latter block is a valid continuation of the former. The following validity checks are done:

  1. PrevBlockHash of new is equal to blockHash of prev
  2. Block ID increased by 1
  3. Timestamp larger 3.5 Token reward was calculated correctly according to formula
  4. Transaction Signatures are valid [full node only]
  5. Transaction list merkle tree roothash was calculated correctly [full node only]
  6. All transactions are valid check [full node only]
  7. State merkle tree after processing block matches blockheader value

If BPH is populated:

  1. Did RA choose correct problem (unique problem hash matching)

func BlockWriteToDb

func BlockWriteToDb(blockData []byte, fullBlock bool) error

BlockWriteToDb writes only to the chaindb bucket. It receives bytes from networking (block content) and a bool description whether these bytes represent a serialized full block or just a block header. Then the blockHash (which will be key) is determined and then the key-blockBytes pair is written to the database. You should only call this function after ensuring the validity of the block. Returns success code (nil on success). Mutex required because db access happens.

func BlockchainVerifyValidity

func BlockchainVerifyValidity(fullNode bool, measurePerformance bool) error

BlockchainVerifyValidity goes through every block in the local blockchain and ensures that the chaindb data is valid. It then tries to locally build the statedb from the given chaindb data, this means calling BlockchainVerifyValidity() does affect the state! Return an error that is only nil when the blockchain is valid, otherwise returns an error that describes why the blockchain is not valid. Note: Blocks being 'valid' means that the chain of blocks abides to certain rules (block ID + 1, timestamp <=, ...) and that the statedb was affected according to the data found in chaindb blocks. Note 2: This function assumes that the chaindb is fully populated and that the statedb is not populated yet.

func BoltBucketExists

func BoltBucketExists(bucketName string) bool

BoltBucketExists checks whether a given bucket name exists in the db or not. This function is used by the -dump flag functionality to determine whether the retrieved chaindb data will be a serialized full block or a serialized header, which only works because light nodes do not have the statedb bucket at all.

func BoltGetChainDBKeys

func BoltGetChainDBKeys() []string

BoltGetChainDBKeys returns a []string which contains all keys of chaindb bucket.

func BoltGetDbKeys

func BoltGetDbKeys(bucketName string) []string

BoltGetDbKeys takes the name of a db bucket and returns a sorted []string which contains all keys of that bucket. When bucket statedb is specified this would return the nodeID addresses of all nodes that at some point had a non-zero balance (either they were sent currency or they were chosen blockwinner at some point). The returned slice entries are sorted by ascending order (0<9<a<z and abc < abc0) and the order is case-insensitive.

func BytesToSimsolBlockProblemSolution

func BytesToSimsolBlockProblemSolution(s []byte) simsol.BlockProblemSolution

BytesToSimsolBlockProblemSolution takes bytes and deserializes them into simsol.BlockProblemSolution. This function is used only by the RA after it has received a miner solution that it knows it can deserialize. Only call this after TSStructExtraction verified that it is valid data that actually can be deserialized without issues.

func BytesToStringSlice

func BytesToStringSlice(acceptedData []byte) []string

BytesToStringSlice unmarshals []byte to []string. It is used during networking to prepare to request each required block one-by-one.

func ChainDBRequestToBytes

func ChainDBRequestToBytes(c ChainDBRequest) ([]byte, error)

ChainDBRequestToBytes casts an instance of ChainDBRequest to bytes by serializing it.

func ChainDbGetGenesisHash

func ChainDbGetGenesisHash(iAmAFullNode bool) string

ChainDbGetGenesisHash retrieves the hash of the genesis block and returns it as string. Used for the -dump flag's 'genesis' functionality.

func CreatePseudoBlockchainFull

func CreatePseudoBlockchainFull(blockAmount int, RApw string, transactionAmountPerBlock int) error

CreatePseudoBlockchainFull is a helper testing function which creates a few example block.Block and adds them to pouw_blockchain.db. This function affects both the chaindb bucket and the statedb bucket. This function takes two parameters: Firstly the amount of blocks to be created, secondly the key password of the RA so that valid transactions can be created. If you pass 1 for the amount of blocks you will get genesis + one additional block, so 2 blocks in total (genesis is not counted in what is passed by the user).

func CreatePseudoBlockchainLight

func CreatePseudoBlockchainLight(blockAmount int) error

CreatePseudoBlockchainLight is a helper testing function which creates a few example block.Header and adds them to pouw_blockchain.db. This function affects only the chaindb bucket.

func CreateRandomTransaction

func CreateRandomTransaction(RApw string) transaction.Transaction

CreateRandomTransaction is used to generate a (pseudo-)random, valid transaction. This function assumes that the location of the private key used is the rootdir.

func DetermineLocallyMissingBlockHashes

func DetermineLocallyMissingBlockHashes(recBlockHashes []string, fullNodes bool) ([]string, error)

DetermineLocallyMissingBlockHashes takes a slice of received blockHashes and then compares them with locally available blocks to determine which blocks are missing. This function returns all missing blocks (err nil) as string slice, but only if all locally available blockhashes are a subset of the received blockHashes (otherwise err != nil).

func DiscoverPeers

func DiscoverPeers(ctx context.Context, h host.Host, ch chan bool)

DiscoverPeers uses Kademlia DHT bootstrap nodes and the Rendezvous protocol.

func EncryptKeyAndWriteToFile

func EncryptKeyAndWriteToFile(privkey ed25519.PrivateKey, password string, outputLocation string, comment string)

EncryptKeyAndWriteToFile takes a private ed25519 key, a password and a filepath string and writes the encrypted key in OpenSSH format to that location.

func FullBlockBytesToBlock

func FullBlockBytesToBlock(blockData []byte) block.Block

FullBlockBytesToBlock takes a serialized byte slice that represents a full block and returns a block.Block object. This function is used e.g. in combination with BlockGetBytesFromDb() which returns a serialized block from the db.

func FullBlockBytesToBlockLight

func FullBlockBytesToBlockLight(blockData []byte) (block.Header, hash.Hash)

FullBlockBytesToBlockLight takes a serialized byte slice that represents a block.Block and returns a block.Header (which basically is a light block) and its hash. It's used so that full nodes can serve content to light nodes.

func FullBlockToFullBlockBytes

func FullBlockToFullBlockBytes(blk block.Block) []byte

FullBlockToFullBlockBytes takes a block instance and serializes it and returns these serialized block bytes.

func GenerateRandomIntBetween

func GenerateRandomIntBetween(min int, max int) int

GenerateRandomIntBetween takes min and max and returns an int in [min,max]

func GenerateRandomStringOfLength

func GenerateRandomStringOfLength(stringlen int) string

GenerateRandomStringOfLength generates random bytes, encodes them to base58 (like libp2p peerIDs) and return the first stringlen characters of that string (stringlen is the int input parameter of the function).

func GetAllBlockHashesAscending

func GetAllBlockHashesAscending(fullNode bool) ([]string, error)

GetAllBlockHashesAscending goes through every block of the local database and returns their hashes in ascending order (ascending by block ID, not by hash). Returns slice of strings, so the blockHashes can be seen as hex strings. Returned data starts at genesis block with index 0.

func GetAllBlockHashesAscendingSerialized

func GetAllBlockHashesAscendingSerialized(fullNodes bool) []byte

GetAllBlockHashesAscendingSerialized uses GetAllBlockHashesAscending() to get a string slice of all block hashes and then return them as serialized msgpack object. Returned data starts at genesis block with index 0.

func GetPendingTransactionSlice

func GetPendingTransactionSlice() []transaction.Transaction

GetPendingTransactionSlice returns slice of currently pending transactions. Used by RA to reply to live data requests.

func HandleIncomingChatMessage

func HandleIncomingChatMessage(chatStream network.Stream, h host.Host, ctx context.Context)

HandleIncomingChatMessage is used to handle directly incoming data. It receives incoming messages on registered protocol (chat1.0) and reads until newline. Note: If the sent message does not have a newline \n, then nothing will be received on the receiving end, so when sending a message make sure to append \n to the end.

func HeaderBytesToBlockLight

func HeaderBytesToBlockLight(blockData []byte) (block.Header, hash.Hash)

HeaderBytesToBlockLight takes a serialized byte slice that represents a block.Header and returns a block.Header.

func HeaderToBytes

func HeaderToBytes(h block.Header) []byte

HeaderToBytes takes a block.Header and returns it as msgpacked []byte.

func HeaderToHash

func HeaderToHash(header block.Header) hash.Hash

HeaderToHash takes a block.Header and returns its hash.Hash

func HexStringToNumber

func HexStringToNumber(a string) uint64

HexStringToNumber takes the output string of a hash function and returns a uint64 number that is derived from this value. The first 15 chars of the input string are converted (to guarantee that it fits into uint64) and the rest is ignored.

func InitDHT

func InitDHT(ctx context.Context, h host.Host) *dht.IpfsDHT

InitDHT connects to a few known default bootstrap nodes (they enable distributed node discovery and are the only centralized necessity in kademlia DHT).

func IsPendingSimparAvailable

func IsPendingSimparAvailable() (bool, []simpar.SimulationParameters)

IsPendingSimparAvailable checks whether PendingSimpars is empty or not. Returns true and the first added simpar slice if there is sth in the queue, returns false and zero value of SimulationParameters when empty. This function is used by the RA when a new block has been created and a new simtask should be sent out: If a pending simpar slice is available it will be used to construct the next SimulationTask (for this additional parameters will have to be determined), otherwise RA will automatically generate a random simtask (to keep transaction throughput up).

func NewTransportStruct

func NewTransportStruct(dataID TSData, originalSenderNodeID string, data []byte) []byte

NewTransportStruct is the constructor for TransportStruct. Note that it returns the msgpack serialized instance of the created struct to simplify networking calls.

func NodeIDStringToPubKey

func NodeIDStringToPubKey(nodeIDString string) (crypto.PubKey, error)

NodeIDStringToPubKey uses btcsuite's base58 decode to convert NodeID to the Ed25519 public key of that node. This function is required so that signatures can be verified. Alternatively, you can use libp2p builtin function to get public key from node id.

func PendingTransactionsRemoveThese

func PendingTransactionsRemoveThese(tl []transaction.Transaction)

PendingTransactionsRemoveThese takes a list of transactions that were included in a block and removes them from pending transactions if possible Note: AFAIK there should be no need to panic if a transaction that is not in pending was included in a block. RA can not forge transactions due to the signatures and can not replay them due to the Nonces.

func PerformStateDbTransaction

func PerformStateDbTransaction(fromAddress string, updatedFromValue []byte, toAddress string, updatedToValue []byte) error

PerformStateDbTransaction takes transaction related info (state of involved wallets after tx was processed) as input and performs the transaction to affect the state. That means 'From' balance is decreased by Amount+Fee, 'From' Nonce is increased by 1, and 'To' balance is increased by Amount. The function returns nil on success and panics if something went wrong (at some point try to recover here, it should not happen anyways for now).

func PrintBlock

func PrintBlock(b block.Block)

PrintBlock prints the entire block content.

func PrintBlockHeader

func PrintBlockHeader(h block.Header)

PrintBlockHeader prints the provided block.Header. It is used in combination with the dump flag, where the user provides the key of the block that he wants to see printed out.

func PrintSerializedStringSliceBlockHashes

func PrintSerializedStringSliceBlockHashes(receivedMessage []byte)

PrintSerializedStringSliceBlockHashes takes a serialized slice of strings, and prints its content after deserialization.

func PrintStateDB

func PrintStateDB()

PrintStateDB gets all keys from the statedb, retrieves the corresponding values (wallets) and prints their info.

func PrintStateDbWallet

func PrintStateDbWallet(w StateValueStruct, keyValue string)

PrintStateDbWallet takes a StateValueStruct and prints it.

func PubKeyToNodeID

func PubKeyToNodeID(pubKeyObject crypto.PubKey) (string, error)

PubKeyToNodeID takes a PubKey and returns the human-readable node ID (12D3Koo...)

func RACreateNewBlock

func RACreateNewBlock(blkWinner winner.BlockWinner, transactionList []transaction.Transaction, simTask simpar.SimulationTask) block.Block

RACreateNewBlock is used by RA to create new chaindb block after block problem has been solved and winner has been chosen.

func RAGetPendingTransactions

func RAGetPendingTransactions() ([]transaction.Transaction, error)

RAGetPendingTransactions is used by RA to get up to <TransactionsPerBlockCap> many transactions from the PendingTransactions slice. This function is used before a new block is created to fill it with pending transactions. The goal of the algorithm is to prefer high Fee transactions, while also avoiding Nonce conflicts (e.g. same node sends three transactions with nonces 1,2 and 3. Now if tx with Nonce 2 has a fee so low that it is not included in the block, tx with Nonce 3 would be invalid and can not be included as well. you also are not able to dynamically update nonces because then replay attacks would be trivial unless more adjustments in other places are made). Note: The transaction list returned by this function must still be checked for validity! For instance, it's possible that after transaction 1 a sender node is too poor for transaction 2 even if it would seem like two valid transactions in isolation.

func RALoop

func RALoop(ctx context.Context)

RALoop is the loop that the RA is in. It defines new sim tasks, collects results, chooses block winner, creates new block etc.

func RAReceivedSimSol

func RAReceivedSimSol(tsData []byte, senderPubKey crypto.PubKey, senderNodeID string)

RAReceivedSimSol is used by the RA to determine the validity of a received simulation solution and to store it if it is valid.

func RaGetProblemDefMessage

func RaGetProblemDefMessage() ([]byte, hash.Hash, string)

RaGetProblemDefMessage is used to generate a new valid simtask. This function should only be used when there is no queued simtask available in the queue, actual problems are always to be prefered. It returns:

  1. signed TransportStruct in msgpacked form so that can be directly sent to topic "pouw_newProblem"
  2. RAcommit hash
  3. secretCommit string

func RandomShortSleep

func RandomShortSleep()

RandomShortSleep is used to sleep for a short amount (between 5 and 15 milliseconds). It is used to retry something networking-related after a short delay.

func ReadFromBucket

func ReadFromBucket(bucketKey string, bucketName string) ([]byte, error)

ReadFromBucket takes a key as string and returns its corresponding value as []byte. Will return an error if the key does not exist.

func ReadKeyFromFileAndDecrypt

func ReadKeyFromFileAndDecrypt(password string, keyLocation string) ed25519.PrivateKey

ReadKeyFromFileAndDecrypt takes the password that the key was encrypted with and the location of the key and returns the decrypted ed25519.PrivateKey)

func RemoveDuplicateStrings

func RemoveDuplicateStrings(ss []string) []string

RemoveDuplicateStrings removes duplicate strings from []string and return the cleansed slice that does not contain any duplicates.

func ResetAndInitializeGenesis

func ResetAndInitializeGenesis(fullNode bool)

ResetAndInitializeGenesis deletes the local database, creates a new database with chaindb and statedb buckets and then initializes the genesis block. Either the function works and nothing is returned or it panics. Mutex needed because db access.

func ResetBucket

func ResetBucket(bucketName string) error

ResetBucket deletes and re-creates the given bucket. Used by RA to reset simdb bucket before broadcasting new block problem.

func SendViaChat

func SendViaChat(data []byte, targetPeer peer.ID, h host.Host, ctx context.Context) error

SendViaChat is used to send a message directly to a peer (no topic involved). It takes a message (usually wrapped in TSStruct), a peerID, a host and a context and sends it via libp2p's /chat/1.0 protocol to the set recipient. Returns nil if everything went smoothly, otherwise returns an error message.

func SimSolToBytes

func SimSolToBytes(s simsol.SimulationSolution) ([]byte, error)

SimSolToBytes takes a simsol.SimulationSolution, serializes it and returns that data and an error.

func SimparToSimtask

func SimparToSimtask(simparSlice []simpar.SimulationParameters) ([]byte, hash.Hash, string)

SimparToSimtask takes a simpar slice that was retrieved from the queue 'PendingSimpars', sets the correct value for each 'Seed' field, then determines further values needed to construct SimulationTask and then returns 3 values: It returns:

  1. signed TransportStruct in msgpacked form so that can be directly sent to topic "pouw_newProblem"
  2. RAcommit hash
  3. secretCommit string

func SimtaskBytesToSimTask

func SimtaskBytesToSimTask(s []byte) simpar.SimulationTask

SimtaskBytesToSimTask takes serialized SimulationTask as bytes and returns it as simpar.SimulationTask object. Only call this after TSStructExtraction verified that it is valid data that actually can be deserialized without issues.

func SimtaskToBytes

func SimtaskToBytes(s simpar.SimulationTask) []byte

SimtaskToBytes takes a SimulationTask and returns the msgpacked bytes.

func SimtaskValidityCheck

func SimtaskValidityCheck(s simpar.SimulationTask, h block.Header) error

SimtaskValidityCheck takes a simulationTask (problem def) and the latest block header, and then determines whether this simTask is valid or not and returns err (only nil return means valid). Rules:

	 	Header:
			1. s.SimHeader.CreationTime > b.Timestamp
			2. s.SimHeader.ExpirationTime > s.SimHeader.CreationTime
			3. s.SimHeader.BlockId == b.BlockID + 1
		  3.5. s.SimHeader.AmountSubProblems == len(s.SimHeader.SubProblemHashes) == len(s.SimPar)
  	Subproblems:
			4. Seed converted to hex string must match first 6 chars of blockHash of b
			5. Seed must be <= 900000000 (pythia max seed)
			6. Particles must be equal to 0 (pions), 1 (eplus) or 2 (proton)
			7. Hash of subproblem is valid (re-create the SimulationParameters object and compare with hash that will automatically be calculated)

func SortStringSliceAscending

func SortStringSliceAscending(stringsToSort []string)

SortStringSliceAscending takes a string slice and sorts it (original is modified) ascending, case-insensitive. Ascending means 0<9<a<z and abc < abc0.

func StateDbAwardWinner

func StateDbAwardWinner(nodeID string, tokenAmount float64)

StateDbAwardWinner is used when a block that has been signed by the RA is received to award the block's winner address. In order to determine tokenAmount a previous call to winner.GetTokenRewardForBlock(blockIndex int) should be made before calling this function.

func StateDbGetMerkleProof

func StateDbGetMerkleProof(nodeID string, stateMerkleTree merkletree.MerkleTree) ([]hash.LRHash, error)

StateDbGetMerkleProof takes a nodeID and a stateMerkleTree and returns the merkle proof for that leaf.

func StateDbGetMerkleTree

func StateDbGetMerkleTree() merkletree.MerkleTree

StateDbGetMerkleTree uses bbolt to get all keys of statedb in ascending order, then gets their values and hashes them, then these hashes are used ascending as leafs of the merkle tree. Then the merkle tree is built and returned. This function will be called anytime after a new block has been fully processed to rebuild the statedb's Merkle Tree.

func StateDbNodeIDToMerkleHash

func StateDbNodeIDToMerkleHash(nodeID string) (hash.Hash, error)

StateDbNodeIDToMerkleHash takes a nodeID as string and returns its corresponding hash in the state merkle tree. In the state merkle tree, the hash of a nodeID is actually nodeID+<statedb value of node> to bind the account to its current data. This allows reusing the same Merkle Tree code that was used for chaindb transactions.

func StateDbProcessAndUpdateBlock

func StateDbProcessAndUpdateBlock(b block.Block) (block.Block, error)

StateDbProcessAndUpdateBlock takes a block and performs its transactions in the statedb (statedb is affected) while also awarding the winner of this block. Returns the block with its updated StateMerkleRoot and updated TransactionsMerkleRoot. For pseudo sim: Note that now the block will have a new hash which means a new key for being stored in chaindb. Note: Before calling this function use BlockVerifyValidity() to ensure that all transactions are valid in this order, otherwise this function here could fail while runing leaving a corrupted state (e.g. transaction 3 fails when it occurs after transaction 2 but it seemed to be valid in isolation). This function only performs validity checks for included transactions, but it does not check the validity of other block fields like e.g. stateMerkleRootHash which makes it compatible with pseudo where this value is not known yet.

func StateDbStructToBytes

func StateDbStructToBytes(s StateValueStruct) ([]byte, error)

StateDbStructToBytes takes a StateValueStruct and msgpack serializes it. Returns serialized data and error.

func StateDbTransactionIsAllowed

func StateDbTransactionIsAllowed(t transaction.Transaction, readActualStateFromDb bool, pseudoStateFrom []byte, pseudoStateTo []byte) (error, string, []byte, string, []byte)

StateDbTransactionIsAllowed takes a transaction and checks whether it is valid or not. If it is valid, it will determine the new statedb values of both account involved in the transaction and return the data in such a way that it will be easy to actually perform the transaction without having to perform unnecessary, additional statedb lookups. This function's behavior can be toggled with a bool so that in-memory pseudo states are used instead of reading the actual current state from the db file, which is used by BlockVerifyValidity() which wants to safely determine validity without touching the state. In order to avoid duplication of verification logic, I added this bool so that this function's behavior can be adjusted when needed. Here is a list of things that must be true so that the transaction can be allowed:

  1. TxHash has been calculated correctly
  2. From and To addresses start with "12D3Koo" AND From and To addresses are not identical (can't send tokens to yourself)
  3. Transaction Signature is valid
  4. From Balance >= Amount + Fee 3.4 Fee >= winner.MinTransactionAmount 3.5 ensure that amount sent is at least as large as winner.MinTransactionAmount
  5. Nonce of 'From' is increased by 1 compared to current statedb value Nonce
  6. TxTime is later than 2024-01-01 and earlier than current time (i guess this is a reasonable check, the time basically is just used to make TxHash unique so rough estimation if the timestamp makes sense is good enough)

Note: This function does not actually affect the statedb, it does not perform the transaction.

This function returns the following values:

error: 	this is either nil (valid transaction) or holds error message (why transaction is not valid)
string:	t.From (who sent the transaction)
[]byte:	Serialized StateValueStruct of t.From (state of the transaction sender wallet after transaction would have been sent)
string: t.To (who receives the transaction)
[]byte: Serialized StateValueStruct of t.To (state of the transaction receiver wallet after transaction would have been performed)

func SubproblemIsValid

func SubproblemIsValid(amountEvents string, runID string, particles string, momentum string, theta string) (bool, simpar.SimulationParameters)

SubproblemIsValid takes the string values of the fields of the submit-simtask form and aims to ensure that each field is valid (e.g. no string in a field where uint32 is expected). Returns true and the SimulationParameters object that holds these values in the correct type if the subproblem fields have valid values, otherwise returns false.

func SyncNode

func SyncNode(ctx context.Context, h host.Host, initialSyncDone chan struct{})

SyncNode starts an automatic sync between nodes.

Phase 1: First initial sync mode is triggered where a list of blockHashes is requested from multiple nodes until it is accepted.
Phase 2: Then each block is requested indiviudally
Phase 3: When all blocks are received the blockchain is checked for validity (builds statedb too).

Then you switch to the final sync mode (there are flowcharts that define which initial mode ends up in which final mode):

Phase 4: Then the nodes switches to its final sync mode which affects how it will behave.

func TopicChaindbReceiveEvent

func TopicChaindbReceiveEvent(m pubsub.Message, h host.Host, ctx context.Context)

TopicChaindbReceiveEvent is a topic-specific function that is triggered when a node receives a message for topic "pouw_chaindb".

func TopicNewBlockReceiveEvent

func TopicNewBlockReceiveEvent(m pubsub.Message, h host.Host, ctx context.Context)

TopicNewBlockReceiveEvent is a topic-specific function that is triggered when a node receives a message in topic "pouw_newBlock". The topic is used by the RA to send out new chaindb blocks to the network. Nodes will ignore any message sent to this topic, if its signature is not that of the RA.

func TopicNewCommitmentReceiveEvent

func TopicNewCommitmentReceiveEvent(m pubsub.Message, h host.Host, ctx context.Context)

TopicNewCommitmentReceiveEvent is a topic-specific function that is triggered when a node receives a message for topic "pouw_minerCommitments".

func TopicNewProblemReceiveEvent

func TopicNewProblemReceiveEvent(m pubsub.Message, h host.Host, ctx context.Context)

TopicNewProblemReceiveEvent is a topic-specific function that is triggered when a node receives a message in topic "pouw_newProblem". The topic is used by the RA for two purposes:

  1. Sending out new block problem definitions (SimPar)
  2. Revealing RAcommitSecret which is used for winner selection (RAcommitSecret)

Nodes will ignore any message sent to this topic, if its signature is not that of the RA. Nodes in initial sync mode ignore messages from this topic.

func TopicNewRASecretRevealEvent

func TopicNewRASecretRevealEvent(m pubsub.Message, h host.Host, ctx context.Context)

TopicNewRASecretRevealEvent is a topic-specific function that is triggered when a node receives a message in topic "pouw_raSecretReveal". This implies that the current block problem has expired, the RA reveals the previously generated random bytes whose hash was already known to all nodes. The value is needed to form consensus between nodes on how to choose the block winner from the eligible miners list.

func TopicNewTransactionReceiveEvent

func TopicNewTransactionReceiveEvent(m pubsub.Message, h host.Host, ctx context.Context)

TopicNewTransactionReceiveEvent is a topic-specific function that is triggered when a node receives a message for topic "pouw_transactions".

func TopicReceiveMessage

func TopicReceiveMessage(ctx context.Context, sub *pubsub.Subscription, h host.Host)

TopicReceiveMessage is responsible for calling a suitable topic handler function whenever a message is received on any subscribed topic.

func TopicSendMessage

func TopicSendMessage(ctx context.Context, targetTopicString string, msgContent []byte) error

TopicSendMessage is used to automatically (as in no user input from console required) send messages to a pubsub topic. Possible target topics are:

pouw_chaindb			- Used to request chaindb data from other nodes (e.g. when newly joining the network) [replies are sent via direct chat, not via this topic]
pouw_minerCommitments	- Used by miners to broadcast cryptographic commitments and signed messages to prove to the network that they knew the solution before the problem expired without revealing it.
pouw_newProblem			- Only RA should send to this topic to broadcast new block problems (if other nodes send messages to this topic they will be ignored) [solutions are sent directly to the RA, not to this topic]
pouw_newBlock			- Only RA should send to this topic to broadcast new blocks (if other nodes send messages to this topic they will be ignored)

func TransactionIsValid

func TransactionIsValid(toAddress string, value string, reference string, fee string) (bool, transaction.Transaction)

TransactionIsValid takes the string values of the fields of the submit-transaction form and aims to ensure that each field is valid. Returns true and the transaction.Transaction object that holds these values in the correct type if the subproblem fields have valid values, otherwise returns false.

func TransactionListFilterOutInvalid

func TransactionListFilterOutInvalid(tl []transaction.Transaction) []transaction.Transaction

TransactionListFilterOutInvalid takes a transaction list and filter out transactions that can not be performed. This function (in memory, without affecting statedb) goes from first to last transaction and checks each transaction for validity (in that context, so order matters). Returns a list of transaction that can be performed as-is (transactions from input list might have been removed which means these will continue to be in PendingTransactions).

func TransactionSliceToBytes

func TransactionSliceToBytes(pt []transaction.Transaction) ([]byte, error)

TransactionSliceToBytes serializes []transaction.Transaction and returns []byte and error.

func TransactionToBytes

func TransactionToBytes(t transaction.Transaction) ([]byte, error)

TransactionToBytes serializes a transaction and returns []byte and error.

func TransportStructExtraction

func TransportStructExtraction(expectedDataID TSData, tsSer []byte, onlyAllowRAoriginalSender bool) ([]byte, string, error)

TransportStructExtraction takes the expected DataID (the data type you requested) and a serialized TransportStruct (contains data you received, includes metadata) and a bool (which when true says only accept the data if it was originally sent by the RA) and then determines five things. 1. It determines whether the provided serialized TransportStruct can be deserialized into a valid TransportStruct. 2. It determines whether the contained DataID matches the ID of the expected data. 3. It determines whether the contained data can successfully be deserialized into the object that corresponds to the contained DataID. 4. Determines the hash string of the contained data (block.Block gets its BlockHeader hashed, block.Header gets itself hashed, []string is msgpacked and string()-casted and hashed) 5. Verifies that the included signature is valid to prevent nodeID spoofing. On success, this function returns the contained data as []byte, its hash as string [note: not necessarily the hash of the entire data: e.g. a full block would return the hash of its header only] and error nil. On failure nil, empty string and the error message are returned (don't panic just because a node sent you unexpected or invalid data).

func UnpackSerializedStringSliceBlockHashes

func UnpackSerializedStringSliceBlockHashes(receivedMessage []byte) ([]string, error)

UnpackSerializedStringSliceBlockHashes takes msgpack serialized slice of strings, then unpacks and returns it

func WinnerSelection

func WinnerSelection(inputEligibleMiners []ActiveMiner, raCommitSecret string) string

WinnerSelection takes a slice of elgible miners and the RAcommitSecret and then performs the winner selection after the block problem has expired and RA has published its secretCommitBytes. Returns the nodeID of the winner node.

func WriteToBucket

func WriteToBucket(key string, serializedValue []byte, bucketName string) error

WriteToBucket is the equivalent of BlockWriteToDb but instead of writing to the chaindb bucket it writes to the statedb or simdb bucket. The logic is slightly different as there is no such thing as full block / light block in this context. It takes a key (case statedb: nodeID as string, case simdb: solutionHash as string) and a value and either adds key-value pair to the database (if it does not exist already) or overwrites the value if the key already exists. An error is returned if anything goes wrong. Note: When targeting statedb bucket: This function does not check whether the value is valid, it just performs the statedb transaction and the dev is supposed to ensure the validity before calling this function.

Types

type ActiveMiner

type ActiveMiner struct {
	Commitment               simsol.MinerCommitment // Commitment 1: Hash(solutionHash) that this miner broadcast, Commitment 2: Signature Sig(solutionHash) that this miner broadcast [solutionHash unknown at least until problem expires]
	ActualSolutionHashString string                 // Only RA sets value for this
}

ActiveMiner is used to aggregate information about an active miner that has broadcast commitments before problem expiry.

func NewActiveMiner

func NewActiveMiner(commitment simsol.MinerCommitment) ActiveMiner

NewActiveMiner is the constructor for ActiveMiner. RA will later add the actually receive solutionHash to the third field.

type BlockProblemHelperStruct

type BlockProblemHelperStruct struct {
	RAcommitSecret string                // secretBytes that are only revealed by RA as soon as the block problem has expired
	Miners         []ActiveMiner         // Keep track of which active miners broadcast which commitments for the current problem
	SimulationTask simpar.SimulationTask // Keep track of all simtask details
}

BlockProblemHelperStruct is used to keep track of the current block problem and miner commitments. This will help for solution determination and winner selection procedures

var BlockProblemHelper BlockProblemHelperStruct

BlockProblemHelper is used to keep track of other miner's commitments for the current block problem

func (*BlockProblemHelperStruct) AddMiner

func (b *BlockProblemHelperStruct) AddMiner(miner ActiveMiner, skipTimeCheck bool) error

AddMiner is used to add a new ActiveMiner to the Miners slice in a concurrency-safe way. If the miner is already stored in the slice then it is not added again (only first received broadcast is accepted)

func (*BlockProblemHelperStruct) CheckIfCommitmentAvailable

func (b *BlockProblemHelperStruct) CheckIfCommitmentAvailable(nodeID string) bool

CheckIfCommitmentAvailable checks whether a given nodeID has broadcast a seemingly valid commitment yet. Returns true if commitment is already available, returns false otherwise.

func (*BlockProblemHelperStruct) DetermineEligibleMiners

func (b *BlockProblemHelperStruct) DetermineEligibleMiners(acceptedSolutionHash string) []ActiveMiner

DetermineEligibleMiners is called when problem expires to loop over all commitments and determine all miners that are eligible for winner selection. This function will perform two filtering stages, first subsolution matching (which is not yet implemented) and then it determines the most common solution. All miners with valid commitments that pass both stages are eligible for winner selection. Note: The RA is able to verify the commitment signatures before even adding a miner to the ActiveMiner slice, that's why it does not again have to check the validity of the commitment signatures (but all other nodes have to do it after receiving a new block from RA).

func (*BlockProblemHelperStruct) GetBlockID

func (b *BlockProblemHelperStruct) GetBlockID() uint32

GetBlockID gets the current blockID from the BlockProblemHelperStruct (ID of block that will be created after current problem is solved)

func (*BlockProblemHelperStruct) GetCommitment

func (b *BlockProblemHelperStruct) GetCommitment(nodeID string) simsol.MinerCommitment

GetCommitment retrieves the commitment of a miner of interest and returns it. Will panic if it doesn't exist so only only use this function after ensuring with CheckIfCommitmentAvailable().

func (*BlockProblemHelperStruct) GetCopyWithoutSecret

func (b *BlockProblemHelperStruct) GetCopyWithoutSecret() BlockProblemHelperStruct

GetCopyWithoutSecret creates an instance of BlockProblemHelperStruct that contains all current fields but the RAcommitSecret is set to empty string. Used only by RA and only to get current state of BlockProblemHelper when a node that is about to finish its initial sync requests it.

func (*BlockProblemHelperStruct) GetMiners

func (b *BlockProblemHelperStruct) GetMiners() []ActiveMiner

GetMiners is used to access the Miners slice in a concurrency-safe way.

func (*BlockProblemHelperStruct) GetProblemExpirationTime

func (b *BlockProblemHelperStruct) GetProblemExpirationTime() uint64

GetProblemExpirationTime gets the current problem expiration time from the BlockProblemHelperStruct

func (*BlockProblemHelperStruct) GetProblemID

func (b *BlockProblemHelperStruct) GetProblemID() hash.Hash

GetProblemID gets the current problemID from the BlockProblemHelperStruct (unique hash of currently active block problem)

func (*BlockProblemHelperStruct) GetRAcommit

func (b *BlockProblemHelperStruct) GetRAcommit() hash.Hash

GetRAcommit gets the RAcommit from the BlockProblemHelperStruct (Keccak256(PrevBlockHash + secretBytes) that RA commits to before sending out new block problem)

func (*BlockProblemHelperStruct) GetRAcommitSecret

func (b *BlockProblemHelperStruct) GetRAcommitSecret() string

GetRAcommitSecret gets the RAcommitSecret from the BlockProblemHelperStruct

func (*BlockProblemHelperStruct) GetSimulationTask

func (b *BlockProblemHelperStruct) GetSimulationTask() simpar.SimulationTask

GetSimulationTask gets the current SimulationTask from the BlockProblemHelperStruct

func (*BlockProblemHelperStruct) ResetMiners

func (b *BlockProblemHelperStruct) ResetMiners() error

ResetMiners is used to reset the list of miners that have broadcast a mining commitment. Used after a new block has been received.

func (*BlockProblemHelperStruct) SetRAcommitSecret

func (b *BlockProblemHelperStruct) SetRAcommitSecret(raCommitSecret string)

SetRAcommitSecret sets the RAcommitSecret for the BlockProblemHelperStruct

func (*BlockProblemHelperStruct) SetSimulationTask

func (b *BlockProblemHelperStruct) SetSimulationTask(simTask simpar.SimulationTask)

SetSimulationTask sets the current SimulationTask for the BlockProblemHelperStruct

func (*BlockProblemHelperStruct) UpdateActiveMinerWithActualSolution

func (b *BlockProblemHelperStruct) UpdateActiveMinerWithActualSolution(nodeID string, actualSolutionHash string)

UpdateActiveMinerWithActualSolution is used by RA only to store the actually received solution hash of a miner so that it can be retrieved later.

type ChainDBRequest

type ChainDBRequest struct {
	OriginalSenderNodeID      string // Retain info who originally requested the data so that nodes later can directly start communication with this node via chat protocol
	WantOnlyAllBlockHashes    bool   // If you want []string (a list of blockHashes) set this to true, in this case the following fields are ignored
	WantFullBlock             bool   // Info whether you are interested in block.Block (you are a full node) or block.Header (you are a light node)
	WantOnlyLatestBlock       bool   // Info whether you are only interest in the newest block (if this is set to true, the next field is ignored)
	BlockHashStringOfInterest string // Info which blockHash data you are interested in. If it does not exist you might not get a reply.
}

ChainDBRequest is the struct used to request specific chaindb data from other nodes via the topic 'pouw_chaindb'

func BytesToChainDBRequest

func BytesToChainDBRequest(b []byte) (ChainDBRequest, error)

BytesToChainDBRequest unmarshals a serialized ChainDBRequest if possible.

func NewChainDBRequest

func NewChainDBRequest(originalSenderNodeID string, wantOnlyAllBlockHashes bool, wantFullBlock bool, wantOnlyLatestBlock bool, blockHashStringOfInterest string) ChainDBRequest

NewChainDBRequest is the constructor of ChainDBRequest. I like using constructors so that when the struct is ever changed by e.g. adding fields the code breaks (and I get notified) instead of silently putting zero values for the new fields which can be hard to detect.

type LiveData

type LiveData struct {
	BPH                 BlockProblemHelperStruct
	PendingTransactions []transaction.Transaction
}

LiveData is a struct used to transmit current live data state to nodes that just completed their initial sync. E.g. a new node knows about all block hashes and the content of the latest block and now requests LiveData to be informed about currently pending transactions and the currently active block problem.

func NewLiveData

NewLiveData is the constructor for LiveData.

type Mode

type Mode int

Mode is an int alias used to implement what would be called an enum in other languages (which Go does not have yet as of writing)

var OriginalMode Mode

OriginalMode stores the initial mode a node was in at startup. It's used to determine the final sync mode after the initial sync is completed.

func StringToMode

func StringToMode(modeString string) (Mode, error)

StringToMode takes a string that represents a Mode and returns the Mode and error. Error will only be nil if the given string represents a valid Mode.

func (Mode) String

func (e Mode) String() string

String implements the string interface for Mode so that the name of the enum element will be printed instead of its int value.

type StateValueStruct

type StateValueStruct struct {
	Balance float64
	Nonce   int
}

StateValueStruct is a custom struct for the statedb. It holds token balance and transaction nonce. This struct is msgpacked and used as value in statedb. The corresponding key of these key-value pairs in statedb is the nodeID in string form.

func StateDbBytesToStruct

func StateDbBytesToStruct(ser []byte) (StateValueStruct, error)

StateDbBytesToStruct takes bytes that were retrieved from the statedb and returns the corresponding StateValueStruct instance and an error.

type SyncHelperStruct

type SyncHelperStruct struct {
	NodeMode         Mode // Determines behavior of node (affects how incoming data is handled / replied to).
	ConfirmationsReq int  // Node sets target confirmation amount (only if this many other nodes sent same data it is accepted)
	Data             map[string]struct {
		ConfirmationsCur int // Node keeps counting how many confirmations for any wanted piece of data is has
		Data             []byte
	}
	Senders []string // holds NodeIDs so that each sender can only send a piece of data once (otherwise same sender could boost ConfirmationsCur by sending same data multiple times). Senders does not allow duplicate values.
}

SyncHelperStruct is a custom struct that a node uses to keep track of its syncmode, which data it has received and from whom and how often etc.

var SyncHelper SyncHelperStruct

SyncHelper is used to coordinate the current sync

func (*SyncHelperStruct) ConfirmationsReqGet

func (s *SyncHelperStruct) ConfirmationsReqGet() int

ConfirmationsReqGet returns the amount of data confirmations that are needed until the data is accepted. Higher value provides potentially more security but is slower and can lead to sync not working if not enough nodes are online.

func (*SyncHelperStruct) ConfirmationsReqWrite

func (s *SyncHelperStruct) ConfirmationsReqWrite(i int)

ConfirmationsReqWrite changes the amount of confirmations required until data is accepted. If the correct hash is known already, this function is used to set Req to 1.

func (*SyncHelperStruct) MapAdd

func (s *SyncHelperStruct) MapAdd(data []byte, mapKey string, senderNodeIDstring string)

MapAdd adds a new element to the map. Data is received from other nodes, then it is hashed to get the mapKey. Every time the same data is received the int counter is increased by one. This way, the map can keep track of which data has been received how many times. This enables a fundation for consensus between nodes. Note: This functions automatically determines whether the key already exists and its occurances counter should be increased by one,

or whether the key is new and the occurances should be set to 1. It also is able to initialize an empty map should it currently be nil.

func (*SyncHelperStruct) MapCheckIfConfirmationsReached

func (s *SyncHelperStruct) MapCheckIfConfirmationsReached() (bool, []byte, string)

MapCheckIfConfirmationsReached checks if any piece of data has been received often enough to be accepted, then returns true and the accepted data. Otherwise returns false and nil.

func (*SyncHelperStruct) MapReset

func (s *SyncHelperStruct) MapReset()

MapReset resets the Data map to empty. This is done after you successfully got data you wanted.

func (*SyncHelperStruct) NodeModeGet

func (s *SyncHelperStruct) NodeModeGet() Mode

NodeModeGet returns the current node mode as int. Uses RLock to allow concurrent reads.

func (*SyncHelperStruct) NodeModeWrite

func (s *SyncHelperStruct) NodeModeWrite(i Mode)

NodeModeWrite changes the node mode by setting it to a new value. This is a write operation and must be handled with mutex.

func (*SyncHelperStruct) SendersAddUnique

func (s *SyncHelperStruct) SendersAddUnique(newSender string)

SendersAddUnique takes nodeID and adds it to Senders (but only if it was not in there already)

func (*SyncHelperStruct) SendersIsNew

func (s *SyncHelperStruct) SendersIsNew(newSender string) bool

SendersIsNew returns bool value that describes whether a given sender is new (true - not in Senders) or known (false - sender already was in Senders). Uses rmutex to allow concurrent reads.

type TSData

type TSData int

TSData is an alias for int which describes which kind of data was put in a TransportStruct. It makes it easier for the receiving node to determine which data might have been sent.

func TransportStructGetDataID

func TransportStructGetDataID(tsSer []byte) (TSData, error)

TransportStructGetDataID takes a serialized TransportStruct, deserializes it and returns the enum value of DataID. This function is used by the receiver during networking to determine which data might have been sent (DataID still could have been lied about but this is handled in TransportStructExtraction). Int-to-DataType Mapping: 1 = block.Block, 2 = block.Header, 3 = []string.

func (TSData) String

func (e TSData) String() string

String implements the stringer interface so that the readable string value of enum element is printed in error messages instead of just its int.

type TransportStruct

type TransportStruct struct {
	DataID               TSData // Describes which kind of data is sent
	OriginalSenderNodeID string // Pubsub makes it difficult to later determine who the original sender of a received message was, so include this info manually. This will be converted to pubkey so that then the signature can be verified.
	Data                 []byte // serialized msgpack object that contains actual data (msgpack allows double serialization)
	Sig                  []byte // You hash the Data field with hash.NewHash and then you sign the resulting hash
}

TransportStruct is a struct that contains serialized data and an enum element (TSData) that tells the receiver which kind of data it contains. It also contains a Sig field which holds the signature of the data that is contained in this struct to prevent tampering. The databases contain TransportStruct.Data, so this struct is specifically made for easier handling of untrusted data received from other nodes.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL