zkt24/z2/backend/core/consensus.go
2024-04-25 13:51:47 +02:00

194 lines
4.3 KiB
Go

package core
import (
"context"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"hash"
"log"
"time"
"thesis/crypto"
"thesis/ent"
)
/*
** Type 1: Transaction sync
** Type 2: New Transaction cast
*/
type DataPacket struct {
Type int
Data []byte
}
func (p DataPacket) Serialize() []byte {
data, err := json.Marshal(p)
if err != nil {
panic(err)
}
return data
}
func DeSerialize(p []byte) DataPacket {
var msg DataPacket
err := json.Unmarshal(p, &msg)
if err != nil {
panic(err)
}
return msg
}
func SyncContent(msg DataPacket) {
if msg.Type == 1 {
fmt.Println("got a tx sync")
}
}
func ValidateContent(client *ent.Client, pk *crypto.PublicKey) error {
txs, err := client.Transactions.Query().All(context.Background())
handleError(err)
for i := 0; i < len(txs); i++ {
currentTx := &Transaction{
Type: txs[i].Type,
Timestamp: int64(txs[i].Timestamp),
Comment: txs[i].Comment,
Content: txs[i].Content,
Hash: txs[i].Hash,
Signature: txs[i].Signature,
}
// fmt.Println(currentTx)
err := crypto.ValidateSignature(currentTx.Signature, pk, []byte(currentTx.Hash))
handleError(err)
log.Printf("Valid signature for tx: %s", currentTx.Hash)
}
blocks, err := client.Blocks.Query().All(context.Background())
handleError(err)
for i := 0; i < len(blocks); i++ {
// currentBlock := &core.Block{
// Hash: blocks[i].Hash,
// Nonce: blocks[i].ID,
// Length: blocks[i].Length,
// PreviousHash: blocks[i].PreviousHash,
// }
txs, err := blocks[i].QueryMinedTxs().All(context.Background())
handleError(err)
var hash hash.Hash
for j := 0; j < len(txs); j++ {
tx := &Transaction{
Type: txs[j].Type,
Timestamp: int64(txs[j].Timestamp),
Comment: txs[j].Comment,
Content: txs[j].Content,
Hash: txs[j].Hash,
Signature: txs[j].Signature,
}
txBytes, err := json.Marshal(tx)
handleError(err)
hash = sha256.New()
hash.Write(txBytes)
}
if fmt.Sprintf("0x%x", string(hash.Sum(nil))) == blocks[i].Hash {
log.Printf("Block %d validated \n", blocks[i].ID)
} else {
log.Printf("Block %d is invalid !!!\n", blocks[i].ID)
return errors.New("invalid block detected")
}
}
return nil
}
func AddNewTx(client *ent.Client, content []byte, commit string, sig string, key *ent.Key) error {
// key := db.GetKeyFromHex(pk)
// if key == nil {
// return
// }
tx := &Transaction{
Type: 2,
Timestamp: time.Now().Unix(),
Comment: "regular tx",
Content: content,
Signature: sig,
}
txBytes, err := json.Marshal(tx)
handleError(err)
hash := sha256.New()
hash.Write(txBytes)
tx.Hash = fmt.Sprintf("0x%x", string(hash.Sum(nil)))
pubBytes, err := hex.DecodeString(key.PublicKey[2:])
handleError(err)
pk := new(crypto.PublicKey).Uncompress(pubBytes)
fmt.Println(hash)
err = crypto.ValidateSignature(sig, pk, []byte(fmt.Sprintf("%s%s%s", key.PublicKey, tx.Comment, commit)))
if err != nil {
fmt.Println("Invalid data submitted")
// return nil
}
txContent := &TransactionContent{
Signer: key.PublicKey,
Commitment: commit,
}
contentBytes, err := json.Marshal(txContent)
handleError(err)
dbTX, err := client.Transactions.Create().
SetComment(tx.Comment).
SetHash(tx.Hash).
SetTimestamp(int(tx.Timestamp)).
SetSignature(tx.Signature).
SetType(tx.Type).
SetContent(contentBytes).
Save(context.Background())
handleError(err)
// db.AddTx(client, txObj)
txBytes, err = json.Marshal(tx)
handleError(err)
hash = sha256.New()
hash.Write(txBytes)
blocks, err := client.Blocks.Query().All(context.Background())
handleError(err)
var block Block
if len(blocks) == 0 {
block = Block{
Hash: fmt.Sprintf("0x%x", string(hash.Sum(nil))),
Nonce: 0,
Length: 1,
PreviousHash: "0x000",
}
} else {
lastBlock := blocks[len(blocks)-1]
block = Block{
Hash: fmt.Sprintf("0x%x", string(hash.Sum(nil))),
Nonce: lastBlock.ID,
Length: 1,
PreviousHash: lastBlock.Hash,
}
}
dbBlock, err := client.Blocks.Create().
SetHash(block.Hash).
SetID(block.Nonce).
SetLength(block.Length).
SetPreviousHash(block.PreviousHash).
Save(context.Background())
handleError(err)
_, err = dbTX.Update().AddBlock(dbBlock).Save(context.Background())
handleError(err)
return nil
}
func handleError(err error) {
if err != nil {
panic(err)
}
}