Skip to content

Commit

Permalink
add committer state root
Browse files Browse the repository at this point in the history
  • Loading branch information
zhouop0 committed Apr 22, 2024
1 parent 29029f8 commit 0d7eb8d
Show file tree
Hide file tree
Showing 16 changed files with 507 additions and 36 deletions.
12 changes: 7 additions & 5 deletions internal/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ import (
func Run(ctx *svc.ServiceContext) {

// query last block number
go LatestBlackNumber(ctx)
// sync blocks
go SyncBlock(ctx)
// sync events
go SyncEvent(ctx)
//go LatestBlackNumber(ctx)
//// sync blocks
//go SyncBlock(ctx)
//// sync events
//go SyncEvent(ctx)
// query blob and store in local
//go QueryBlobOnChainAndStoreInLocal(ctx)
// commit and vote txs proposal
//go GetBlobsAndCommitTxsProposal(ctx)
// commit state root to ar and btc
go GetStateRootAndCommitStateRootProposal(ctx)

}
4 changes: 2 additions & 2 deletions internal/handler/inscribe.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ func Inscribe(ctx *svc.ServiceContext) {

if proposal.Status == schema.ProposalPendingStatus &&
proposal.Winner.String() == ctx.B2NodeConfig.Address && proposal.BtcTxHash == "" {
rs, err := inscribe.Inscribe(ctx.BTCConfig.PrivateKey, proposal.StateRootHash,
proposal.ProofHash, ctx.BTCConfig.DestinationAddress, btcapi.ChainParams(ctx.BTCConfig.NetworkName))
rs, err := inscribe.Inscribe(ctx.BTCConfig.PrivateKey, []byte(proposal.StateRootHash+proposal.ProofHash),
ctx.BTCConfig.DestinationAddress, btcapi.ChainParams(ctx.BTCConfig.NetworkName))
if err != nil {
log.Errorf("[Handler.Inscribe] Inscribe err: %s\n", errors.WithStack(err).Error())
continue
Expand Down
234 changes: 228 additions & 6 deletions internal/handler/op_committer_stateroot.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package handler

import (
"context"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/b2network/b2committer/internal/schema"
"github.com/b2network/b2committer/internal/svc"
"github.com/b2network/b2committer/internal/types"
"github.com/b2network/b2committer/pkg/btcapi"
"github.com/b2network/b2committer/pkg/contract/op"
"github.com/b2network/b2committer/pkg/inscribe"
"github.com/b2network/b2committer/pkg/log"
"github.com/b2network/b2committer/pkg/merkle"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
Expand All @@ -31,33 +34,252 @@ func GetStateRootAndCommitStateRootProposal(ctx *svc.ServiceContext) {
continue
}
latestProposalID := lastProposal.ProposalID
//voteAddress := ctx.B2NodeConfig.Address
voteAddress := ctx.B2NodeConfig.Address
if lastProposal.Status == schema.ProposalSucceedStatus || lastProposal.ProposalID == 0 {
log.Infof("this proposal has been successful or just beginning : %d", latestProposalID)
log.Infof("[Handler.GetStateRootAndCommitStateRootProposal] this proposal has been successful or just beginning : %d", latestProposalID)
// submit new proposal
newStateRootProposal, err := constructNextStateRootProposal(ctx, lastProposal)
if err != nil {
log.Errorf("[Handler.GetBlobsAndCommitProposal] Try to construct new state root proposal: %s", err.Error())
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] Try to construct new state root proposal: %s", err.Error())
time.Sleep(3 * time.Second)
continue
}
_, err = ctx.OpCommitterClient.SubmitStateRoot(newStateRootProposal)
if err != nil {
log.Errorf("[Handler.GetBlobsAndCommitProposal] Try to submit new state root proposal: %s", err.Error())
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal]Try to submit new state root proposal: %s", err.Error())
time.Sleep(3 * time.Second)
continue
}
log.Infof("[Handler.GetBlobsAndCommitProposal] submit new state root proposal: %s", newStateRootProposal.ProposalID)
log.Infof("[Handler.GetStateRootAndCommitStateRootProposal] submit new state root proposal: %s", newStateRootProposal.ProposalID)
time.Sleep(10 * time.Second)
continue
}

if lastProposal.Status == schema.ProposalVotingStatus || lastProposal.Status == schema.ProposalTimeoutStatus {
// check address voted or not
phase, err := ctx.OpCommitterClient.ProposalManager.IsVotedOnStateRootProposalPhase(&bind.CallOpts{}, lastProposal.ProposalID, common.HexToAddress(voteAddress))
if err != nil {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] Try to find address voted or not: %s", err)
time.Sleep(3 * time.Second)
continue
}
if phase {
log.Infof("[Handler.GetStateRootAndCommitStateRootProposal] address already voted in voting status: %s", voteAddress)
continue
}
var voteProposalStartL1Timestamp uint64
var voteProposalEndL1Timestamp uint64
if lastProposal.ProposalID == 1 {
voteProposalStartL1Timestamp = lastProposal.StartL1Timestamp
voteProposalEndL1Timestamp = voteProposalStartL1Timestamp + ctx.Config.BlobIntervalTime
} else {
beforeLastProposal, err := ctx.OpCommitterClient.ProposalManager.GetTxsRootProposal(&bind.CallOpts{}, lastProposal.ProposalID-1)
if err != nil {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal]Try to get before last proposal: %s", err.Error())
time.Sleep(3 * time.Second)
continue
}
voteProposalStartL1Timestamp = beforeLastProposal.EndTimestamp + 1
voteProposalEndL1Timestamp = voteProposalStartL1Timestamp + ctx.Config.BlobIntervalTime
}
tsp, err := constructStateRootProposal(ctx, lastProposal.ProposalID, voteProposalStartL1Timestamp, voteProposalEndL1Timestamp)
if err != nil {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] Try to construct new proposal to vote: %s", err.Error())
time.Sleep(3 * time.Second)
continue
}
_, err = ctx.OpCommitterClient.SubmitStateRoot(tsp)
if err != nil {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] Try to submit new proposal to vote: %s", err.Error())
time.Sleep(3 * time.Second)
continue
}
log.Infof("[Handler.GetStateRootAndCommitStateRootProposal] vote txs proposal %s, %s ", tsp.ProposalID, voteAddress)
continue
}

