Skip to content

Commit

Permalink
feat: construct data result and validator trees with sorted leaves
Browse files Browse the repository at this point in the history
  • Loading branch information
hacheigriega committed Sep 5, 2024
1 parent 6e83c9c commit aeaea34
Show file tree
Hide file tree
Showing 11 changed files with 148 additions and 81 deletions.
3 changes: 3 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,9 @@ func NewApp(
runtime.NewKVStoreService(keys[batchingtypes.StoreKey]),
authtypes.NewModuleAddress(batchingtypes.ModuleName).String(),
app.StakingKeeper,
app.WasmStorageKeeper,
contractKeeper,
app.WasmKeeper,
authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()),
)

Expand Down
8 changes: 4 additions & 4 deletions proto/sedachain/batching/v1/batching.proto
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ message Batch {
uint64 batch_number = 1;
// block_height is the height at which the batch was created.
int64 block_height = 2;
// data_result_root is the root of the data result merkle tree.
// data_result_root is the hex-encoded root of the data result merkle tree.
string data_result_root = 3;
// validator_root is the root of the validator merkle tree.
// validator_root is the hex-encoded root of the validator merkle tree.
string validator_root = 4;
// votes is the canonical set of votes on the batch from validators.
repeated Vote votes = 5;
Expand Down Expand Up @@ -54,7 +54,7 @@ message Signature {
message Params {
option (gogoproto.equal) = true;

// validator_set_trim_percentage is the percentage of the validator
// validator_set_trim_percent is the percentage of the validator
// set to store in the validator merkle tree in the batch.
uint32 validator_set_trim_percentage = 1;
uint32 validator_set_trim_percent = 1;
}
82 changes: 63 additions & 19 deletions x/batching/keeper/abci.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package keeper

import (
"bytes"
"encoding/binary"
"encoding/hex"
"encoding/json"
"fmt"
"sort"

"github.com/cometbft/cometbft/crypto/merkle"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/sedaprotocol/seda-chain/x/batching/types"

"github.com/cometbft/cometbft/crypto/merkle"
"github.com/sedaprotocol/seda-chain/x/batching/types"
tallytypes "github.com/sedaprotocol/seda-chain/x/tally/types"
)

func (k Keeper) EndBlock(ctx sdk.Context) (err error) {
Expand Down Expand Up @@ -36,6 +41,10 @@ func (k Keeper) EndBlock(ctx sdk.Context) (err error) {
if err != nil {
panic(err)
}
err = k.IncrementCurrentBatchNum(ctx)
if err != nil {
panic(err)
}

return nil
}
Expand All @@ -47,39 +56,74 @@ func (k Keeper) ConstructBatch(ctx sdk.Context) (types.Batch, error) {
}

// Construct data result tree.
// Fetch batch-ready data requests.
coreContract, err := k.wasmStorageKeeper.GetCoreContractAddr(ctx)
if err != nil {
return types.Batch{}, err
}
// TODO: Deal with offset and limits. (#313)
// queryRes, err := k.wasmViewKeeper.QuerySmart(ctx, coreContract, []byte(`{"get_data_requests_by_status":{"status": "tallied", "offset": 0, "limit": 100}}`))
// if err != nil {
// return err
// }
// if string(queryRes) == "[]" {
// return nil
// }
queryRes, err := k.wasmViewKeeper.QuerySmart(ctx, coreContract, []byte(`{"get_data_results_by_status":{"status": "tallied", "offset": 0, "limit": 100}}`))
if err != nil {
return types.Batch{}, err
}
if string(queryRes) == "[]" {
return types.Batch{}, err
}

// Leaves are SHA-256 hashes of JSON-serialized data result structs.
var dataResults []tallytypes.DataResult
err = json.Unmarshal(queryRes, &dataResults)
if err != nil {
return types.Batch{}, err
}

var dataLeaves [][]byte

Check failure on line 78 in x/batching/keeper/abci.go

View workflow job for this annotation

GitHub Actions / golangci

Consider pre-allocating `dataLeaves` (prealloc)
for _, res := range dataResults {
resHash, err := hex.DecodeString(res.ID)
if err != nil {
return types.Batch{}, err
}
dataLeaves = append(dataLeaves, resHash)
}

sort.Slice(dataLeaves, func(i, j int) bool {
if bytes.Compare(dataLeaves[i], dataLeaves[j]) == -1 {

Check failure on line 88 in x/batching/keeper/abci.go

View workflow job for this annotation

GitHub Actions / golangci

S1008: should use 'return bytes.Compare(dataLeaves[i], dataLeaves[j]) == -1' instead of 'if bytes.Compare(dataLeaves[i], dataLeaves[j]) == -1 { return true }; return false' (gosimple)
return true
}
return false
})
dataRoot := merkle.HashFromByteSlices(dataLeaves)
dataRootHex := hex.EncodeToString(dataRoot)

// Construct validator tree.
var leaves [][]byte
var valLeaves [][]byte
err = k.stakingKeeper.IterateLastValidatorPowers(ctx, func(addr sdk.ValAddress, power int64) (stop bool) {
// TODO construct with pubkey in pubkey module instead
buf := make([]byte, len(addr)+8)
copy(buf[:len(addr)], addr)
binary.BigEndian.PutUint64(buf[:len(addr)], uint64(power))

leaves = append(leaves, addr)
valLeaves = append(valLeaves, addr)
return false
})
if err != nil {
return types.Batch{}, err
}
valRoot := merkle.HashFromByteSlices(leaves) // TODO "ordered" merkle tree

// TODO subtrees based on keys

sort.Slice(valLeaves, func(i, j int) bool {
if bytes.Compare(valLeaves[i], valLeaves[j]) == -1 {

Check failure on line 114 in x/batching/keeper/abci.go

View workflow job for this annotation

GitHub Actions / golangci

S1008: should use 'return bytes.Compare(valLeaves[i], valLeaves[j]) == -1' instead of 'if bytes.Compare(valLeaves[i], valLeaves[j]) == -1 { return true }; return false' (gosimple)
return true
}
return false
})
valRoot := merkle.HashFromByteSlices(valLeaves)
valRootHex := hex.EncodeToString(valRoot)

return types.Batch{
BatchNumber: curBatchNum,
BlockHeight: ctx.BlockHeight(),
// DataResultRoot: ,
ValidatorRoot: valRootHex,
BlockTime: ctx.BlockTime(),
BatchNumber: curBatchNum,
BlockHeight: ctx.BlockHeight(),
DataResultRoot: dataRootHex,
ValidatorRoot: valRootHex,
BlockTime: ctx.BlockTime(),
}, nil
}
15 changes: 13 additions & 2 deletions x/batching/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"context"
"fmt"

wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"

"cosmossdk.io/collections"
addresscodec "cosmossdk.io/core/address"
storetypes "cosmossdk.io/core/store"
Expand All @@ -17,6 +19,9 @@ import (

type Keeper struct {
stakingKeeper types.StakingKeeper
wasmStorageKeeper types.WasmStorageKeeper
wasmKeeper wasmtypes.ContractOpsKeeper
wasmViewKeeper wasmtypes.ViewKeeper
validatorAddressCodec addresscodec.Codec

// authority is the address capable of executing MsgUpdateParams.
Expand All @@ -34,14 +39,20 @@ func NewKeeper(
storeService storetypes.KVStoreService,
authority string,
sk types.StakingKeeper,
wsk types.WasmStorageKeeper,
wk wasmtypes.ContractOpsKeeper,
wvk wasmtypes.ViewKeeper,
validatorAddressCodec addresscodec.Codec,
) Keeper {
sb := collections.NewSchemaBuilder(storeService)

k := Keeper{
authority: authority,
stakingKeeper: sk,
wasmStorageKeeper: wsk,
wasmKeeper: wk,
wasmViewKeeper: wvk,
validatorAddressCodec: validatorAddressCodec,
authority: authority,
currentBatchNumber: collections.NewSequence(sb, types.CurrentBatchNumberKey, "current_batch_number"),
batch: collections.NewMap(sb, types.BatchPrefix, "batch", collections.Uint64Key, codec.CollValue[types.Batch](cdc)),
params: collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[types.Params](cdc)),
Expand All @@ -59,7 +70,7 @@ func (k Keeper) SetCurrentBatchNum(ctx context.Context, batchNum uint64) error {
return k.currentBatchNumber.Set(ctx, batchNum)
}

func (k Keeper) IncrementCurrentBatchNum(ctx context.Context, batchNum uint64) error {
func (k Keeper) IncrementCurrentBatchNum(ctx context.Context) error {
_, err := k.currentBatchNumber.Next(ctx)
return err
}
Expand Down
2 changes: 1 addition & 1 deletion x/batching/keeper/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ func (k Keeper) GetParams(ctx sdk.Context) (types.Params, error) {

func (k Keeper) GetValSetTrimPercent(ctx sdk.Context) (uint32, error) {
params, err := k.params.Get(ctx)
return params.ValidatorSetTrimPercentage, err
return params.ValidatorSetTrimPercent, err
}
101 changes: 50 additions & 51 deletions x/batching/types/batching.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions x/batching/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ type StakingKeeper interface {
GetValidatorUpdates(ctx context.Context) ([]abci.ValidatorUpdate, error)
IterateLastValidatorPowers(ctx context.Context, handler func(operator sdk.ValAddress, power int64) (stop bool)) error
}

type WasmStorageKeeper interface {
GetCoreContractAddr(ctx context.Context) (sdk.AccAddress, error)
}
2 changes: 1 addition & 1 deletion x/batching/types/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const (
// DefaultParams returns default batching module parameters.
func DefaultParams() Params {
return Params{
ValidatorSetTrimPercentage: DefaultValSetTrimPercent,
ValidatorSetTrimPercent: DefaultValSetTrimPercent,
}
}

Expand Down
Loading

0 comments on commit aeaea34

Please sign in to comment.