Skip to content

Commit

Permalink
Implements pre-mining time verification and fixes bug with time verif…
Browse files Browse the repository at this point in the history
…iers
  • Loading branch information
Ashy5000 committed Apr 9, 2024
1 parent c269cae commit ebe864c
Show file tree
Hide file tree
Showing 14 changed files with 119 additions and 87 deletions.
20 changes: 11 additions & 9 deletions block.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,15 @@ func (i *Transaction) UnmarshalJSON(data []byte) error {
}

type Block struct {
Transactions []Transaction `json:"transactions"`
Miner dsa.PublicKey `json:"miner"`
Nonce int64 `json:"nonce"`
MiningTime time.Duration `json:"miningTime"`
Difficulty uint64 `json:"difficulty"`
PreviousBlockHash [32]byte `json:"previousBlockHash"`
Timestamp time.Time `json:"timestamp"`
TimeVerifierSignatures []Signature `json:"timeVerifierSignature"`
TimeVerifiers []dsa.PublicKey `json:"timeVerifiers"`
Transactions []Transaction `json:"transactions"`
Miner dsa.PublicKey `json:"miner"`
Nonce int64 `json:"nonce"`
MiningTime time.Duration `json:"miningTime"`
Difficulty uint64 `json:"difficulty"`
PreviousBlockHash [32]byte `json:"previousBlockHash"`
Timestamp time.Time `json:"timestamp"`
PreMiningTimeVerifierSignatures []Signature `json:"preMiningTimeVerifierSignatures"`
PreMiningTimeVerifiers []dsa.PublicKey `json:"preMiningTimeVerifiers"`
TimeVerifierSignatures []Signature `json:"timeVerifierSignature"`
TimeVerifiers []dsa.PublicKey `json:"timeVerifiers"`
}
Binary file modified builds/node/node_darwin-amd64
Binary file not shown.
Binary file modified builds/node/node_darwin-arm64
Binary file not shown.
Binary file modified builds/node/node_linux-386
Binary file not shown.
Binary file modified builds/node/node_linux-amd64
Binary file not shown.
Binary file modified builds/node/node_linux-arm
Binary file not shown.
Binary file modified builds/node/node_linux-arm64
Binary file not shown.
Binary file modified builds/node/node_windows-386
Binary file not shown.
Binary file modified builds/node/node_windows-amd64
Binary file not shown.
Binary file modified builds/node/node_windows-arm
Binary file not shown.
Binary file modified builds/node/node_windows-arm64
Binary file not shown.
142 changes: 77 additions & 65 deletions create_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,74 +26,17 @@ import (
var transactionHashes = make(map[[32]byte]int)
var miningTransactions []Transaction

func CreateBlock() (Block, error) {
if len(miningTransactions) == 0 {
return Block{}, errors.New("pool dry")
}
start := time.Now()
previousBlock, previousBlockFound := GetLastMinedBlock()
if !previousBlockFound {
previousBlock.Difficulty = initialBlockDifficulty
previousBlock.MiningTime = time.Minute
}
block := Block{
Miner: GetKey().PublicKey,
Transactions: miningTransactions,
Nonce: 0,
Difficulty: GetDifficulty(previousBlock.MiningTime, previousBlock.Difficulty),
Timestamp: time.Now(),
TimeVerifierSignatures: []Signature{},
TimeVerifiers: []dsa.PublicKey{},
}
if len(blockchain) > 0 {
block.PreviousBlockHash = HashBlock(blockchain[len(blockchain)-1])
} else {
block.PreviousBlockHash = [32]byte{}
}
hashBytes := HashBlock(block)
hash := binary.BigEndian.Uint64(hashBytes[:]) // Take the last 64 bits-- we won't ever need more than 64 zeroes.
fmt.Printf("Mining block with difficulty %d\n", block.Difficulty)
for hash > maximumUint64/block.Difficulty {
for i, transaction := range miningTransactions {
transactionString := fmt.Sprintf("%s:%s:%f:%d", EncodePublicKey(transaction.Sender), EncodePublicKey(transaction.Recipient), transaction.Amount, transaction.Timestamp.UnixNano())
transactionBytes := []byte(transactionString)
hash := sha256.Sum256(transactionBytes)
if transactionHashes[hash] > 1 {
miningTransactions[i] = miningTransactions[len(miningTransactions)-1]
miningTransactions = miningTransactions[:len(miningTransactions)-1]
i--
}
}
if len(miningTransactions) > 0 {
previousBlock, previousBlockFound = GetLastMinedBlock()
if !previousBlockFound {
previousBlock.Difficulty = initialBlockDifficulty
previousBlock.MiningTime = time.Minute
}
if len(blockchain) > 0 {
block.PreviousBlockHash = HashBlock(blockchain[len(blockchain)-1])
} else {
block.PreviousBlockHash = [32]byte{}
}
block.Difficulty = GetDifficulty(previousBlock.MiningTime, previousBlock.Difficulty)
block.Transactions = miningTransactions
block.Nonce++
hashBytes = HashBlock(block)
hash = binary.BigEndian.Uint64(hashBytes[:])
} else {
fmt.Println("Pool dry.")
return Block{}, errors.New("pool dry")
}
}
block.MiningTime = time.Since(start)
func RequestTimeVerification(block Block) ([]Signature, []dsa.PublicKey) {
fmt.Println("Requesting time verification")
var signatures []Signature
var publicKeys []dsa.PublicKey
// Convert the block to a string (JSON)
bodyChars, err := json.Marshal(&block)
if err != nil {
panic(err)
}
// Ask for time verifiers
for _, peer := range GetPeers() {
if int64(len(block.TimeVerifiers)) >= GetMinerCount(len(blockchain))/5 && VerifyTimeVerifiers(block, block.TimeVerifiers, block.TimeVerifierSignatures) {
if int64(len(block.TimeVerifiers)) >= GetMinerCount(len(blockchain))/5 && VerifyTimeVerifiers(block, block.TimeVerifiers, block.TimeVerifierSignatures) {
break
}
// Verify that the peer has mined a block (only miners can be time verifiers)
Expand Down Expand Up @@ -124,7 +67,7 @@ func CreateBlock() (Block, error) {
Y: peerY,
}
// Verify that the peer has mined a block
if IsNewMiner(peerKey, len(blockchain)) {
if IsNewMiner(peerKey, len(blockchain) + 1) {
fmt.Println("Peer has not mined a block.")
continue
}
Expand Down Expand Up @@ -163,10 +106,79 @@ func CreateBlock() (Block, error) {
panic(err)
}
// Add the time verifier to the block
block.TimeVerifiers = append(block.TimeVerifiers, publicKey)
publicKeys = append(publicKeys, publicKey)
// Add the time verifier signature to the block
block.TimeVerifierSignatures = append(block.TimeVerifierSignatures, signature)
signatures = append(signatures, signature)
fmt.Println("Got verification.")
}
return signatures, publicKeys
}

func CreateBlock() (Block, error) {
if len(miningTransactions) == 0 {
return Block{}, errors.New("pool dry")
}
start := time.Now()
previousBlock, previousBlockFound := GetLastMinedBlock()
if !previousBlockFound {
previousBlock.Difficulty = initialBlockDifficulty
previousBlock.MiningTime = time.Minute
}
block := Block{
Miner: GetKey().PublicKey,
Transactions: miningTransactions,
Nonce: 0,
Difficulty: GetDifficulty(previousBlock.MiningTime, previousBlock.Difficulty),
Timestamp: time.Now(),
TimeVerifierSignatures: []Signature{},
TimeVerifiers: []dsa.PublicKey{},
MiningTime: 0,
}
if len(blockchain) > 0 {
block.PreviousBlockHash = HashBlock(blockchain[len(blockchain)-1])
} else {
block.PreviousBlockHash = [32]byte{}
}
hashBytes := HashBlock(block)
hash := binary.BigEndian.Uint64(hashBytes[:]) // Take the last 64 bits-- we won't ever need more than 64 zeroes.
// Request time verifiers
block.PreMiningTimeVerifierSignatures, block.PreMiningTimeVerifiers = RequestTimeVerification(block)
fmt.Printf("Mining block with difficulty %d\n", block.Difficulty)
for hash > maximumUint64/block.Difficulty {
for i, transaction := range miningTransactions {
transactionString := fmt.Sprintf("%s:%s:%f:%d", EncodePublicKey(transaction.Sender), EncodePublicKey(transaction.Recipient), transaction.Amount, transaction.Timestamp.UnixNano())
transactionBytes := []byte(transactionString)
hash := sha256.Sum256(transactionBytes)
if transactionHashes[hash] > 1 {
miningTransactions[i] = miningTransactions[len(miningTransactions)-1]
miningTransactions = miningTransactions[:len(miningTransactions)-1]
i--
}
}
if len(miningTransactions) > 0 {
previousBlock, previousBlockFound = GetLastMinedBlock()
if !previousBlockFound {
previousBlock.Difficulty = initialBlockDifficulty
previousBlock.MiningTime = time.Minute
}
if len(blockchain) > 0 {
block.PreviousBlockHash = HashBlock(blockchain[len(blockchain)-1])
} else {
block.PreviousBlockHash = [32]byte{}
}
block.Difficulty = GetDifficulty(previousBlock.MiningTime, previousBlock.Difficulty)
block.Transactions = miningTransactions
block.Nonce++
hashBytes = HashBlock(block)
hash = binary.BigEndian.Uint64(hashBytes[:])
} else {
fmt.Println("Pool dry.")
return Block{}, errors.New("pool dry")
}
}
block.MiningTime = time.Since(start)
// Ask for time verifiers
block.TimeVerifierSignatures, block.TimeVerifiers = RequestTimeVerification(block)
if int64(len(block.TimeVerifiers)) < GetMinerCount(len(blockchain))/5 {
fmt.Println("Not enough time verifiers.")
return Block{}, errors.New("lost block")
Expand Down
42 changes: 30 additions & 12 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,20 +213,38 @@ func HandleVerifyTimeRequest(w http.ResponseWriter, req *http.Request) {
}
// Get the current time
currentTime := time.Now()
// Get the time mining finished
miningFinishedTime := block.Timestamp.Add(block.MiningTime)
// Check if the time the block was mined is within a reasonable range of the current time
// It cannot be in the future, and it cannot be more than 10 seconds in the past
if miningFinishedTime.After(currentTime) || miningFinishedTime.Before(currentTime.Add(-10*time.Second)) {
_, err := io.WriteString(w, "invalid")
if err != nil {
panic(err)
}
return
}
var miningFinishedTime time.Time
if block.MiningTime > 0 {
// Get the time mining finished
miningFinishedTime = block.Timestamp.Add(block.MiningTime)
// Check if the time the block was mined is within a reasonable range of the current time
// It cannot be in the future, and it cannot be more than 10 seconds in the past
if miningFinishedTime.After(currentTime) || miningFinishedTime.Before(currentTime.Add(-10*time.Second)) {
_, err := io.WriteString(w, "invalid")
if err != nil {
panic(err)
}
return
}
} else {
// Check if the time the block started to be mined is within a reasonable range of the current time
// It cannot be in the future, and it cannot be more than 10 seconds in the past
if block.Timestamp.After(currentTime) || block.Timestamp.Before(currentTime.Add(-10*time.Second)) {
_, err := io.WriteString(w, "invalid")
if err != nil {
panic(err)
}
}
}
// Sign the time with the time verifier's (this node's) private key
key := GetKey()
r, s, err := dsa.Sign(rand.Reader, &key, []byte(fmt.Sprintf("%d", miningFinishedTime.UnixNano())))
var r *big.Int
var s *big.Int
if block.MiningTime > 0 {
r, s, err = dsa.Sign(rand.Reader, &key, []byte(fmt.Sprintf("%d", miningFinishedTime.UnixNano())))
} else {
r, s, err = dsa.Sign(rand.Reader, &key, []byte(fmt.Sprintf("%d", block.Timestamp.UnixNano())))
}
if err != nil {
panic(err)
}
Expand Down
2 changes: 1 addition & 1 deletion verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ func VerifyTimeVerifiers(block Block, verifiers []dsa.PublicKey, signatures []Si
}
// Ensure all verifiers are miners
for _, verifier := range verifiers {
if !IsNewMiner(verifier, len(blockchain)) {
if !IsNewMiner(verifier, len(blockchain) + 1) {
fmt.Println("Time verifier is not a miner.")
return false
}
Expand Down

0 comments on commit ebe864c

Please sign in to comment.