if lastProposal.Status == schema.ProposalPendingStatus {
phase, err := ctx.OpCommitterClient.ProposalManager.IsVotedOnStateRootDSTxPhase(&bind.CallOpts{}, lastProposal.ProposalID, common.HexToAddress(voteAddress))
if err != nil {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal][IsVotedOnStateRootDSTxPhase] is failed : %s", err)
time.Sleep(3 * time.Second)
continue
}
if phase {
log.Infof("[Handler.GetStateRootAndCommitStateRootProposal] address already voted in pending status: %s", voteAddress)
continue
}
if lastProposal.Winner == common.HexToAddress(ctx.B2NodeConfig.Address) {
var events []schema.SyncEvent
err = ctx.DB.Where("block_time between ? and ?", lastProposal.StartL1Timestamp, lastProposal.EndL1Timestamp).Order("block_number").Find(&events).Error
if err != nil {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal]collecting the state root blocks of proposal is failed. err : %s", errors.WithStack(err))
continue
}
stateRoots, err := types.NewDsStateRootProposal(ctx.B2NodeConfig.ChainID, lastProposal.ProposalID, lastProposal.OutputRoot, events)
if err != nil {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] constructing state root for ds is failed. err : %s", errors.WithStack(err))
}
dsJson, err := stateRoots.MarshalJson()
if err != nil {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] Try to marshal ds proposal: %s", err.Error())
time.Sleep(3 * time.Second)
continue
}

