Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Self-Contained Proofs 📦 #16

Open
wants to merge 13 commits into
base: make-permissionless
Choose a base branch
from
18 changes: 4 additions & 14 deletions REST/EPAccount.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package REST

import (
"fmt"
"github.com/bazo-blockchain/bazo-client/client"
"github.com/bazo-blockchain/bazo-client/network"
"github.com/bazo-blockchain/bazo-miner/protocol"
"github.com/gorilla/mux"
"math/big"
"net/http"
Expand All @@ -16,22 +15,13 @@ func GetAccountEndpoint(w http.ResponseWriter, req *http.Request) {
logger.Printf("Incoming acc request for id: %v", param)

var address [64]byte
var addressHash [32]byte

pubKeyInt, _ := new(big.Int).SetString(param, 16)

if len(param) == 64 {
copy(addressHash[:], pubKeyInt.Bytes())

network.AccReq(false, addressHash)

accI, _ := network.Fetch(network.AccChan)
acc := accI.(*protocol.Account)

address = acc.Address
} else if len(param) == 128 {
if len(param) == 128 {
copy(address[:], pubKeyInt.Bytes())
addressHash = protocol.SerializeHashContent(address)
} else {
logger.Fatal(fmt.Sprintf("provided invalid address %x\n", param))
}

acc, lastTenTx, err := client.GetAccount(address)
Expand Down
2 changes: 0 additions & 2 deletions cli/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ func checkAccount(args *accountArgs, logger *log.Logger) error {
address = crypto.GetAddressFromPubKey(&privKey.PublicKey)
}

logger.Printf("My address: %x\n", address)

acc, _, err := client.CheckAccount(address)
if err != nil {
logger.Println(err)
Expand Down
13 changes: 12 additions & 1 deletion cli/funds.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import (
"errors"
"fmt"
"github.com/bazo-blockchain/bazo-client/client"
"github.com/bazo-blockchain/bazo-client/cstorage"
"github.com/bazo-blockchain/bazo-client/network"
"github.com/bazo-blockchain/bazo-client/util"
"github.com/bazo-blockchain/bazo-miner/crypto"
"github.com/bazo-blockchain/bazo-miner/p2p"
"github.com/bazo-blockchain/bazo-miner/protocol"
"github.com/urfave/cli"
"log"
"sort"
)

type fundsArgs struct {
Expand Down Expand Up @@ -117,7 +119,14 @@ func sendFunds(args *fundsArgs, logger *log.Logger) error {
fromAddress := crypto.GetAddressFromPubKey(&fromPrivKey.PublicKey)
toAddress := crypto.GetAddressFromPubKey(toPubKey)

tx, err := protocol.ConstrFundsTx(
client.SyncBeforeTx(fromAddress)

proofs, err := cstorage.ReadMerkleProofs()
sort.Slice(proofs, func(i, j int) bool {
return proofs[i].Height > proofs[j].Height
})

tx, err := protocol.NewSignedFundsTx(
byte(args.header),
uint64(args.amount),
uint64(args.fee),
Expand All @@ -132,6 +141,8 @@ func sendFunds(args *fundsArgs, logger *log.Logger) error {
return err
}

tx.Proofs = proofs

if err := network.SendTx(util.Config.BootstrapIpport, tx, p2p.FUNDSTX_BRDCST); err != nil {
logger.Printf("%v\n", err)
return err
Expand Down
1 change: 1 addition & 0 deletions cli/rest.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ func GetRestCommand() cli.Command {
Name: "rest",
Usage: "start the REST service",
Action: func(c *cli.Context) error {
client.Init()
client.Sync()
REST.Init()
return nil
Expand Down
4 changes: 2 additions & 2 deletions client/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ func GetAccount(address [64]byte) (*Account, []*FundsTxJson, error) {
//Set default params
activeParameters = miner.NewDefaultParameters()

network.AccReq(false, protocol.SerializeHashContent(account.Address))
network.AccReq(false, account.Address)
if accI, _ := network.Fetch(network.AccChan); accI != nil {
if acc := accI.(*protocol.Account); acc != nil {
account.IsCreated = true
account.IsStaking = acc.IsStaking

network.AccReq(true, protocol.SerializeHashContent(account.Address))
network.AccReq(true, account.Address)
if rootAccI, _ := network.Fetch(network.AccChan); rootAccI != nil {
if rootAcc := rootAccI.(*protocol.Account); rootAcc != nil {
account.IsRoot = true
Expand Down
204 changes: 134 additions & 70 deletions client/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,22 @@ var (
)

//Update allBlockHeaders to the latest header. Start listening to broadcasted headers after.
func SyncBeforeTx(address [64]byte) {
loadBlockHeaders()
incomingBlockHeaders(true)
GetAccount(address)
}

func Sync() {
loadBlockHeaders()
go incomingBlockHeaders()
go incomingBlockHeaders(false)
}

func loadBlockHeaders() {
var last *protocol.Block

//youngest = fetchBlockHeader(nil)
if last = cstorage.ReadLastBlockHeader(); last != nil {
if last, _ = cstorage.ReadLastBlockHeader(); last != nil {
var loaded []*protocol.Block
loaded = loadDB(last, [32]byte{}, loaded)
blockHeaders = append(blockHeaders, loaded...)
Expand All @@ -40,7 +46,7 @@ func loadBlockHeaders() {
network.Uptodate = true
}

func incomingBlockHeaders() {
func incomingBlockHeaders(untilSynced bool) {
for {
blockHeaderIn := <-network.BlockHeaderIn

Expand Down Expand Up @@ -85,6 +91,10 @@ func incomingBlockHeaders() {

blockHeaders = append(blockHeaders, blockHeaderIn)
cstorage.WriteLastBlockHeader(blockHeaderIn)

if untilSynced {
return
}
}
}
}
Expand Down Expand Up @@ -118,7 +128,7 @@ func loadDB(last *protocol.Block, abort [32]byte, loaded []*protocol.Block) []*p
var ancestor *protocol.Block

if last.PrevHash != abort {
if ancestor = cstorage.ReadBlockHeader(last.PrevHash); ancestor == nil {
if ancestor, _ = cstorage.ReadBlockHeader(last.PrevHash); ancestor == nil {
logger.Fatal()
}

Expand Down Expand Up @@ -174,83 +184,137 @@ func getState(acc *Account, lastTenTx []*FundsTxJson) (err error) {

relevantBlocks, err := getRelevantBlocks(relevantHeadersConfigBF)
for _, block := range relevantBlocks {
if block != nil {
//Balance funds and collect fee
for _, txHash := range block.FundsTxData {
err := network.TxReq(p2p.FUNDSTX_REQ, txHash)
if err != nil {
return err
}

txI, err := network.Fetch(network.FundsTxChan)
if err != nil {
return err
}

tx := txI.(protocol.Transaction)
fundsTx := txI.(*protocol.FundsTx)

if fundsTx.From == acc.Address || fundsTx.To == acc.Address || block.Beneficiary == acc.Address {
//Validate tx
if err := validateTx(block, tx, txHash); err != nil {
return err
}

if fundsTx.From == acc.Address {
//If Acc is no root, balance funds
if !acc.IsRoot {
acc.Balance -= fundsTx.Amount
acc.Balance -= fundsTx.Fee
}

acc.TxCnt += 1
}

if fundsTx.To == acc.Address {
acc.Balance += fundsTx.Amount

put(lastTenTx, ConvertFundsTx(fundsTx, "verified"))
}

if block.Beneficiary == acc.Address {
acc.Balance += fundsTx.Fee
}
}
}
if block == nil {
continue
}

//Update config parameters and collect fee
for _, txHash := range block.ConfigTxData {
err := network.TxReq(p2p.CONFIGTX_REQ, txHash)
if err != nil {
return err
}
err = updateConfigParameters(block)
if err != nil {
return err
}

txI, err := network.Fetch(network.ConfigTxChan)
if err != nil {
return err
}
// Check if bloomfilter returns false, if yes, the block has nothing related to account's address
if !block.BloomFilter.Test(acc.Address[:]) {
continue
}

tx := txI.(protocol.Transaction)
configTx := txI.(*protocol.ConfigTx)
fundsTxs, err := requestFundsTx(block)

configTxSlice := []*protocol.ConfigTx{configTx}
// Check if it's a block with a Bloomfilter that returns false positive
if len(fundsTxs) == 0 && block.Beneficiary != acc.Address {
// TODO @rmnblm
}

if block.Beneficiary == acc.Address {
//Validate tx
if err := validateTx(block, tx, txHash); err != nil {
return err
}
err = balanceFunds(fundsTxs, block, acc, lastTenTx)
if err != nil {
return err
}

acc.Balance += configTx.Fee
}
if block.Beneficiary == acc.Address {
acc.Balance += block.TotalFees
}
}

miner.CheckAndChangeParameters(&activeParameters, &configTxSlice)
}
return nil
}

//TODO stakeTx
func requestFundsTx(block *protocol.Block) (fundsTxs []*protocol.FundsTx, err error) {
for _, txHash := range block.FundsTxData {
err := network.TxReq(p2p.FUNDSTX_REQ, txHash)
if err != nil {
return nil, err
}

txI, err := network.Fetch(network.FundsTxChan)
if err != nil {
return nil, err
}

fundsTx := txI.(*protocol.FundsTx)
fundsTxs = append(fundsTxs, fundsTx)
}

return fundsTxs, nil
}

func balanceFunds(fundsTxs []*protocol.FundsTx, block *protocol.Block, acc *Account, lastTenTx []*FundsTxJson) error {
bucket := protocol.NewTxBucket(acc.Address)

for _, fundsTx := range fundsTxs {
if fundsTx.From == acc.Address || fundsTx.To == acc.Address {
bucket.AddFundsTx(fundsTx)
}
}

bucketHash := bucket.Hash()
if err := validateBucket(block, bucketHash); err != nil {
return err
}

for _, fundsTx := range bucket.Transactions {
// Check if account is sender of a transaction
if fundsTx.From == acc.Address {
//If Acc is no root, balance funds
if !acc.IsRoot {
acc.Balance -= fundsTx.Amount
acc.Balance -= fundsTx.Fee
}
acc.TxCnt += 1
}

if fundsTx.To == acc.Address {
acc.Balance += fundsTx.Amount
put(lastTenTx, ConvertFundsTx(fundsTx, "verified"))
}
}

// Create the Merkle proof for this block
merkleTree := block.BuildMerkleTree()
mhashes, err := merkleTree.MerkleProof(bucketHash)
if err != nil {
return err
}

proof := protocol.NewMerkleProof(
block.Height,
mhashes,
bucket.Address,
bucket.RelativeBalance,
bucket.CalculateMerkleRoot())

err = cstorage.WriteMerkleProof(&proof)
if err != nil {
return err
}

logger.Printf("Merkle proof written to client storage for tx at block height %v", block.Height)

return nil
}

func updateConfigParameters(block *protocol.Block) error {
for _, txHash := range block.ConfigTxData {
err := network.TxReq(p2p.CONFIGTX_REQ, txHash)
if err != nil {
return err
}

txI, err := network.Fetch(network.ConfigTxChan)
if err != nil {
return err
}

tx := txI.(protocol.Transaction)
configTx := txI.(*protocol.ConfigTx)

//Validate tx
if err := validateTx(block, tx, txHash); err != nil {
return err
}

configTxSlice := []*protocol.ConfigTx{configTx}
miner.CheckAndChangeParameters(&activeParameters, &configTxSlice)
}

return nil
}
Loading