-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #25 from dusk-network/update-bid
Refactor generation component to search for bid values by itself, without needing user input
- Loading branch information
Showing
13 changed files
with
409 additions
and
258 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
package generation | ||
|
||
import ( | ||
"bytes" | ||
"errors" | ||
|
||
"github.com/dusk-network/dusk-blockchain/pkg/core/block" | ||
"github.com/dusk-network/dusk-blockchain/pkg/core/database" | ||
"github.com/dusk-network/dusk-blockchain/pkg/core/database/heavy" | ||
"github.com/dusk-network/dusk-blockchain/pkg/core/transactions" | ||
log "github.com/sirupsen/logrus" | ||
) | ||
|
||
// bidRetriever is a simple searcher, who's responsibility is to find a bid transaction, when given | ||
// an M value. | ||
type bidRetriever struct { | ||
db database.DB | ||
} | ||
|
||
// newBidRetriever returns an initialized bidRetriever, ready for use. | ||
func newBidRetriever(db database.DB) *bidRetriever { | ||
// Get a db connection, if none was given. | ||
if db == nil { | ||
_, db = heavy.CreateDBConnection() | ||
} | ||
|
||
return &bidRetriever{ | ||
db: db, | ||
} | ||
} | ||
|
||
// SearchForBid will walk up the blockchain to find a bid with the corresponding `m`, | ||
// by running a comparison function on each tx for every found block. If the comparison function finds a match, | ||
// then this tx is returned. This tx can then be used by the generation component to start or reset itself. | ||
func (i *bidRetriever) SearchForBid(m []byte) (transactions.Transaction, error) { | ||
currentHeight := i.getCurrentHeight() | ||
searchingHeight := i.getSearchingHeight(currentHeight) | ||
|
||
for { | ||
blk, err := i.getBlock(searchingHeight) | ||
if err != nil { | ||
break | ||
} | ||
|
||
tx, err := findCorrespondingBid(blk.Txs, m, searchingHeight, currentHeight) | ||
if err != nil { | ||
searchingHeight++ | ||
continue | ||
} | ||
|
||
return tx, nil | ||
} | ||
|
||
return nil, errors.New("could not find corresponding value for specified item") | ||
} | ||
|
||
// If given a set of transactions and an M value, this function will return a bid | ||
// transaction corresponding to that M value. | ||
func findCorrespondingBid(txs []transactions.Transaction, m []byte, searchingHeight, currentHeight uint64) (transactions.Transaction, error) { | ||
for _, tx := range txs { | ||
bid, ok := tx.(*transactions.Bid) | ||
if !ok { | ||
continue | ||
} | ||
|
||
if bytes.Equal(m, bid.M) && bid.Lock+searchingHeight > currentHeight { | ||
hash, err := bid.CalculateHash() | ||
if err != nil { | ||
// If we found a valid bid tx, we should under no circumstance have issues marshalling it | ||
panic(err) | ||
} | ||
|
||
log.WithFields(log.Fields{ | ||
"process": "generation", | ||
"height": searchingHeight, | ||
"tx hash": hash, | ||
}).Debugln("bid found in chain") | ||
return bid, nil | ||
} | ||
} | ||
|
||
return nil, errors.New("could not find a corresponding d value") | ||
} | ||
|
||
// Bid transactions can only be valid for the maximum locktime. So, we will begin our search at | ||
// the tip height, minus the maximum locktime. This function will tell us exactly what that height is. | ||
func (i *bidRetriever) getSearchingHeight(currentHeight uint64) uint64 { | ||
if currentHeight < transactions.MaxLockTime { | ||
return 0 | ||
} | ||
return currentHeight - transactions.MaxLockTime | ||
} | ||
|
||
func (i *bidRetriever) getBlock(searchingHeight uint64) (*block.Block, error) { | ||
var b *block.Block | ||
err := i.db.View(func(t database.Transaction) error { | ||
hash, err := t.FetchBlockHashByHeight(searchingHeight) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
b, err = t.FetchBlock(hash) | ||
return err | ||
}) | ||
|
||
return b, err | ||
} | ||
|
||
func (i *bidRetriever) getCurrentHeight() (currentHeight uint64) { | ||
err := i.db.View(func(t database.Transaction) error { | ||
var err error | ||
currentHeight, err = t.FetchCurrentHeight() | ||
return err | ||
}) | ||
|
||
if err != nil { | ||
// If we can not get the current height, it means we have no DB state object, or the header of the tip hash is missing | ||
// Neither should ever happen, so we panic | ||
panic(err) | ||
} | ||
|
||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package generation | ||
|
||
import ( | ||
"testing" | ||
|
||
ristretto "github.com/bwesterb/go-ristretto" | ||
"github.com/dusk-network/dusk-blockchain/pkg/core/database" | ||
"github.com/dusk-network/dusk-blockchain/pkg/core/database/lite" | ||
"github.com/dusk-network/dusk-blockchain/pkg/core/tests/helper" | ||
"github.com/dusk-network/dusk-blockchain/pkg/core/transactions" | ||
zkproof "github.com/dusk-network/dusk-zkproof" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestSearchForBid(t *testing.T) { | ||
k := ristretto.Scalar{} | ||
k.Rand() | ||
|
||
d := ristretto.Scalar{} | ||
d.Rand() | ||
db, err := initTest(t) | ||
assert.NoError(t, err) | ||
|
||
bid, err := helper.RandomBidTx(t, false) | ||
assert.NoError(t, err) | ||
|
||
bid.Outputs[0].Commitment = d.Bytes() | ||
m := zkproof.CalculateM(k) | ||
bid.M = m.Bytes() | ||
|
||
retriever := newBidRetriever(db) | ||
// We shouldn't get anything back yet, as the bid is not included in a block in the db | ||
retrieved, err := retriever.SearchForBid(m.Bytes()) | ||
assert.Error(t, err) | ||
assert.Nil(t, retrieved) | ||
|
||
// Now, add the bid to the db | ||
storeTx(t, db, bid) | ||
|
||
// This time, we shouldn't get an error, and an actual value returned | ||
retrieved, err = retriever.SearchForBid(m.Bytes()) | ||
assert.NoError(t, err) | ||
assert.NotNil(t, retrieved) | ||
assert.Equal(t, d.Bytes(), retrieved.(*transactions.Bid).Outputs[0].Commitment) | ||
} | ||
|
||
func initTest(t *testing.T) (database.DB, error) { | ||
_, db := lite.CreateDBConnection() | ||
// Add a genesis block so we don't run into any panics | ||
blk := helper.RandomBlock(t, 0, 2) | ||
return db, db.Update(func(t database.Transaction) error { | ||
return t.StoreBlock(blk) | ||
}) | ||
} | ||
|
||
func storeTx(t *testing.T, db database.DB, tx transactions.Transaction) { | ||
blk := helper.RandomBlock(t, 1, 2) | ||
blk.AddTx(tx) | ||
err := db.Update(func(t database.Transaction) error { | ||
return t.StoreBlock(blk) | ||
}) | ||
assert.NoError(t, err) | ||
} |
Oops, something went wrong.