dsTxID, err := ctx.DecentralizedStore.StoreDetailsOnChain(dsJson, ctx.B2NodeConfig.ChainID, lastProposal.ProposalID)
if err != nil {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] Try to store ds proposal: %s", err.Error())
continue
}
_, err = ctx.OpCommitterClient.DsHash(lastProposal.ProposalID, schema.ProposalTypeStateRoot, schema.DsTypeArWeave, dsTxID)
if err != nil {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] Try to send ds proposal: %s", err.Error())
continue
}
log.Infof("[Handler.GetStateRootAndCommitStateRootProposal] success submit txs to ds: %s, dsHash: %s", lastProposal.ProposalID, lastProposal.DsTxHash)

}
if lastProposal.Winner != common.HexToAddress(voteAddress) {
outputs, err := ctx.DecentralizedStore.QueryDetailsByTxID(lastProposal.DsTxHash)
if err != nil {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] Try to get outputs from ds: %s", err.Error())
time.Sleep(3 * time.Second)
continue
}
var dsProposal types.DsStateRootProposal
err = json.Unmarshal(outputs, &dsProposal)
if err != nil {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] Try to unmarshal ds proposal: %s", err.Error())
continue
}

events, err := types.ConvertOutputsToEventData(dsProposal.OutputEvents)
if err != nil {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] Try to convert outputs to event data: %s", err.Error())
continue
}
verifyOutputRoots, err := GetOutputRootMerkleRoot(events)
if err != nil {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] Try to get outputs merkle root: %s", err.Error())
continue
}

if verifyOutputRoots != lastProposal.OutputRoot {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] Try to verify output from ds: %s", err.Error())
continue
}
_, err = ctx.OpCommitterClient.DsHash(lastProposal.ProposalID, schema.ProposalTypeStateRoot, schema.DsTypeArWeave, lastProposal.DsTxHash)
if err != nil {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] Try to send ds proposal: %s", err.Error())
continue
}
log.Infof("[Handler.GetStateRootAndCommitStateRootProposal] success verify and vote submit output from ds: %s, dsHash: %s", lastProposal.ProposalID, lastProposal.DsTxHash)
}

}

}
if lastProposal.Status == schema.ProposalCommitting {
isVotedBtcTx, err := ctx.OpCommitterClient.ProposalManager.IsVotedOnSubmitBitcoinTxPhase(&bind.CallOpts{}, lastProposal.ProposalID, common.HexToAddress(voteAddress))
if err != nil {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal][IsVotedOnSubmitBitcoinTxPhase] is failed : %s", err)
time.Sleep(3 * time.Second)
continue
}
if isVotedBtcTx {
log.Infof("[Handler.GetStateRootAndCommitStateRootProposal] address already voted btc tx in committing status: %s", voteAddress)
continue
}
if lastProposal.Winner == common.HexToAddress(voteAddress) {
stateRoot := &types.StateRootProposal{
ProposalID: lastProposal.ProposalID,
OutputRoot: lastProposal.OutputRoot,
StartL1Timestamp: lastProposal.StartL1Timestamp,
EndL1Timestamp: lastProposal.EndL1Timestamp,
StartL2BlockNumber: lastProposal.StartL2BlockNumber,
EndL2BlockNumber: lastProposal.EndL2BlockNumber,
OutputStartIndex: lastProposal.OutputStartIndex,
OutputEndIndex: lastProposal.OutputEndIndex,
}
btcStateRoot := &types.BtcStateRootProposal{
Proposal: stateRoot,
ChainID: ctx.B2NodeConfig.ChainID,
}
content, err := json.Marshal(btcStateRoot)
if err != nil {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] Pending btcHash Try to marshal state root proposal: %s", err.Error())
continue
}
rs, err := inscribe.Inscribe(ctx.BTCConfig.PrivateKey, content,
ctx.BTCConfig.DestinationAddress, btcapi.ChainParams(ctx.BTCConfig.NetworkName))
if err != nil {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] Inscribe state root err: %s\n", errors.WithStack(err).Error())
continue
}
str, err := json.Marshal(rs)
if err != nil {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] Marshal result err: %s\n", errors.WithStack(err).Error())
continue
}
log.Infof("[Handler.GetStateRootAndCommitStateRootProposal] inscribe result: %s", str)
bitcoinTxHash := rs.RevealTxHashList[0].String()
_, err = ctx.OpCommitterClient.BitcoinTxHash(lastProposal.ProposalID, bitcoinTxHash)
if err != nil {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] Try to send bitcoin tx hash: %s", err.Error())
continue
}
log.Infof("[Handler.GetStateRootAndCommitStateRootProposal] success submit content to btc network. proposalID: %s, btcTxHash: %s", lastProposal.ProposalID, bitcoinTxHash)
} else {
outs, err := ctx.UnisatHTTPClient.QueryAPIBTCTxOutputsByTxID(context.Background(), lastProposal.BitcoinTxHash)
if err != nil {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] Try to get outputs from btc: %s", err.Error())
time.Sleep(3 * time.Second)
continue
}
if len(outs.Data) <= 0 {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] Try to get outputs from btc: no data")
time.Sleep(3 * time.Second)
continue
}
if len(outs.Data[0].Inscriptions) <= 0 {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] Try to get outputs from btc: no inscription")
time.Sleep(3 * time.Second)
continue
}
blockHeight := outs.Data[0].Height + 6
if uint64(ctx.LatestBTCBlockNumber) < blockHeight {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] Try to get outputs from btc: block height is too low")
time.Sleep(3 * time.Second)
continue
}

insID := outs.Data[0].Inscriptions[0].InscriptionID
btcStateRootProposal, err := ctx.UnisatHTTPClient.QueryStateRootProposalByInsID(context.Background(), insID)
if lastProposal.ProposalID != btcStateRootProposal.Proposal.ProposalID ||
btcStateRootProposal.Proposal.OutputRoot != lastProposal.OutputRoot ||
btcStateRootProposal.Proposal.StartL1Timestamp != lastProposal.StartL1Timestamp ||
btcStateRootProposal.Proposal.EndL1Timestamp != lastProposal.EndL1Timestamp ||
btcStateRootProposal.Proposal.StartL2BlockNumber != lastProposal.StartL2BlockNumber ||
btcStateRootProposal.Proposal.EndL2BlockNumber != lastProposal.EndL2BlockNumber ||
btcStateRootProposal.Proposal.OutputStartIndex != lastProposal.OutputStartIndex ||
btcStateRootProposal.Proposal.OutputEndIndex != lastProposal.OutputEndIndex ||
btcStateRootProposal.ChainID != ctx.B2NodeConfig.ChainID {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] Try to verify btc state root proposal: %s", err.Error())
time.Sleep(3 * time.Second)
continue
}

_, err = ctx.OpCommitterClient.BitcoinTxHash(lastProposal.ProposalID, lastProposal.BitcoinTxHash)
if err != nil {
log.Errorf("[Handler.GetStateRootAndCommitStateRootProposal] Try to vote bitcoin tx hash: %s", err.Error())
continue
}
log.Infof("[Handler.GetStateRootAndCommitStateRootProposal] success verify and vote submit output from btc: %s, btcTxHash: %s", lastProposal.ProposalID, lastProposal.BitcoinTxHash)
}

}

}
}

func constructNextStateRootProposal(ctx *svc.ServiceContext, lastProposal op.OpProposalStateRootProposal) (*types.StateRootProposal, error) {
Expand Down
8 changes: 4 additions & 4 deletions internal/handler/op_committer_txs.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,14 @@ func GetBlobsAndCommitTxsProposal(ctx *svc.ServiceContext) {
continue
}
blobMerkleRoot, err := GetBlobsMerkleRoot(blobs)
dsProposal := types.NewDsProposal(ctx.B2NodeConfig.ChainID, lastProposal.ProposalID, blobMerkleRoot, blobs)
dsProposal := types.NewDsTxsProposal(ctx.B2NodeConfig.ChainID, lastProposal.ProposalID, blobMerkleRoot, blobs)
dsJson, err := dsProposal.MarshalJson()
if err != nil {
log.Errorf("[Handler.GetBlobsAndCommitProposal] Try to marshal ds proposal: %s", err.Error())
time.Sleep(3 * time.Second)
continue
}
dsTxID, err := ctx.DecentralizedStore.StoreTxsOnChain(dsJson, ctx.B2NodeConfig.ChainID, lastProposal.ProposalID)
dsTxID, err := ctx.DecentralizedStore.StoreDetailsOnChain(dsJson, ctx.B2NodeConfig.ChainID, lastProposal.ProposalID)
if err != nil {
log.Errorf("[Handler.GetBlobsAndCommitProposal] Try to store ds proposal: %s", err.Error())
continue
Expand All @@ -138,13 +138,13 @@ func GetBlobsAndCommitTxsProposal(ctx *svc.ServiceContext) {
log.Infof("[Handler.GetBlobsAndCommitProposal] success submit txs to ds: %s, dsHash: %s", lastProposal.ProposalID, lastProposal.DsTxHash)
}
if lastProposal.Winner != common.HexToAddress(ctx.B2NodeConfig.Address) {
blobs, err := ctx.DecentralizedStore.QueryTxsByTxID(lastProposal.DsTxHash)
blobs, err := ctx.DecentralizedStore.QueryDetailsByTxID(lastProposal.DsTxHash)
if err != nil {
log.Errorf("[Handler.GetBlobsAndCommitProposal] Try to get blobs from ds: %s", err.Error())
time.Sleep(3 * time.Second)
continue
}
var dsProposal types.DsProposal
var dsProposal types.DsTxsProposal
err = json.Unmarshal(blobs, &dsProposal)
if err != nil {
log.Errorf("[Handler.GetBlobsAndCommitProposal] Try to unmarshal ds proposal: %s", err.Error())
Expand Down
6 changes: 5 additions & 1 deletion internal/svc/svc.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/b2network/b2committer/pkg/contract/op"
"github.com/b2network/b2committer/pkg/ds"
"github.com/b2network/b2committer/pkg/log"
"github.com/b2network/b2committer/pkg/unisat"
"github.com/ethereum-optimism/optimism/op-service/sources"
"github.com/ethereum/go-ethereum/common"
ethTypes "github.com/ethereum/go-ethereum/core/types"
Expand Down Expand Up @@ -38,6 +39,7 @@ type ServiceContext struct {
SyncedBlobBlockHash common.Hash
OpCommitterClient *b2node.OpCommitterClient
DecentralizedStore ds.DecentralizedStore
UnisatHTTPClient *unisat.UnisatHTTPClient
}

func NewServiceContext(cfg *types.Config, bitcoinCfg *types.BitcoinRPCConfig, b2nodeConfig *types.B2NODEConfig) *ServiceContext {
Expand Down Expand Up @@ -92,7 +94,7 @@ func NewServiceContext(cfg *types.Config, bitcoinCfg *types.BitcoinRPCConfig, b2
log.Panicf("[svc] init committer contract panic: %s\n", err)
}
opCommitterClient := b2node.NewOpCommitterClient(b2nodeConfig.PrivateKey, b2nodeConfig.ChainID, proposer, committer, proposalManager)

unisatClient := unisat.NewUnisatHTTPClient(client.NewBasicHTTPClient(cfg.UnisatURL), cfg.UnisatAuth)
svc = &ServiceContext{
BTCConfig: bitcoinCfg,
DB: storage,
Expand All @@ -103,6 +105,7 @@ func NewServiceContext(cfg *types.Config, bitcoinCfg *types.BitcoinRPCConfig, b2
NodeClient: nodeClient,
BlobDataSource: bds,
OpCommitterClient: opCommitterClient,
UnisatHTTPClient: unisatClient,
}

dsType := cfg.DSType
Expand All @@ -126,5 +129,6 @@ func NewServiceContext(cfg *types.Config, bitcoinCfg *types.BitcoinRPCConfig, b2

svc.DecentralizedStore = ds.NewArWeave(w, arClient)
}

return svc
}
Loading

0 comments on commit 0d7eb8d

Please sign in to comment.