From 33a8d61b744961755e7c121b2e6b2f01f6d4cdc8 Mon Sep 17 00:00:00 2001 From: sleepy ramen Date: Mon, 15 Nov 2021 20:30:36 +0100 Subject: [PATCH 01/23] checkpointing module and starting listener at start (#1) --- .gitignore | 3 + chain/checkpointing/sub.go | 108 +++++++++++++++++++++++++++++++ chain/consensus/delegcns/mine.go | 7 ++ cmd/eudico/delegated.go | 5 ++ cmd/eudico/types.go | 5 ++ 5 files changed, 128 insertions(+) create mode 100644 chain/checkpointing/sub.go diff --git a/.gitignore b/.gitignore index 9cc0bcf0c..b6a7c5533 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,6 @@ bin/ipget bin/tmp/* .idea scratchpad + +gen.gen +*.key \ No newline at end of file diff --git a/chain/checkpointing/sub.go b/chain/checkpointing/sub.go new file mode 100644 index 000000000..087495660 --- /dev/null +++ b/chain/checkpointing/sub.go @@ -0,0 +1,108 @@ +package checkpointing + +import ( + "context" + "fmt" + + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/chain/events" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/node/impl" + "github.com/filecoin-project/lotus/node/modules/helpers" + "github.com/filecoin-project/specs-actors/actors/builtin" + logging "github.com/ipfs/go-log/v2" + "github.com/libp2p/go-libp2p-core/host" + pubsub "github.com/libp2p/go-libp2p-pubsub" + "go.uber.org/fx" +) + +var log = logging.Logger("checkpointing") + +type CheckpointingSub struct { + host host.Host + pubsub *pubsub.PubSub + // This is the API for the fullNode in the root chain. + api *impl.FullNodeAPI + // Listener for events of the root chain. + events *events.Events +} + +func NewCheckpointSub( + mctx helpers.MetricsCtx, + lc fx.Lifecycle, + host host.Host, + pubsub *pubsub.PubSub, + api impl.FullNodeAPI, +) (*CheckpointingSub, error) { + + ctx := helpers.LifecycleCtx(mctx, lc) + // Starting shardSub to listen to events in the root chain. + e, err := events.NewEvents(ctx, &api) + if err != nil { + return nil, err + } + return &CheckpointingSub{ + pubsub: pubsub, + host: host, + api: &api, + events: e, + }, nil +} + +func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { + + checkFunc := func(ctx context.Context, ts *types.TipSet) (done bool, more bool, err error) { + return false, true, nil + } + + changeHandler := func(oldTs, newTs *types.TipSet, states events.StateChange, curH abi.ChainEpoch) (more bool, err error) { + log.Infow("State change detected for power actor") + + return true, nil + } + + revertHandler := func(ctx context.Context, ts *types.TipSet) error { + return nil + } + + match := func(oldTs, newTs *types.TipSet) (bool, events.StateChange, error) { + oldAct, err := c.api.StateGetActor(ctx, builtin.StoragePowerActorAddr, oldTs.Key()) + if err != nil { + return false, nil, err + } + newAct, err := c.api.StateGetActor(ctx, builtin.StoragePowerActorAddr, newTs.Key()) + if err != nil { + return false, nil, err + } + + // ZONDAX TODO: + // If Power Actors list has changed start DKG + + fmt.Print(oldAct) + fmt.Println(newAct) + + return true, nil, nil + } + + err := c.events.StateChanged(checkFunc, changeHandler, revertHandler, 5, 76587687658765876, match) + if err != nil { + return + } +} + +func (c *CheckpointingSub) Start(ctx context.Context) { + c.listenCheckpointEvents(ctx) +} + +func BuildCheckpointingSub(mctx helpers.MetricsCtx, lc fx.Lifecycle, c *CheckpointingSub) { + ctx := helpers.LifecycleCtx(mctx, lc) + c.Start(ctx) + + lc.Append(fx.Hook{ + OnStop: func(ctx context.Context) error { + // Do we need to stop something here ? + return nil + }, + }) + +} diff --git a/chain/consensus/delegcns/mine.go b/chain/consensus/delegcns/mine.go index 024560caa..3dbcb2c8e 100644 --- a/chain/consensus/delegcns/mine.go +++ b/chain/consensus/delegcns/mine.go @@ -81,6 +81,13 @@ func Mine(ctx context.Context, api v1api.FullNode) error { } log.Info("delegated mined a block! ", bh.Cid(), " msgs ", len(msgs)) + + // ZONDAX TODO + // Activate checkpointing every 5 blocks + if base.Height()%5 == 0 { + log.Info("Check point time") + } + case <-ctx.Done(): return nil } diff --git a/cmd/eudico/delegated.go b/cmd/eudico/delegated.go index 0ef3d9977..a5dafd7bc 100644 --- a/cmd/eudico/delegated.go +++ b/cmd/eudico/delegated.go @@ -5,6 +5,7 @@ import ( "time" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/chain/checkpointing" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet" "github.com/urfave/cli/v2" @@ -33,6 +34,10 @@ var delegatedCmd = &cli.Command{ node.Override(new(store.WeightFunc), delegcns.Weight), node.Override(new(stmgr.Executor), delegcns.TipSetExecutor()), node.Override(new(stmgr.UpgradeSchedule), delegcns.DefaultUpgradeSchedule()), + + // Start checkpoint sub + node.Override(new(*checkpointing.CheckpointingSub), checkpointing.NewCheckpointSub), + node.Override(StartCheckpointingSubKey, checkpointing.BuildCheckpointingSub), )), }, } diff --git a/cmd/eudico/types.go b/cmd/eudico/types.go index 411b7af8a..559ba4355 100644 --- a/cmd/eudico/types.go +++ b/cmd/eudico/types.go @@ -1,6 +1,11 @@ package main +import "github.com/filecoin-project/lotus/node" + // TODO: Remove this // import "github.com/filecoin-project/lotus/node" // // var StartSubnetMgrKey = node.AddInvoke() +// var StartShardingSubKey = node.AddInvoke() + +var StartCheckpointingSubKey = node.AddInvoke() From 8d0c87344512f3d2f9a38ec75cbcfe17864719e3 Mon Sep 17 00:00:00 2001 From: sleepy ramen Date: Mon, 29 Nov 2021 21:06:00 +0100 Subject: [PATCH 02/23] DKG + signing (#2) --- .gitignore | 6 +- chain/checkpointing/network.go | 64 ++++ chain/checkpointing/sub.go | 286 +++++++++++++++++- chain/checkpointing/util.go | 249 +++++++++++++++ chain/consensus/delegcns/mine.go | 6 - data/alice/config.toml | 185 +++++++++++ .../alice/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU | 1 + data/alice/keystore/MRSWMYLVNR2A | 1 + data/alice/keystore/NRUWE4BSOAWWQ33TOQ | 1 + ...GE6LMMM2WGM3EGVWHMYLOMRYXONDJO5WDMZLQPBRGC | 1 + data/alice/token | 1 + data/bob/config.toml | 185 +++++++++++ data/bob/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU | 1 + data/bob/keystore/NRUWE4BSOAWWQ33TOQ | 1 + data/bob/token | 1 + data/charlie/config.toml | 185 +++++++++++ .../keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU | 1 + data/charlie/keystore/NRUWE4BSOAWWQ33TOQ | 1 + data/charlie/token | 1 + go.mod | 3 + go.sum | 24 ++ scripts/generate-bitcoin-blocks.sh | 6 + scripts/taproot.sh | 27 ++ 23 files changed, 1222 insertions(+), 15 deletions(-) create mode 100644 chain/checkpointing/network.go create mode 100644 chain/checkpointing/util.go create mode 100644 data/alice/config.toml create mode 100644 data/alice/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU create mode 100644 data/alice/keystore/MRSWMYLVNR2A create mode 100644 data/alice/keystore/NRUWE4BSOAWWQ33TOQ create mode 100644 data/alice/keystore/O5QWY3DFOQWXIMLEGJ4HE6TDONWHQN3YNRRGE6LMMM2WGM3EGVWHMYLOMRYXONDJO5WDMZLQPBRGC create mode 100644 data/alice/token create mode 100644 data/bob/config.toml create mode 100644 data/bob/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU create mode 100644 data/bob/keystore/NRUWE4BSOAWWQ33TOQ create mode 100644 data/bob/token create mode 100644 data/charlie/config.toml create mode 100644 data/charlie/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU create mode 100644 data/charlie/keystore/NRUWE4BSOAWWQ33TOQ create mode 100644 data/charlie/token create mode 100755 scripts/generate-bitcoin-blocks.sh create mode 100755 scripts/taproot.sh diff --git a/.gitignore b/.gitignore index b6a7c5533..e5be6b118 100644 --- a/.gitignore +++ b/.gitignore @@ -50,4 +50,8 @@ bin/tmp/* scratchpad gen.gen -*.key \ No newline at end of file +*.key +data/*/* +!data/*/keystore/ +!data/*/config.toml +!data/*/token \ No newline at end of file diff --git a/chain/checkpointing/network.go b/chain/checkpointing/network.go new file mode 100644 index 000000000..8074d1487 --- /dev/null +++ b/chain/checkpointing/network.go @@ -0,0 +1,64 @@ +package checkpointing + +import ( + "context" + "fmt" + + "github.com/Zondax/multi-party-sig/pkg/party" + "github.com/Zondax/multi-party-sig/pkg/protocol" + pubsub "github.com/libp2p/go-libp2p-pubsub" +) + +type Network struct { + sub *pubsub.Subscription + topic *pubsub.Topic + parties party.IDSlice +} + +func NewNetwork(parties party.IDSlice, sub *pubsub.Subscription, topic *pubsub.Topic) *Network { + c := &Network{ + sub: sub, + topic: topic, + parties: parties, + } + return c +} + +func (n *Network) Next(ctx context.Context) *protocol.Message { + fmt.Println("Waiting for message") + msg, err := n.sub.Next(ctx) + if err != nil { + panic(err) + } + + fmt.Println("Message received") + + // Converting a pubsub.Message into a protocol.Message + // see https://pkg.go.dev/github.com/libp2p/go-libp2p-pubsub@v0.5.3/pb#Message + // https://pkg.go.dev/github.com/taurusgroup/multi-party-sig@v0.6.0-alpha-2021-09-21/pkg/protocol?utm_source=gopls#Message + var pmessage protocol.Message + err = pmessage.UnmarshalBinary(msg.Data) + if err != nil { + panic(err) + } + + return &pmessage +} + +func (n *Network) Send(ctx context.Context, msg *protocol.Message) { + data, err := msg.MarshalBinary() + if err != nil { + panic(err) + } + n.topic.Publish(ctx, data) +} + +func (n *Network) Done() { + fmt.Println("Done") + + /* Might need to do something here ? */ +} + +func (n *Network) Parties() party.IDSlice { + return n.parties +} diff --git a/chain/checkpointing/sub.go b/chain/checkpointing/sub.go index 087495660..b247eca80 100644 --- a/chain/checkpointing/sub.go +++ b/chain/checkpointing/sub.go @@ -2,14 +2,21 @@ package checkpointing import ( "context" + "encoding/binary" + "encoding/hex" "fmt" + "os" + "sort" + "github.com/Zondax/multi-party-sig/pkg/party" + "github.com/Zondax/multi-party-sig/pkg/protocol" + "github.com/Zondax/multi-party-sig/protocols/frost" + "github.com/Zondax/multi-party-sig/protocols/frost/keygen" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/chain/events" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node/impl" "github.com/filecoin-project/lotus/node/modules/helpers" - "github.com/filecoin-project/specs-actors/actors/builtin" logging "github.com/ipfs/go-log/v2" "github.com/libp2p/go-libp2p-core/host" pubsub "github.com/libp2p/go-libp2p-pubsub" @@ -21,10 +28,28 @@ var log = logging.Logger("checkpointing") type CheckpointingSub struct { host host.Host pubsub *pubsub.PubSub + // Topic for keygen + topic *pubsub.Topic + // Sub for keygen + sub *pubsub.Subscription // This is the API for the fullNode in the root chain. api *impl.FullNodeAPI // Listener for events of the root chain. events *events.Events + // Generated public key + pubkey []byte + // taproot config + config *keygen.TaprootConfig + // If we have started the key generation + genkey bool + // Initiated + init bool + // Previous tx + ptxid string + // Tweaked value + tweakedValue []byte + //checkpoint value + cp []byte } func NewCheckpointSub( @@ -41,11 +66,21 @@ func NewCheckpointSub( if err != nil { return nil, err } + + // Load configTaproot + fmt.Println(os.Getenv("EUDICO_PATH")) + // Read file + return &CheckpointingSub{ pubsub: pubsub, + topic: nil, + sub: nil, host: host, api: &api, events: e, + genkey: false, + init: false, + ptxid: "", }, nil } @@ -58,6 +93,62 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { changeHandler := func(oldTs, newTs *types.TipSet, states events.StateChange, curH abi.ChainEpoch) (more bool, err error) { log.Infow("State change detected for power actor") + idsStrings := c.orderParticipantsList() + + fmt.Println("Participants list :", idsStrings) + + ids := c.formIDSlice(idsStrings) + + id := party.ID(c.host.ID().String()) + + threshold := 2 + n := NewNetwork(ids, c.sub, c.topic) + f := frost.KeygenTaproot(id, ids, threshold) + + handler, err := protocol.NewMultiHandler(f, []byte{1, 2, 3}) + + fmt.Println(handler) + + if err != nil { + fmt.Println(err) + log.Fatal("Not working") + } + c.LoopHandler(ctx, handler, n) + r, err := handler.Result() + if err != nil { + fmt.Println(err) + log.Fatal("Not working neither") + } + fmt.Println("Result :", r) + + c.config = r.(*keygen.TaprootConfig) + + if !c.init { + cp := []byte("random data")[:] + pubkeyShort := GenCheckpointPublicKeyTaproot(c.config.PublicKey, cp) + c.pubkey = pubkeyShort + + if idsStrings[0] == c.host.ID().String() { + taprootAddress := PubkeyToTapprootAddress(c.pubkey) + + payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"sendtoaddress\", \"params\": [\"" + taprootAddress + "\", 50]}" + result := jsonRPC(payload) + fmt.Println(result) + if result == nil { + // Should probably not panic here + panic("Couldn't create first transaction") + } + + c.ptxid = result["result"].(string) + } + + // Save tweaked value + merkleRoot := HashMerkleRoot(c.config.PublicKey, cp) + c.tweakedValue = HashTweakedValue(c.config.PublicKey, merkleRoot) + + c.init = true + } + return true, nil } @@ -66,11 +157,21 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { } match := func(oldTs, newTs *types.TipSet) (bool, events.StateChange, error) { - oldAct, err := c.api.StateGetActor(ctx, builtin.StoragePowerActorAddr, oldTs.Key()) - if err != nil { - return false, nil, err - } - newAct, err := c.api.StateGetActor(ctx, builtin.StoragePowerActorAddr, newTs.Key()) + /* + NOT WORKING WITHOUT THE MOCKED POWER ACTOR + + oldAct, err := c.api.StateGetActor(ctx, mpoweractor.MpowerActorAddr, oldTs.Key()) + if err != nil { + return false, nil, err + } + newAct, err := c.api.StateGetActor(ctx, mpoweractor.MpowerActorAddr, newTs.Key()) + if err != nil { + return false, nil, err + } + */ + + // This is not actually what we want. Just here to check. + oldTipset, err := c.api.ChainGetTipSet(ctx, oldTs.Key()) if err != nil { return false, nil, err } @@ -78,8 +179,31 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { // ZONDAX TODO: // If Power Actors list has changed start DKG - fmt.Print(oldAct) - fmt.Println(newAct) + // Only start when we have 3 peers + if len(c.topic.ListPeers()) < 2 { + return false, nil, nil + } + + if c.genkey { + fmt.Println(oldTipset.Height()) + // ZONDAX TODO + // Activate checkpointing every 5 blocks + if oldTipset.Height()%5 == 0 { + fmt.Println("Check point time") + + if c.init && c.config != nil { + fmt.Println("We have a taproot config") + + data := oldTipset.Cids()[0] + + c.CreateCheckpoint(ctx, data.Bytes()) + } + + } + return false, nil, nil + } + + c.genkey = true return true, nil, nil } @@ -92,10 +216,156 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { func (c *CheckpointingSub) Start(ctx context.Context) { c.listenCheckpointEvents(ctx) + + topic, err := c.pubsub.Join("keygen") + if err != nil { + panic(err) + } + c.topic = topic + + // and subscribe to it + sub, err := topic.Subscribe() + if err != nil { + panic(err) + } + c.sub = sub +} + +func (c *CheckpointingSub) LoopHandler(ctx context.Context, h protocol.Handler, network *Network) { + for { + msg, ok := <-h.Listen() + if !ok { + network.Done() + // the channel was closed, indicating that the protocol is done executing. + fmt.Println("Should be good") + return + } + network.Send(ctx, msg) + + for _, _ = range network.Parties() { + msg = network.Next(ctx) + h.Accept(msg) + } + } +} + +func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, data []byte) { + idsStrings := c.orderParticipantsList() + fmt.Println("Participants list :", idsStrings) + ids := c.formIDSlice(idsStrings) + taprootAddress := PubkeyToTapprootAddress(c.pubkey) + + if c.ptxid == "" { + taprootScript := GetTaprootScript(c.pubkey) + success := AddTaprootScriptToWallet(taprootScript) + if !success { + panic("failed to add taproot address to wallet") + } + + ptxid, err := WalletGetTxidFromAddress(taprootAddress) + fmt.Println(taprootAddress) + if err != nil { + panic(err) + } + c.ptxid = ptxid + fmt.Println("Found precedent txid:", c.ptxid) + } + + //if idsStrings[0] == c.host.ID().String() { + { + // The first participant create the message to sign + payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"createrawtransaction\", \"params\": [[{\"txid\":\"" + c.ptxid + "\",\"vout\": 0, \"sequence\": 4294967295}], [{\"" + taprootAddress + "\": \"50\"}, {\"data\": \"636964\"}]]}" + result := jsonRPC(payload) + if result == nil { + panic("cant create new transaction") + } + + rawTransaction := result["result"].(string) + + payload = "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"gettxout\", \"params\": [\"" + c.ptxid + "\", 0]}" + + result = jsonRPC(payload) + if result == nil { + panic("cant retrieve previous transaction") + } + taprootTxOut := result["result"].(map[string]interface{}) + scriptPubkey := taprootTxOut["scriptPubKey"].(map[string]interface{}) + scriptPubkeyBytes, _ := hex.DecodeString(scriptPubkey["hex"].(string)) + + var buf [8]byte + binary.LittleEndian.PutUint64(buf[:], uint64(taprootTxOut["value"].(float64)*100000000)) + + tx, err := hex.DecodeString(rawTransaction) + if err != nil { + panic(err) + } + utxo := append(buf[:], []byte{34}...) + utxo = append(utxo, scriptPubkeyBytes...) + + hashedTx, err := TaprootSignatureHash(tx, utxo, 0x00) + if err != nil { + panic(err) + } + + /* + * Orchestrate the signing message + */ + + f := frost.SignTaprootWithTweak(c.config, ids, hashedTx[:], c.tweakedValue[:]) + n := NewNetwork(ids, c.sub, c.topic) + handler, err := protocol.NewMultiHandler(f, []byte{1, 2, 3}) + if err != nil { + panic(err) + } + c.LoopHandler(ctx, handler, n) + r, err := handler.Result() + if err != nil { + fmt.Println(err) + log.Fatal("Not working neither") + } + fmt.Println("Result :", r) + } + +} + +func (c *CheckpointingSub) orderParticipantsList() []string { + id := c.host.ID().String() + var ids []string + + ids = append(ids, id) + + for _, p := range c.topic.ListPeers() { + ids = append(ids, p.String()) + } + + sort.Strings(ids) + + return ids +} + +func (c *CheckpointingSub) formIDSlice(ids []string) party.IDSlice { + var _ids []party.ID + for _, p := range ids { + _ids = append(_ids, party.ID(p)) + } + + idsSlice := party.NewIDSlice(_ids) + + return idsSlice } func BuildCheckpointingSub(mctx helpers.MetricsCtx, lc fx.Lifecycle, c *CheckpointingSub) { ctx := helpers.LifecycleCtx(mctx, lc) + + // Ping to see if bitcoind is available + success := BitcoindPing() + if !success { + // Should probably not panic here + panic("Bitcoin node not available") + } + + fmt.Println("Successfully pinged bitcoind") + c.Start(ctx) lc.Append(fx.Hook{ diff --git a/chain/checkpointing/util.go b/chain/checkpointing/util.go new file mode 100644 index 000000000..81c91e8e7 --- /dev/null +++ b/chain/checkpointing/util.go @@ -0,0 +1,249 @@ +package checkpointing + +import ( + "crypto/sha256" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "net/http" + "strings" + + "github.com/Zondax/multi-party-sig/pkg/math/curve" + "github.com/btcsuite/btcutil/bech32" + "github.com/cronokirby/safenum" +) + +func TaggedHash(tag string, datas ...[]byte) []byte { + tagSum := sha256.Sum256([]byte(tag)) + + h := sha256.New() + h.Write(tagSum[:]) + h.Write(tagSum[:]) + for _, data := range datas { + h.Write(data) + } + return h.Sum(nil) +} + +func Sha256(data []byte) []byte { + h := sha256.New() + h.Write(data[:]) + return h.Sum(nil) +} + +func TaprootSignatureHash(tx []byte, utxo []byte, hash_type byte) ([]byte, error) { + if hash_type != 0x00 { + return nil, errors.New("only support SIGHASH_DEFAULT (0x00)") + } + + var ss []byte + + ext_flag := 0x00 + ss = append(ss, byte(ext_flag)) + + // Epoch + ss = append(ss, 0x00) + + // version (4 bytes) + ss = append(ss, tx[:4]...) + // locktime + ss = append(ss, tx[len(tx)-4:]...) + // Transaction level data + // !IMPORTANT! This only work because we have 1 utxo. + // Please check https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message + + // Previous output (txid + index = 36 bytes) + ss = append(ss, Sha256(tx[5:5+36])...) + + // Amount in the previous output (8 bytes) + ss = append(ss, Sha256(utxo[0:8])...) + + // PubScript in the previous output (35 bytes) + ss = append(ss, Sha256(utxo[8:8+35])...) + + // Sequence (4 bytes) + ss = append(ss, Sha256(tx[5+36+1:5+36+1+4])...) + + // Adding new txouts + ss = append(ss, Sha256(tx[47:len(tx)-4])...) + + // spend type (here key path spending) + ss = append(ss, 0x00) + + // Input index + ss = append(ss, []byte{0, 0, 0, 0}...) + + return TaggedHash("TapSighash", ss), nil +} + +func PubkeyToTapprootAddress(pubkey []byte) string { + conv, err := bech32.ConvertBits(pubkey, 8, 5, true) + if err != nil { + fmt.Println("Error:", err) + log.Fatal("I dunno.") + } + + // Add segwit version byte 1 + conv = append([]byte{0x01}, conv...) + + // regtest human-readable part is "bcrt" according to no documentation ever... (see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki) + // Using EncodeM becasue we want bech32m... which has a new checksum + taprootAddress, err := bech32.EncodeM("bcrt", conv) + if err != nil { + fmt.Println(err) + log.Fatal("Couldn't produce our tapproot address.") + } + return taprootAddress +} + +func PubkeyToTapprootAddressLegacy(pubkey []byte) string { + conv, err := bech32.ConvertBits(pubkey, 8, 5, true) + if err != nil { + fmt.Println("Error:", err) + log.Fatal("I dunno.") + } + // Add segwit version byte 1 + conv = append([]byte{0x01}, conv...) + + taprootAddressLegacy, err := bech32.Encode("bcrt", conv) + if err != nil { + fmt.Println(err) + log.Fatal("Couldn't produce our tapproot address.") + } + return taprootAddressLegacy +} + +func ApplyTweakToPublicKeyTaproot(public []byte, tweak []byte) []byte { + group := curve.Secp256k1{} + s_tweak := group.NewScalar().SetNat(new(safenum.Nat).SetBytes(tweak)) + p_tweak := s_tweak.ActOnBase() + + P, _ := curve.Secp256k1{}.LiftX(public) + + Y_tweak := P.Add(p_tweak) + YSecp := Y_tweak.(*curve.Secp256k1Point) + if !YSecp.HasEvenY() { + s_tweak.Negate() + p_tweak := s_tweak.ActOnBase() + Y_tweak = P.Negate().Add(p_tweak) + YSecp = Y_tweak.(*curve.Secp256k1Point) + } + PBytes := YSecp.XBytes() + return PBytes +} + +func HashMerkleRoot(pubkey []byte, checkpoint []byte) []byte { + merkle_root := TaggedHash("TapLeaf", []byte{0xc0}, pubkey, checkpoint) + return merkle_root[:] +} + +func HashTweakedValue(pubkey []byte, merkle_root []byte) []byte { + tweaked_value := TaggedHash("TapTweak", pubkey, merkle_root) + return tweaked_value[:] +} + +func GenCheckpointPublicKeyTaproot(internal_pubkey []byte, checkpoint []byte) []byte { + merkle_root := HashMerkleRoot(internal_pubkey, checkpoint) + tweaked_value := HashTweakedValue(internal_pubkey, merkle_root) + + tweaked_pubkey := ApplyTweakToPublicKeyTaproot(internal_pubkey, tweaked_value) + return tweaked_pubkey +} + +func AddTaprootScriptToWallet(taprootScript string) bool { + payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"importaddress\", \"params\": [\"" + taprootScript + "\", \"\", true]}" + result := jsonRPC(payload) + + if result["error"] == nil { + return true + } + + err := result["error"].(map[string]interface{}) + if err["code"].(float64) == -4 { + // Particular case where we are already in the process of adding the key + // because we are using 1 bitcoin node for all + return true + } + + return false +} + +func GetTaprootScript(pubkey []byte) string { + return "5120" + hex.EncodeToString(pubkey) +} + +// Temporary +func BitcoindGetWalletAddress() string { + // Create wallet + payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"createwallet\", \"params\": [\"wow\"]}" + _ = jsonRPC(payload) + // We don't cehck error here + + //Get new address + payload = "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"getnewaddress\", \"params\": []}" + + result := jsonRPC(payload) + address := fmt.Sprintf("%v", result["result"]) + return address +} + +func WalletGetTxidFromAddress(taprootAddress string) (string, error) { + payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"listtransactions\", \"params\": [\"*\", 500000000, 0, true]}" + result := jsonRPC(payload) + list := result["result"].([]interface{}) + for _, item := range list { + item_map := item.(map[string]interface{}) + fmt.Println(item_map) + if item_map["address"] == taprootAddress { + txid := item_map["txid"].(string) + return txid, nil + } + } + return "", errors.New("did not find checkpoint") +} + +func BitcoindPing() bool { + payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"ping\", \"params\": []}" + result := jsonRPC(payload) + return result != nil +} + +func jsonRPC(payload string) map[string]interface{} { + // ZONDAX TODO + // This needs to be in a config file + url := "http://127.0.0.1:18443" + method := "POST" + + user := "satoshi" + password := "amiens" + + client := &http.Client{} + + p := strings.NewReader(payload) + req, err := http.NewRequest(method, url, p) + + if err != nil { + fmt.Println(err) + return nil + } + req.SetBasicAuth(user, password) + + res, err := client.Do(req) + if err != nil { + fmt.Println(err) + return nil + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + fmt.Println(err) + return nil + } + + var result map[string]interface{} + json.Unmarshal([]byte(body), &result) + return result +} diff --git a/chain/consensus/delegcns/mine.go b/chain/consensus/delegcns/mine.go index 3dbcb2c8e..acf88e4c3 100644 --- a/chain/consensus/delegcns/mine.go +++ b/chain/consensus/delegcns/mine.go @@ -82,12 +82,6 @@ func Mine(ctx context.Context, api v1api.FullNode) error { log.Info("delegated mined a block! ", bh.Cid(), " msgs ", len(msgs)) - // ZONDAX TODO - // Activate checkpointing every 5 blocks - if base.Height()%5 == 0 { - log.Info("Check point time") - } - case <-ctx.Done(): return nil } diff --git a/data/alice/config.toml b/data/alice/config.toml new file mode 100644 index 000000000..567bdf27c --- /dev/null +++ b/data/alice/config.toml @@ -0,0 +1,185 @@ +[API] + # Binding address for the Lotus API + # + # type: string + # env var: LOTUS_API_LISTENADDRESS + ListenAddress = "/ip4/127.0.0.1/tcp/1234/http" + + # type: string + # env var: LOTUS_API_REMOTELISTENADDRESS + #RemoteListenAddress = "" + + # type: Duration + # env var: LOTUS_API_TIMEOUT + #Timeout = "30s" + + +[Backup] + # Note that in case of metadata corruption it might be much harder to recover + # your node if metadata log is disabled + # + # type: bool + # env var: LOTUS_BACKUP_DISABLEMETADATALOG + #DisableMetadataLog = false + + +[Libp2p] + # Binding address for the libp2p host - 0 means random port. + # Format: multiaddress; see https://multiformats.io/multiaddr/ + # + # type: []string + # env var: LOTUS_LIBP2P_LISTENADDRESSES + ListenAddresses = ["/ip4/0.0.0.0/tcp/3000", "/ip6/::/tcp/3000"] + + # Addresses to explicitally announce to other peers. If not specified, + # all interface addresses are announced + # Format: multiaddress + # + # type: []string + # env var: LOTUS_LIBP2P_ANNOUNCEADDRESSES + #AnnounceAddresses = [] + + # Addresses to not announce + # Format: multiaddress + # + # type: []string + # env var: LOTUS_LIBP2P_NOANNOUNCEADDRESSES + #NoAnnounceAddresses = [] + + # When not disabled (default), lotus asks NAT devices (e.g., routers), to + # open up an external port and forward it to the port lotus is running on. + # When this works (i.e., when your router supports NAT port forwarding), + # it makes the local lotus node accessible from the public internet + # + # type: bool + # env var: LOTUS_LIBP2P_DISABLENATPORTMAP + #DisableNatPortMap = false + + # ConnMgrLow is the number of connections that the basic connection manager + # will trim down to. + # + # type: uint + # env var: LOTUS_LIBP2P_CONNMGRLOW + #ConnMgrLow = 150 + + # ConnMgrHigh is the number of connections that, when exceeded, will trigger + # a connection GC operation. Note: protected/recently formed connections don't + # count towards this limit. + # + # type: uint + # env var: LOTUS_LIBP2P_CONNMGRHIGH + #ConnMgrHigh = 180 + + # ConnMgrGrace is a time duration that new connections are immune from being + # closed by the connection manager. + # + # type: Duration + # env var: LOTUS_LIBP2P_CONNMGRGRACE + #ConnMgrGrace = "20s" + + +[Pubsub] + # Run the node in bootstrap-node mode + # + # type: bool + # env var: LOTUS_PUBSUB_BOOTSTRAPPER + #Bootstrapper = false + + # type: string + # env var: LOTUS_PUBSUB_REMOTETRACER + #RemoteTracer = "" + + +[Client] + # type: bool + # env var: LOTUS_CLIENT_USEIPFS + #UseIpfs = false + + # type: bool + # env var: LOTUS_CLIENT_IPFSONLINEMODE + #IpfsOnlineMode = false + + # type: string + # env var: LOTUS_CLIENT_IPFSMADDR + #IpfsMAddr = "" + + # type: bool + # env var: LOTUS_CLIENT_IPFSUSEFORRETRIEVAL + #IpfsUseForRetrieval = false + + # The maximum number of simultaneous data transfers between the client + # and storage providers for storage deals + # + # type: uint64 + # env var: LOTUS_CLIENT_SIMULTANEOUSTRANSFERSFORSTORAGE + #SimultaneousTransfersForStorage = 20 + + # The maximum number of simultaneous data transfers between the client + # and storage providers for retrieval deals + # + # type: uint64 + # env var: LOTUS_CLIENT_SIMULTANEOUSTRANSFERSFORRETRIEVAL + #SimultaneousTransfersForRetrieval = 20 + + +[Wallet] + # type: string + # env var: LOTUS_WALLET_REMOTEBACKEND + #RemoteBackend = "" + + # type: bool + # env var: LOTUS_WALLET_ENABLELEDGER + #EnableLedger = false + + # type: bool + # env var: LOTUS_WALLET_DISABLELOCAL + #DisableLocal = false + + +[Fees] + # type: types.FIL + # env var: LOTUS_FEES_DEFAULTMAXFEE + #DefaultMaxFee = "0.07 FIL" + + +[Chainstore] + # type: bool + # env var: LOTUS_CHAINSTORE_ENABLESPLITSTORE + #EnableSplitstore = false + + [Chainstore.Splitstore] + # ColdStoreType specifies the type of the coldstore. + # It can be "universal" (default) or "discard" for discarding cold blocks. + # + # type: string + # env var: LOTUS_CHAINSTORE_SPLITSTORE_COLDSTORETYPE + #ColdStoreType = "universal" + + # HotStoreType specifies the type of the hotstore. + # Only currently supported value is "badger". + # + # type: string + # env var: LOTUS_CHAINSTORE_SPLITSTORE_HOTSTORETYPE + #HotStoreType = "badger" + + # MarkSetType specifies the type of the markset. + # It can be "map" (default) for in memory marking or "badger" for on-disk marking. + # + # type: string + # env var: LOTUS_CHAINSTORE_SPLITSTORE_MARKSETTYPE + #MarkSetType = "map" + + # HotStoreMessageRetention specifies the retention policy for messages, in finalities beyond + # the compaction boundary; default is 0. + # + # type: uint64 + # env var: LOTUS_CHAINSTORE_SPLITSTORE_HOTSTOREMESSAGERETENTION + #HotStoreMessageRetention = 0 + + # HotStoreFullGCFrequency specifies how often to perform a full (moving) GC on the hotstore. + # A value of 0 disables, while a value 1 will do full GC in every compaction. + # Default is 20 (about once a week). + # + # type: uint64 + # env var: LOTUS_CHAINSTORE_SPLITSTORE_HOTSTOREFULLGCFREQUENCY + #HotStoreFullGCFrequency = 20 diff --git a/data/alice/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU b/data/alice/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU new file mode 100644 index 000000000..ee63c46ab --- /dev/null +++ b/data/alice/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU @@ -0,0 +1 @@ +{"Type":"jwt-hmac-secret","PrivateKey":"uqujAEsAAM0A+4GwmywzA3uiBLJgRkpS4geuXZQzXko="} \ No newline at end of file diff --git a/data/alice/keystore/MRSWMYLVNR2A b/data/alice/keystore/MRSWMYLVNR2A new file mode 100644 index 000000000..3e74a17f6 --- /dev/null +++ b/data/alice/keystore/MRSWMYLVNR2A @@ -0,0 +1 @@ +{"Type":"secp256k1","PrivateKey":"8VcW07ADswS4BV2cxi5rnIadVsyTDDhY1NfDH19T8Uo="} \ No newline at end of file diff --git a/data/alice/keystore/NRUWE4BSOAWWQ33TOQ b/data/alice/keystore/NRUWE4BSOAWWQ33TOQ new file mode 100644 index 000000000..116f7a2be --- /dev/null +++ b/data/alice/keystore/NRUWE4BSOAWWQ33TOQ @@ -0,0 +1 @@ +{"Type":"libp2p-host","PrivateKey":"CAESQEztxOsWTHFFmqkcTzyVl0ZaRKNPtWVcpv6YU0YPMAOaqOCjp1qnEbCnn1zifx1Qy8JwD0RBlm4WwFJWZCZaTZc="} \ No newline at end of file diff --git a/data/alice/keystore/O5QWY3DFOQWXIMLEGJ4HE6TDONWHQN3YNRRGE6LMMM2WGM3EGVWHMYLOMRYXONDJO5WDMZLQPBRGC b/data/alice/keystore/O5QWY3DFOQWXIMLEGJ4HE6TDONWHQN3YNRRGE6LMMM2WGM3EGVWHMYLOMRYXONDJO5WDMZLQPBRGC new file mode 100644 index 000000000..3e74a17f6 --- /dev/null +++ b/data/alice/keystore/O5QWY3DFOQWXIMLEGJ4HE6TDONWHQN3YNRRGE6LMMM2WGM3EGVWHMYLOMRYXONDJO5WDMZLQPBRGC @@ -0,0 +1 @@ +{"Type":"secp256k1","PrivateKey":"8VcW07ADswS4BV2cxi5rnIadVsyTDDhY1NfDH19T8Uo="} \ No newline at end of file diff --git a/data/alice/token b/data/alice/token new file mode 100644 index 000000000..efa5ba845 --- /dev/null +++ b/data/alice/token @@ -0,0 +1 @@ +eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJBbGxvdyI6WyJyZWFkIiwid3JpdGUiLCJzaWduIiwiYWRtaW4iXX0.5vRs10xGPlN132VXqL396WAPiqYTVPKPasqu1TMLqzU \ No newline at end of file diff --git a/data/bob/config.toml b/data/bob/config.toml new file mode 100644 index 000000000..1e80a901f --- /dev/null +++ b/data/bob/config.toml @@ -0,0 +1,185 @@ +[API] + # Binding address for the Lotus API + # + # type: string + # env var: LOTUS_API_LISTENADDRESS + ListenAddress = "/ip4/127.0.0.1/tcp/1235/http" + + # type: string + # env var: LOTUS_API_REMOTELISTENADDRESS + #RemoteListenAddress = "" + + # type: Duration + # env var: LOTUS_API_TIMEOUT + #Timeout = "30s" + + +[Backup] + # Note that in case of metadata corruption it might be much harder to recover + # your node if metadata log is disabled + # + # type: bool + # env var: LOTUS_BACKUP_DISABLEMETADATALOG + #DisableMetadataLog = false + + +[Libp2p] + # Binding address for the libp2p host - 0 means random port. + # Format: multiaddress; see https://multiformats.io/multiaddr/ + # + # type: []string + # env var: LOTUS_LIBP2P_LISTENADDRESSES + ListenAddresses = ["/ip4/0.0.0.0/tcp/3001", "/ip6/::/tcp/3001"] + + # Addresses to explicitally announce to other peers. If not specified, + # all interface addresses are announced + # Format: multiaddress + # + # type: []string + # env var: LOTUS_LIBP2P_ANNOUNCEADDRESSES + #AnnounceAddresses = [] + + # Addresses to not announce + # Format: multiaddress + # + # type: []string + # env var: LOTUS_LIBP2P_NOANNOUNCEADDRESSES + #NoAnnounceAddresses = [] + + # When not disabled (default), lotus asks NAT devices (e.g., routers), to + # open up an external port and forward it to the port lotus is running on. + # When this works (i.e., when your router supports NAT port forwarding), + # it makes the local lotus node accessible from the public internet + # + # type: bool + # env var: LOTUS_LIBP2P_DISABLENATPORTMAP + #DisableNatPortMap = false + + # ConnMgrLow is the number of connections that the basic connection manager + # will trim down to. + # + # type: uint + # env var: LOTUS_LIBP2P_CONNMGRLOW + #ConnMgrLow = 150 + + # ConnMgrHigh is the number of connections that, when exceeded, will trigger + # a connection GC operation. Note: protected/recently formed connections don't + # count towards this limit. + # + # type: uint + # env var: LOTUS_LIBP2P_CONNMGRHIGH + #ConnMgrHigh = 180 + + # ConnMgrGrace is a time duration that new connections are immune from being + # closed by the connection manager. + # + # type: Duration + # env var: LOTUS_LIBP2P_CONNMGRGRACE + #ConnMgrGrace = "20s" + + +[Pubsub] + # Run the node in bootstrap-node mode + # + # type: bool + # env var: LOTUS_PUBSUB_BOOTSTRAPPER + #Bootstrapper = false + + # type: string + # env var: LOTUS_PUBSUB_REMOTETRACER + #RemoteTracer = "" + + +[Client] + # type: bool + # env var: LOTUS_CLIENT_USEIPFS + #UseIpfs = false + + # type: bool + # env var: LOTUS_CLIENT_IPFSONLINEMODE + #IpfsOnlineMode = false + + # type: string + # env var: LOTUS_CLIENT_IPFSMADDR + #IpfsMAddr = "" + + # type: bool + # env var: LOTUS_CLIENT_IPFSUSEFORRETRIEVAL + #IpfsUseForRetrieval = false + + # The maximum number of simultaneous data transfers between the client + # and storage providers for storage deals + # + # type: uint64 + # env var: LOTUS_CLIENT_SIMULTANEOUSTRANSFERSFORSTORAGE + #SimultaneousTransfersForStorage = 20 + + # The maximum number of simultaneous data transfers between the client + # and storage providers for retrieval deals + # + # type: uint64 + # env var: LOTUS_CLIENT_SIMULTANEOUSTRANSFERSFORRETRIEVAL + #SimultaneousTransfersForRetrieval = 20 + + +[Wallet] + # type: string + # env var: LOTUS_WALLET_REMOTEBACKEND + #RemoteBackend = "" + + # type: bool + # env var: LOTUS_WALLET_ENABLELEDGER + #EnableLedger = false + + # type: bool + # env var: LOTUS_WALLET_DISABLELOCAL + #DisableLocal = false + + +[Fees] + # type: types.FIL + # env var: LOTUS_FEES_DEFAULTMAXFEE + #DefaultMaxFee = "0.07 FIL" + + +[Chainstore] + # type: bool + # env var: LOTUS_CHAINSTORE_ENABLESPLITSTORE + #EnableSplitstore = false + + [Chainstore.Splitstore] + # ColdStoreType specifies the type of the coldstore. + # It can be "universal" (default) or "discard" for discarding cold blocks. + # + # type: string + # env var: LOTUS_CHAINSTORE_SPLITSTORE_COLDSTORETYPE + #ColdStoreType = "universal" + + # HotStoreType specifies the type of the hotstore. + # Only currently supported value is "badger". + # + # type: string + # env var: LOTUS_CHAINSTORE_SPLITSTORE_HOTSTORETYPE + #HotStoreType = "badger" + + # MarkSetType specifies the type of the markset. + # It can be "map" (default) for in memory marking or "badger" for on-disk marking. + # + # type: string + # env var: LOTUS_CHAINSTORE_SPLITSTORE_MARKSETTYPE + #MarkSetType = "map" + + # HotStoreMessageRetention specifies the retention policy for messages, in finalities beyond + # the compaction boundary; default is 0. + # + # type: uint64 + # env var: LOTUS_CHAINSTORE_SPLITSTORE_HOTSTOREMESSAGERETENTION + #HotStoreMessageRetention = 0 + + # HotStoreFullGCFrequency specifies how often to perform a full (moving) GC on the hotstore. + # A value of 0 disables, while a value 1 will do full GC in every compaction. + # Default is 20 (about once a week). + # + # type: uint64 + # env var: LOTUS_CHAINSTORE_SPLITSTORE_HOTSTOREFULLGCFREQUENCY + #HotStoreFullGCFrequency = 20 diff --git a/data/bob/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU b/data/bob/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU new file mode 100644 index 000000000..f7a10cceb --- /dev/null +++ b/data/bob/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU @@ -0,0 +1 @@ +{"Type":"jwt-hmac-secret","PrivateKey":"XySQypIONp3i5/hTlV01537sm6fdjxaYKsYVFMSAuwM="} \ No newline at end of file diff --git a/data/bob/keystore/NRUWE4BSOAWWQ33TOQ b/data/bob/keystore/NRUWE4BSOAWWQ33TOQ new file mode 100644 index 000000000..311666243 --- /dev/null +++ b/data/bob/keystore/NRUWE4BSOAWWQ33TOQ @@ -0,0 +1 @@ +{"Type":"libp2p-host","PrivateKey":"CAESQEuL5Q2fYZCNH+zSJ3FziYhP7w3PKkmWPUSapKCM9It2u+8En9WWVaKdOOkwJ1GPTsB6FtUU76isveFMiJAxVAU="} \ No newline at end of file diff --git a/data/bob/token b/data/bob/token new file mode 100644 index 000000000..dfc037d67 --- /dev/null +++ b/data/bob/token @@ -0,0 +1 @@ +eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJBbGxvdyI6WyJyZWFkIiwid3JpdGUiLCJzaWduIiwiYWRtaW4iXX0.5t2bfN0HkFcf8BMLbfuVOFA_8ojdbCQ0mSjwsPnVbf4 \ No newline at end of file diff --git a/data/charlie/config.toml b/data/charlie/config.toml new file mode 100644 index 000000000..67ad510b0 --- /dev/null +++ b/data/charlie/config.toml @@ -0,0 +1,185 @@ +[API] + # Binding address for the Lotus API + # + # type: string + # env var: LOTUS_API_LISTENADDRESS + ListenAddress = "/ip4/127.0.0.1/tcp/1236/http" + + # type: string + # env var: LOTUS_API_REMOTELISTENADDRESS + #RemoteListenAddress = "" + + # type: Duration + # env var: LOTUS_API_TIMEOUT + #Timeout = "30s" + + +[Backup] + # Note that in case of metadata corruption it might be much harder to recover + # your node if metadata log is disabled + # + # type: bool + # env var: LOTUS_BACKUP_DISABLEMETADATALOG + #DisableMetadataLog = false + + +[Libp2p] + # Binding address for the libp2p host - 0 means random port. + # Format: multiaddress; see https://multiformats.io/multiaddr/ + # + # type: []string + # env var: LOTUS_LIBP2P_LISTENADDRESSES + ListenAddresses = ["/ip4/0.0.0.0/tcp/3002", "/ip6/::/tcp/3002"] + + # Addresses to explicitally announce to other peers. If not specified, + # all interface addresses are announced + # Format: multiaddress + # + # type: []string + # env var: LOTUS_LIBP2P_ANNOUNCEADDRESSES + #AnnounceAddresses = [] + + # Addresses to not announce + # Format: multiaddress + # + # type: []string + # env var: LOTUS_LIBP2P_NOANNOUNCEADDRESSES + #NoAnnounceAddresses = [] + + # When not disabled (default), lotus asks NAT devices (e.g., routers), to + # open up an external port and forward it to the port lotus is running on. + # When this works (i.e., when your router supports NAT port forwarding), + # it makes the local lotus node accessible from the public internet + # + # type: bool + # env var: LOTUS_LIBP2P_DISABLENATPORTMAP + #DisableNatPortMap = false + + # ConnMgrLow is the number of connections that the basic connection manager + # will trim down to. + # + # type: uint + # env var: LOTUS_LIBP2P_CONNMGRLOW + #ConnMgrLow = 150 + + # ConnMgrHigh is the number of connections that, when exceeded, will trigger + # a connection GC operation. Note: protected/recently formed connections don't + # count towards this limit. + # + # type: uint + # env var: LOTUS_LIBP2P_CONNMGRHIGH + #ConnMgrHigh = 180 + + # ConnMgrGrace is a time duration that new connections are immune from being + # closed by the connection manager. + # + # type: Duration + # env var: LOTUS_LIBP2P_CONNMGRGRACE + #ConnMgrGrace = "20s" + + +[Pubsub] + # Run the node in bootstrap-node mode + # + # type: bool + # env var: LOTUS_PUBSUB_BOOTSTRAPPER + #Bootstrapper = false + + # type: string + # env var: LOTUS_PUBSUB_REMOTETRACER + #RemoteTracer = "" + + +[Client] + # type: bool + # env var: LOTUS_CLIENT_USEIPFS + #UseIpfs = false + + # type: bool + # env var: LOTUS_CLIENT_IPFSONLINEMODE + #IpfsOnlineMode = false + + # type: string + # env var: LOTUS_CLIENT_IPFSMADDR + #IpfsMAddr = "" + + # type: bool + # env var: LOTUS_CLIENT_IPFSUSEFORRETRIEVAL + #IpfsUseForRetrieval = false + + # The maximum number of simultaneous data transfers between the client + # and storage providers for storage deals + # + # type: uint64 + # env var: LOTUS_CLIENT_SIMULTANEOUSTRANSFERSFORSTORAGE + #SimultaneousTransfersForStorage = 20 + + # The maximum number of simultaneous data transfers between the client + # and storage providers for retrieval deals + # + # type: uint64 + # env var: LOTUS_CLIENT_SIMULTANEOUSTRANSFERSFORRETRIEVAL + #SimultaneousTransfersForRetrieval = 20 + + +[Wallet] + # type: string + # env var: LOTUS_WALLET_REMOTEBACKEND + #RemoteBackend = "" + + # type: bool + # env var: LOTUS_WALLET_ENABLELEDGER + #EnableLedger = false + + # type: bool + # env var: LOTUS_WALLET_DISABLELOCAL + #DisableLocal = false + + +[Fees] + # type: types.FIL + # env var: LOTUS_FEES_DEFAULTMAXFEE + #DefaultMaxFee = "0.07 FIL" + + +[Chainstore] + # type: bool + # env var: LOTUS_CHAINSTORE_ENABLESPLITSTORE + #EnableSplitstore = false + + [Chainstore.Splitstore] + # ColdStoreType specifies the type of the coldstore. + # It can be "universal" (default) or "discard" for discarding cold blocks. + # + # type: string + # env var: LOTUS_CHAINSTORE_SPLITSTORE_COLDSTORETYPE + #ColdStoreType = "universal" + + # HotStoreType specifies the type of the hotstore. + # Only currently supported value is "badger". + # + # type: string + # env var: LOTUS_CHAINSTORE_SPLITSTORE_HOTSTORETYPE + #HotStoreType = "badger" + + # MarkSetType specifies the type of the markset. + # It can be "map" (default) for in memory marking or "badger" for on-disk marking. + # + # type: string + # env var: LOTUS_CHAINSTORE_SPLITSTORE_MARKSETTYPE + #MarkSetType = "map" + + # HotStoreMessageRetention specifies the retention policy for messages, in finalities beyond + # the compaction boundary; default is 0. + # + # type: uint64 + # env var: LOTUS_CHAINSTORE_SPLITSTORE_HOTSTOREMESSAGERETENTION + #HotStoreMessageRetention = 0 + + # HotStoreFullGCFrequency specifies how often to perform a full (moving) GC on the hotstore. + # A value of 0 disables, while a value 1 will do full GC in every compaction. + # Default is 20 (about once a week). + # + # type: uint64 + # env var: LOTUS_CHAINSTORE_SPLITSTORE_HOTSTOREFULLGCFREQUENCY + #HotStoreFullGCFrequency = 20 diff --git a/data/charlie/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU b/data/charlie/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU new file mode 100644 index 000000000..fc0eb9641 --- /dev/null +++ b/data/charlie/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU @@ -0,0 +1 @@ +{"Type":"jwt-hmac-secret","PrivateKey":"3dGa2EutToPWz5hc5AMO7yQVQB9ElMuWDeTtq8yuHXg="} \ No newline at end of file diff --git a/data/charlie/keystore/NRUWE4BSOAWWQ33TOQ b/data/charlie/keystore/NRUWE4BSOAWWQ33TOQ new file mode 100644 index 000000000..1c53fd795 --- /dev/null +++ b/data/charlie/keystore/NRUWE4BSOAWWQ33TOQ @@ -0,0 +1 @@ +{"Type":"libp2p-host","PrivateKey":"CAESQPbXOriy+aEtHT9qZsfvsX6YFMGbw+sUk7Cyx1EOJm5GTSl6jqgrrFgtgPOBplufrDiRVVog4TunwoXI0YgQOSU="} \ No newline at end of file diff --git a/data/charlie/token b/data/charlie/token new file mode 100644 index 000000000..6c449da95 --- /dev/null +++ b/data/charlie/token @@ -0,0 +1 @@ +eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJBbGxvdyI6WyJyZWFkIiwid3JpdGUiLCJzaWduIiwiYWRtaW4iXX0.lIFY8AwZkqwCZ5Av1aGpHur2gf34kmxhD-U8YnKmLVA \ No newline at end of file diff --git a/go.mod b/go.mod index 65b8ba2b7..ba01fae2f 100644 --- a/go.mod +++ b/go.mod @@ -10,12 +10,15 @@ require ( github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee github.com/Kubuxu/imtui v0.0.0-20210401140320-41663d68d0fa github.com/StackExchange/wmi v1.2.1 // indirect + github.com/Zondax/multi-party-sig v0.6.0-alpha-2021-09-21.0.20211117140501-65990deeb804 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d github.com/alecthomas/jsonschema v0.0.0-20200530073317-71f438968921 + github.com/btcsuite/btcutil v1.0.3-0.20210929233259-9cdf59f60c51 github.com/buger/goterm v1.0.3 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e github.com/cockroachdb/pebble v0.0.0-20201001221639-879f3bfeef07 github.com/coreos/go-systemd/v22 v22.3.2 + github.com/cronokirby/safenum v0.29.0 // indirect github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e github.com/dgraph-io/badger/v2 v2.2007.2 github.com/docker/go-units v0.4.0 diff --git a/go.sum b/go.sum index 0651b2bf7..846f98314 100644 --- a/go.sum +++ b/go.sum @@ -82,6 +82,8 @@ github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9 github.com/Stebalien/go-bitfield v0.0.1 h1:X3kbSSPUaJK60wV2hjOPZwmpljr6VGCqdq4cBLhbQBo= github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI+XWrX9Wf2XH0s= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/Zondax/multi-party-sig v0.6.0-alpha-2021-09-21.0.20211117140501-65990deeb804 h1:zQrDkZ4qvHYKvqCJ2ljZ8VVSwHa1YC6nT8FFNQIahf0= +github.com/Zondax/multi-party-sig v0.6.0-alpha-2021-09-21.0.20211117140501-65990deeb804/go.mod h1:KOfSxMrl13ge7DX30LdWQyw4zrVzyZc9uykL77Q/TXc= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= @@ -144,6 +146,8 @@ github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+q github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= +github.com/btcsuite/btcutil v1.0.3-0.20210929233259-9cdf59f60c51 h1:6XGSs4BMDRlNR9k+tpr1g2S6ZfQhKQl/Xr276yAEfP0= +github.com/btcsuite/btcutil v1.0.3-0.20210929233259-9cdf59f60c51/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= @@ -223,6 +227,8 @@ github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 h1:HVTnpeuv github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cronokirby/safenum v0.29.0 h1:kf1/8vvN/yQjrZU3tR/vDb5OdIQp2uJ6WvPVbU61J+E= +github.com/cronokirby/safenum v0.29.0/go.mod h1:AWp82xwEqKcnrpJPXPa1m0gF/OY8dzgL17ubUBnVygA= github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0= github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis= github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY= @@ -235,6 +241,10 @@ github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQY github.com/davidlazar/go-crypto v0.0.0-20190912175916-7055855a373f/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= +github.com/decred/dcrd/chaincfg/chainhash v1.0.2/go.mod h1:BpbrGgrPTr3YJYRN3Bm+D9NuaFd+zGyNeIKgrhCXK60= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v3 v3.0.0 h1:sgNeV1VRMDzs6rzyPpxyM0jp317hnwiq58Filgag2xw= +github.com/decred/dcrd/dcrec/secp256k1/v3 v3.0.0/go.mod h1:J70FGZSbzsjecRTiTzER+3f1KZLNaXkuv+yeFTKoxM8= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e h1:lj77EKYUpYXTd8CD/+QMIf8b6OIOTsfEBSXiAzuEHTU= github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e/go.mod h1:3ZQK6DMPSz/QZ73jlWxBtUhNA8xZx7LzUFSq/OfP8vk= @@ -413,6 +423,8 @@ github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fxamacker/cbor/v2 v2.3.0 h1:aM45YGMctNakddNNAezPxDUpv38j44Abh+hifNuqXik= +github.com/fxamacker/cbor/v2 v2.3.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/gammazero/keymutex v0.0.0-20211002043844-c7ebad3e5479 h1:lCqfYOAqlMRixZ/t6MB7Khu1YSTrEE4GEIsiF0qNSdY= github.com/gammazero/keymutex v0.0.0-20211002043844-c7ebad3e5479/go.mod h1:qtzWCCLMisQUmVa4dvqHVgwfh4BP2YB7JxNDGXnsKrs= github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 h1:EzDjxMg43q1tA2c0MV3tNbaontnHLplHyFF6M5KiVP0= @@ -1652,6 +1664,7 @@ github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.21.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM= +github.com/rs/zerolog v1.23.0/go.mod h1:6c7hFfxPOy7TacJc4Fcdi24/J0NKYGzjG8FWRI916Qo= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -1837,6 +1850,8 @@ github.com/whyrusleeping/pubsub v0.0.0-20190708150250-92bcb0691325/go.mod h1:g7c github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee h1:lYbXeSvJi5zk5GLKVuid9TVjS9a0OmLIDKTfoZBL6Ow= github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg= github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/c-for-go v0.0.0-20201112171043-ea6dce5809cb h1:/7/dQyiKnxAOj9L69FhST7uMe17U015XPzX7cy+5ykM= github.com/xlab/c-for-go v0.0.0-20201112171043-ea6dce5809cb/go.mod h1:pbNsDSxn1ICiNn9Ct4ZGNrwzfkkwYbx/lw8VuyutFIg= @@ -1851,6 +1866,12 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= +github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/blake3 v0.2.0 h1:1SGx3IvKWFUU/xl+/7kjdcjjMcvVSm+3dMo/N42afC8= +github.com/zeebo/blake3 v0.2.0/go.mod h1:G9pM4qQwjRzF1/v7+vabMj/c5mWpGZ2Wzo3Eb4z0pb4= +github.com/zeebo/pcg v1.0.0 h1:dt+dx+HvX8g7Un32rY9XWoYnd0NmKmrIzpHF7qiTDj0= +github.com/zeebo/pcg v1.0.0/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8= github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= github.com/zondax/ledger-go v0.12.1 h1:hYRcyznPRJp+5mzF2sazTLP2nGvGjYDD2VzhHhFomLU= @@ -1968,6 +1989,7 @@ golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5 golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210915214749-c084706c2272 h1:3erb+vDS8lU1sxfDHF4/hhWyaXnhIaO+7RgL4fDZORA= golang.org/x/crypto v0.0.0-20210915214749-c084706c2272/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -2185,6 +2207,7 @@ golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200812155832-6a926be9bd1d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200926100807-9d91bd62050c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201014080544-cc95f250f6bc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2206,6 +2229,7 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210917161153-d61c044b1678 h1:J27LZFQBFoihqXoegpscI10HpjZ7B5WQLLKL2FZXQKw= golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= diff --git a/scripts/generate-bitcoin-blocks.sh b/scripts/generate-bitcoin-blocks.sh new file mode 100755 index 000000000..299976527 --- /dev/null +++ b/scripts/generate-bitcoin-blocks.sh @@ -0,0 +1,6 @@ +#! /bin/bash + +while sleep 10; do curl -u satoshi:amiens -X POST \ + 127.0.0.1:18443 \ + -d "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"generatetoaddress\", \"params\": [1, \"bcrt1qgp62tlj8hwd7lpp0thz0ujjvgxsjug5hr4l8xj\"]}" \ + -H 'Content-Type:application/json'; done \ No newline at end of file diff --git a/scripts/taproot.sh b/scripts/taproot.sh new file mode 100755 index 000000000..b98af788d --- /dev/null +++ b/scripts/taproot.sh @@ -0,0 +1,27 @@ +#! /bin/bash + +curl -u satoshi:amiens -X POST \ + 127.0.0.1:18443 \ + -d "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"createwallet\", \"params\": [\"wow\"]}" \ + -H 'Content-Type:application/json' + +ADDRESS=$(curl -u satoshi:amiens -X POST \ + 127.0.0.1:18443 \ + -d "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"getnewaddress\", \"params\": [\"wow\"]}" \ + -H 'Content-Type:application/json' | jq -r '.result') + +echo "$ADDRESS" + +curl -u satoshi:amiens -X POST \ + 127.0.0.1:18443 \ + -d "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"generatetoaddress\", \"params\": [150, \"$ADDRESS\"]}" \ + -H 'Content-Type:application/json' + +tmux \ + new-session 'EUDICO_PATH=$PWD/data/alice ./eudico delegated daemon --genesis=gen.gen; sleep infinity' \; \ + split-window -h 'EUDICO_PATH=$PWD/data/bob ./eudico delegated daemon --genesis=gen.gen; sleep infinity' \; \ + split-window 'EUDICO_PATH=$PWD/data/bob ./eudico wait-api; EUDICO_PATH=$PWD/data/bob ./eudico log set-level error; EUDICO_PATH=$PWD/data/bob ./eudico net connect /ip4/127.0.0.1/tcp/3000/p2p/12D3KooWMBbLLKTM9Voo89TXLd98w4MjkJUych6QvECptousGtR4; sleep 3' \; \ + split-window -h 'EUDICO_PATH=$PWD/data/charlie ./eudico delegated daemon --genesis=gen.gen; sleep infinity' \; \ + split-window 'EUDICO_PATH=$PWD/data/charlie ./eudico wait-api; EUDICO_PATH=$PWD/data/charlie ./eudico log set-level error; EUDICO_PATH=$PWD/data/charlie ./eudico net connect /ip4/127.0.0.1/tcp/3000/p2p/12D3KooWMBbLLKTM9Voo89TXLd98w4MjkJUych6QvECptousGtR4 /ip4/127.0.0.1/tcp/3001/p2p/12D3KooWNTyoBdMB9bpSkf7PVWR863ejGVPq9ssaaAipNvhPeQ4t; sleep 3' \; \ + select-pane -t 0 \; \ + split-window -v 'EUDICO_PATH=$PWD/data/alice ./eudico wait-api; EUDICO_PATH=$PWD/data/alice ./eudico log set-level error; EUDICO_PATH=$PWD/data/alice ./eudico wallet import --as-default --format=json-lotus kek.key; EUDICO_PATH=$PWD/data/alice ./eudico delegated miner; sleep infinity' \; \ No newline at end of file From 990aa141bebd1245821108f6e255cf01f4b9c0cf Mon Sep 17 00:00:00 2001 From: sleepy ramen Date: Tue, 30 Nov 2021 16:58:05 +0100 Subject: [PATCH 03/23] checkpointing working (#3) --- chain/checkpointing/constant.go | 3 ++ chain/checkpointing/sub.go | 56 +++++++++++++++++++++++++-------- chain/checkpointing/util.go | 11 ++++++- 3 files changed, 56 insertions(+), 14 deletions(-) create mode 100644 chain/checkpointing/constant.go diff --git a/chain/checkpointing/constant.go b/chain/checkpointing/constant.go new file mode 100644 index 000000000..3cc7c15a1 --- /dev/null +++ b/chain/checkpointing/constant.go @@ -0,0 +1,3 @@ +package checkpointing + +var FEE float64 = 0.01 diff --git a/chain/checkpointing/sub.go b/chain/checkpointing/sub.go index b247eca80..9baed8805 100644 --- a/chain/checkpointing/sub.go +++ b/chain/checkpointing/sub.go @@ -10,6 +10,7 @@ import ( "github.com/Zondax/multi-party-sig/pkg/party" "github.com/Zondax/multi-party-sig/pkg/protocol" + "github.com/Zondax/multi-party-sig/pkg/taproot" "github.com/Zondax/multi-party-sig/protocols/frost" "github.com/Zondax/multi-party-sig/protocols/frost/keygen" "github.com/filecoin-project/go-state-types/abi" @@ -255,6 +256,9 @@ func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, data []byte) { ids := c.formIDSlice(idsStrings) taprootAddress := PubkeyToTapprootAddress(c.pubkey) + pubkeyShort := GenCheckpointPublicKeyTaproot(c.config.PublicKey, data) + newTaprootAddress := PubkeyToTapprootAddress(pubkeyShort) + if c.ptxid == "" { taprootScript := GetTaprootScript(c.pubkey) success := AddTaprootScriptToWallet(taprootScript) @@ -271,34 +275,33 @@ func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, data []byte) { fmt.Println("Found precedent txid:", c.ptxid) } - //if idsStrings[0] == c.host.ID().String() { { - // The first participant create the message to sign - payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"createrawtransaction\", \"params\": [[{\"txid\":\"" + c.ptxid + "\",\"vout\": 0, \"sequence\": 4294967295}], [{\"" + taprootAddress + "\": \"50\"}, {\"data\": \"636964\"}]]}" + payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"gettxout\", \"params\": [\"" + c.ptxid + "\", 0]}" result := jsonRPC(payload) if result == nil { - panic("cant create new transaction") + panic("cant retrieve previous transaction") } + taprootTxOut := result["result"].(map[string]interface{}) + newValue := taprootTxOut["value"].(float64) - FEE - rawTransaction := result["result"].(string) - - payload = "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"gettxout\", \"params\": [\"" + c.ptxid + "\", 0]}" + scriptPubkey := taprootTxOut["scriptPubKey"].(map[string]interface{}) + scriptPubkeyBytes, _ := hex.DecodeString(scriptPubkey["hex"].(string)) + payload = "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"createrawtransaction\", \"params\": [[{\"txid\":\"" + c.ptxid + "\",\"vout\": 0, \"sequence\": 4294967295}], [{\"" + newTaprootAddress + "\": \"" + fmt.Sprintf("%.2f", newValue) + "\"}, {\"data\": \"" + hex.EncodeToString(data) + "\"}]]}" result = jsonRPC(payload) if result == nil { - panic("cant retrieve previous transaction") + panic("cant create new transaction") } - taprootTxOut := result["result"].(map[string]interface{}) - scriptPubkey := taprootTxOut["scriptPubKey"].(map[string]interface{}) - scriptPubkeyBytes, _ := hex.DecodeString(scriptPubkey["hex"].(string)) - var buf [8]byte - binary.LittleEndian.PutUint64(buf[:], uint64(taprootTxOut["value"].(float64)*100000000)) + rawTransaction := result["result"].(string) tx, err := hex.DecodeString(rawTransaction) if err != nil { panic(err) } + + var buf [8]byte + binary.LittleEndian.PutUint64(buf[:], uint64(taprootTxOut["value"].(float64)*100000000)) utxo := append(buf[:], []byte{34}...) utxo = append(utxo, scriptPubkeyBytes...) @@ -324,6 +327,33 @@ func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, data []byte) { log.Fatal("Not working neither") } fmt.Println("Result :", r) + + // if signing is a success we register the new value + merkleRoot := HashMerkleRoot(c.config.PublicKey, data) + c.tweakedValue = HashTweakedValue(c.config.PublicKey, merkleRoot) + c.pubkey = pubkeyShort + + if idsStrings[0] == c.host.ID().String() { + // Only first one broadcast the transaction ? + // Actually all participants can broadcast the transcation. It will be the same everywhere. + rawtx := PrepareWitnessRawTransaction(rawTransaction, r.(taproot.Signature)) + + payload = "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"sendrawtransaction\", \"params\": [\"" + rawtx + "\"]}" + result = jsonRPC(payload) + if result["error"] != nil { + fmt.Println(result) + panic("failed to broadcast transaction") + } + + fmt.Println(result) + + /* Need to keep this to build next one */ + newtxid := result["result"].(string) + + fmt.Println("New Txid:", newtxid) + c.ptxid = newtxid + } + } } diff --git a/chain/checkpointing/util.go b/chain/checkpointing/util.go index 81c91e8e7..a906fd157 100644 --- a/chain/checkpointing/util.go +++ b/chain/checkpointing/util.go @@ -38,6 +38,9 @@ func TaprootSignatureHash(tx []byte, utxo []byte, hash_type byte) ([]byte, error return nil, errors.New("only support SIGHASH_DEFAULT (0x00)") } + fmt.Println(hex.EncodeToString(tx)) + fmt.Println(hex.EncodeToString(utxo)) + var ss []byte ext_flag := 0x00 @@ -195,7 +198,6 @@ func WalletGetTxidFromAddress(taprootAddress string) (string, error) { list := result["result"].([]interface{}) for _, item := range list { item_map := item.(map[string]interface{}) - fmt.Println(item_map) if item_map["address"] == taprootAddress { txid := item_map["txid"].(string) return txid, nil @@ -210,6 +212,13 @@ func BitcoindPing() bool { return result != nil } +func PrepareWitnessRawTransaction(rawtx string, sig []byte) string { + wtx := rawtx[:4*2] + "00" + "01" + rawtx[4*2:len(rawtx)-4*2] + "01" + "40" + hex.EncodeToString(sig) + rawtx[len(rawtx)-4*2:] + fmt.Println("Raw transaction signed :", wtx) + + return wtx +} + func jsonRPC(payload string) map[string]interface{} { // ZONDAX TODO // This needs to be in a config file From 365a52ca93e9572a7dacebb72692e318644a29c9 Mon Sep 17 00:00:00 2001 From: sleepy ramen Date: Fri, 3 Dec 2021 13:58:44 +0100 Subject: [PATCH 04/23] Loading taproot configuration (#4) * Loading taproot configuration + correct configurations for Alice, Bob and Charlie * more robust --- .gitignore | 3 +- chain/checkpointing/sub.go | 350 +++++++++++++++++++++++------------- chain/checkpointing/util.go | 29 +++ data/alice/share.toml | 15 ++ data/bob/share.toml | 15 ++ data/charlie/share.toml | 15 ++ 6 files changed, 297 insertions(+), 130 deletions(-) create mode 100755 data/alice/share.toml create mode 100755 data/bob/share.toml create mode 100755 data/charlie/share.toml diff --git a/.gitignore b/.gitignore index e5be6b118..766de24ec 100644 --- a/.gitignore +++ b/.gitignore @@ -54,4 +54,5 @@ gen.gen data/*/* !data/*/keystore/ !data/*/config.toml -!data/*/token \ No newline at end of file +!data/*/token +!data/*/share.toml \ No newline at end of file diff --git a/chain/checkpointing/sub.go b/chain/checkpointing/sub.go index 9baed8805..edfafa0d8 100644 --- a/chain/checkpointing/sub.go +++ b/chain/checkpointing/sub.go @@ -4,10 +4,13 @@ import ( "context" "encoding/binary" "encoding/hex" + "errors" "fmt" "os" "sort" + "github.com/BurntSushi/toml" + "github.com/Zondax/multi-party-sig/pkg/math/curve" "github.com/Zondax/multi-party-sig/pkg/party" "github.com/Zondax/multi-party-sig/pkg/protocol" "github.com/Zondax/multi-party-sig/pkg/taproot" @@ -41,16 +44,14 @@ type CheckpointingSub struct { pubkey []byte // taproot config config *keygen.TaprootConfig - // If we have started the key generation - genkey bool + // new config generated + newconfig *keygen.TaprootConfig // Initiated init bool // Previous tx ptxid string // Tweaked value tweakedValue []byte - //checkpoint value - cp []byte } func NewCheckpointSub( @@ -69,19 +70,73 @@ func NewCheckpointSub( } // Load configTaproot - fmt.Println(os.Getenv("EUDICO_PATH")) - // Read file + content, err := os.ReadFile(os.Getenv("EUDICO_PATH") + "/share.toml") + if err != nil { + return nil, err + } + + var configTOML TaprootConfigTOML + _, err = toml.Decode(string(content), &configTOML) + if err != nil { + return nil, err + } + + privateSharePath, err := hex.DecodeString(configTOML.PrivateShare) + if err != nil { + return nil, err + } + + publickey, err := hex.DecodeString(configTOML.PublicKey) + if err != nil { + return nil, err + } + + var privateShare curve.Secp256k1Scalar + err = privateShare.UnmarshalBinary(privateSharePath) + if err != nil { + return nil, err + } + + verificationShares := make(map[party.ID]*curve.Secp256k1Point) + + fmt.Println(configTOML.VerificationShares) + + for key, vshare := range configTOML.VerificationShares { + + fmt.Println(key) + fmt.Println(vshare) + + var p curve.Secp256k1Point + pByte, err := hex.DecodeString(vshare.Share) + if err != nil { + return nil, err + } + err = p.UnmarshalBinary(pByte) + if err != nil { + return nil, err + } + verificationShares[party.ID(key)] = &p + } + + config := keygen.TaprootConfig{ + ID: party.ID(host.ID().String()), + Threshold: configTOML.Thershold, + PrivateShare: &privateShare, + PublicKey: publickey, + VerificationShares: verificationShares, + } return &CheckpointingSub{ - pubsub: pubsub, - topic: nil, - sub: nil, - host: host, - api: &api, - events: e, - genkey: false, - init: false, - ptxid: "", + pubsub: pubsub, + topic: nil, + sub: nil, + host: host, + api: &api, + events: e, + init: false, + ptxid: "", + config: &config, + newconfig: nil, }, nil } @@ -122,33 +177,7 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { } fmt.Println("Result :", r) - c.config = r.(*keygen.TaprootConfig) - - if !c.init { - cp := []byte("random data")[:] - pubkeyShort := GenCheckpointPublicKeyTaproot(c.config.PublicKey, cp) - c.pubkey = pubkeyShort - - if idsStrings[0] == c.host.ID().String() { - taprootAddress := PubkeyToTapprootAddress(c.pubkey) - - payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"sendtoaddress\", \"params\": [\"" + taprootAddress + "\", 50]}" - result := jsonRPC(payload) - fmt.Println(result) - if result == nil { - // Should probably not panic here - panic("Couldn't create first transaction") - } - - c.ptxid = result["result"].(string) - } - - // Save tweaked value - merkleRoot := HashMerkleRoot(c.config.PublicKey, cp) - c.tweakedValue = HashTweakedValue(c.config.PublicKey, merkleRoot) - - c.init = true - } + c.newconfig = r.(*keygen.TaprootConfig) return true, nil } @@ -177,36 +206,44 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { return false, nil, err } - // ZONDAX TODO: // If Power Actors list has changed start DKG - - // Only start when we have 3 peers - if len(c.topic.ListPeers()) < 2 { + if !c.init { + ts, err := c.api.ChainGetTipSetByHeight(ctx, 0, oldTs.Key()) + if err != nil { + panic(err) + } + data := ts.Cids()[0] + err = c.initiate(data.Bytes()) + if err != nil { + panic(err) + } return false, nil, nil } - if c.genkey { - fmt.Println(oldTipset.Height()) - // ZONDAX TODO - // Activate checkpointing every 5 blocks - if oldTipset.Height()%5 == 0 { - fmt.Println("Check point time") - - if c.init && c.config != nil { - fmt.Println("We have a taproot config") + // ZONDAX TODO + // Activate checkpointing every 20 blocks + fmt.Println("Height:", oldTipset.Height()) + if oldTipset.Height()%20 == 0 { + fmt.Println("Check point time") - data := oldTipset.Cids()[0] + // Initiation and config should be happening at start + if c.init && c.config != nil { + fmt.Println("We have a taproot config") - c.CreateCheckpoint(ctx, data.Bytes()) - } + data := oldTipset.Cids()[0] + c.CreateCheckpoint(ctx, data.Bytes()) } - return false, nil, nil } - c.genkey = true + // Generating new config every 50 blocks + if oldTipset.Height()%50 == 0 { + fmt.Println("Generate new config") + + return true, nil, nil + } - return true, nil, nil + return false, nil, nil } err := c.events.StateChanged(checkFunc, changeHandler, revertHandler, 5, 76587687658765876, match) @@ -216,8 +253,6 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { } func (c *CheckpointingSub) Start(ctx context.Context) { - c.listenCheckpointEvents(ctx) - topic, err := c.pubsub.Join("keygen") if err != nil { panic(err) @@ -230,6 +265,8 @@ func (c *CheckpointingSub) Start(ctx context.Context) { panic(err) } c.sub = sub + + c.listenCheckpointEvents(ctx) } func (c *CheckpointingSub) LoopHandler(ctx context.Context, h protocol.Handler, network *Network) { @@ -251,15 +288,24 @@ func (c *CheckpointingSub) LoopHandler(ctx context.Context, h protocol.Handler, } func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, data []byte) { + fmt.Println("Create Checkpoint!!!") + idsStrings := c.orderParticipantsList() fmt.Println("Participants list :", idsStrings) + fmt.Println("Precedent tx", c.ptxid) ids := c.formIDSlice(idsStrings) taprootAddress := PubkeyToTapprootAddress(c.pubkey) - pubkeyShort := GenCheckpointPublicKeyTaproot(c.config.PublicKey, data) + pubkey := c.config.PublicKey + if c.newconfig != nil { + pubkey = c.newconfig.PublicKey + } + + pubkeyShort := GenCheckpointPublicKeyTaproot(pubkey, data) newTaprootAddress := PubkeyToTapprootAddress(pubkeyShort) if c.ptxid == "" { + fmt.Println("Missing precedent txid") taprootScript := GetTaprootScript(c.pubkey) success := AddTaprootScriptToWallet(taprootScript) if !success { @@ -275,85 +321,94 @@ func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, data []byte) { fmt.Println("Found precedent txid:", c.ptxid) } - { - payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"gettxout\", \"params\": [\"" + c.ptxid + "\", 0]}" - result := jsonRPC(payload) - if result == nil { - panic("cant retrieve previous transaction") - } - taprootTxOut := result["result"].(map[string]interface{}) - newValue := taprootTxOut["value"].(float64) - FEE + /*payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"gettxout\", \"params\": [\"" + c.ptxid + "\", 0]}" + result := jsonRPC(payload) + if result == nil { + panic("cant retrieve previous transaction") + } + taprootTxOut := result["result"].(map[string]interface{}) + newValue := taprootTxOut["value"].(float64) - FEE - scriptPubkey := taprootTxOut["scriptPubKey"].(map[string]interface{}) - scriptPubkeyBytes, _ := hex.DecodeString(scriptPubkey["hex"].(string)) + scriptPubkey := taprootTxOut["scriptPubKey"].(map[string]interface{}) + scriptPubkeyBytes, _ := hex.DecodeString(scriptPubkey["hex"].(string))*/ - payload = "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"createrawtransaction\", \"params\": [[{\"txid\":\"" + c.ptxid + "\",\"vout\": 0, \"sequence\": 4294967295}], [{\"" + newTaprootAddress + "\": \"" + fmt.Sprintf("%.2f", newValue) + "\"}, {\"data\": \"" + hex.EncodeToString(data) + "\"}]]}" - result = jsonRPC(payload) - if result == nil { - panic("cant create new transaction") - } + value, scriptPubkeyBytes := GetTxOut(c.ptxid, 0) - rawTransaction := result["result"].(string) + if scriptPubkeyBytes[0] != 0x51 { + fmt.Println("Wrong txout") + value, scriptPubkeyBytes = GetTxOut(c.ptxid, 1) + } + newValue := value - FEE - tx, err := hex.DecodeString(rawTransaction) - if err != nil { - panic(err) - } + payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"createrawtransaction\", \"params\": [[{\"txid\":\"" + c.ptxid + "\",\"vout\": 0, \"sequence\": 4294967295}], [{\"" + newTaprootAddress + "\": \"" + fmt.Sprintf("%.2f", newValue) + "\"}, {\"data\": \"" + hex.EncodeToString(data) + "\"}]]}" + result := jsonRPC(payload) + if result == nil { + panic("cant create new transaction") + } - var buf [8]byte - binary.LittleEndian.PutUint64(buf[:], uint64(taprootTxOut["value"].(float64)*100000000)) - utxo := append(buf[:], []byte{34}...) - utxo = append(utxo, scriptPubkeyBytes...) + rawTransaction := result["result"].(string) - hashedTx, err := TaprootSignatureHash(tx, utxo, 0x00) - if err != nil { - panic(err) - } + tx, err := hex.DecodeString(rawTransaction) + if err != nil { + panic(err) + } - /* - * Orchestrate the signing message - */ + var buf [8]byte + binary.LittleEndian.PutUint64(buf[:], uint64(value*100000000)) + utxo := append(buf[:], []byte{34}...) + utxo = append(utxo, scriptPubkeyBytes...) - f := frost.SignTaprootWithTweak(c.config, ids, hashedTx[:], c.tweakedValue[:]) - n := NewNetwork(ids, c.sub, c.topic) - handler, err := protocol.NewMultiHandler(f, []byte{1, 2, 3}) - if err != nil { - panic(err) - } - c.LoopHandler(ctx, handler, n) - r, err := handler.Result() - if err != nil { - fmt.Println(err) - log.Fatal("Not working neither") - } - fmt.Println("Result :", r) + hashedTx, err := TaprootSignatureHash(tx, utxo, 0x00) + if err != nil { + panic(err) + } - // if signing is a success we register the new value - merkleRoot := HashMerkleRoot(c.config.PublicKey, data) - c.tweakedValue = HashTweakedValue(c.config.PublicKey, merkleRoot) - c.pubkey = pubkeyShort - - if idsStrings[0] == c.host.ID().String() { - // Only first one broadcast the transaction ? - // Actually all participants can broadcast the transcation. It will be the same everywhere. - rawtx := PrepareWitnessRawTransaction(rawTransaction, r.(taproot.Signature)) - - payload = "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"sendrawtransaction\", \"params\": [\"" + rawtx + "\"]}" - result = jsonRPC(payload) - if result["error"] != nil { - fmt.Println(result) - panic("failed to broadcast transaction") - } + /* + * Orchestrate the signing message + */ - fmt.Println(result) + f := frost.SignTaprootWithTweak(c.config, ids, hashedTx[:], c.tweakedValue[:]) + n := NewNetwork(ids, c.sub, c.topic) + handler, err := protocol.NewMultiHandler(f, []byte{1, 2, 3}) + if err != nil { + panic(err) + } + c.LoopHandler(ctx, handler, n) + r, err := handler.Result() + if err != nil { + fmt.Println(err) + log.Fatal("Not working neither") + } + fmt.Println("Result :", r) + + // if signing is a success we register the new value + merkleRoot := HashMerkleRoot(pubkey, data) + c.tweakedValue = HashTweakedValue(pubkey, merkleRoot) + c.pubkey = pubkeyShort + // If new config used + if c.newconfig != nil { + c.config = c.newconfig + c.newconfig = nil + } - /* Need to keep this to build next one */ - newtxid := result["result"].(string) + if idsStrings[0] == c.host.ID().String() { + // Only first one broadcast the transaction ? + // Actually all participants can broadcast the transcation. It will be the same everywhere. + rawtx := PrepareWitnessRawTransaction(rawTransaction, r.(taproot.Signature)) - fmt.Println("New Txid:", newtxid) - c.ptxid = newtxid + payload = "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"sendrawtransaction\", \"params\": [\"" + rawtx + "\"]}" + result = jsonRPC(payload) + if result["error"] != nil { + fmt.Println(result) + panic("failed to broadcast transaction") } + fmt.Println(result) + + /* Need to keep this to build next one */ + newtxid := result["result"].(string) + fmt.Println("New Txid:", newtxid) + c.ptxid = newtxid } } @@ -384,6 +439,43 @@ func (c *CheckpointingSub) formIDSlice(ids []string) party.IDSlice { return idsSlice } +func (c *CheckpointingSub) prefundTaproot() error { + taprootAddress := PubkeyToTapprootAddress(c.pubkey) + + payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"sendtoaddress\", \"params\": [\"" + taprootAddress + "\", 50]}" + result := jsonRPC(payload) + fmt.Println(result) + if result == nil { + // Should probably not panic here + return errors.New("couldn't create first transaction") + } + c.ptxid = result["result"].(string) + + return nil +} + +func (c *CheckpointingSub) initiate(data []byte) error { + pubkeyShort := GenCheckpointPublicKeyTaproot(c.config.PublicKey, data) + c.pubkey = pubkeyShort + + idsStrings := c.orderParticipantsList() + + if idsStrings[0] == c.host.ID().String() { + err := c.prefundTaproot() + if err != nil { + return err + } + } + + // Save tweaked value + merkleRoot := HashMerkleRoot(c.config.PublicKey, data) + c.tweakedValue = HashTweakedValue(c.config.PublicKey, merkleRoot) + + c.init = true + + return nil +} + func BuildCheckpointingSub(mctx helpers.MetricsCtx, lc fx.Lifecycle, c *CheckpointingSub) { ctx := helpers.LifecycleCtx(mctx, lc) diff --git a/chain/checkpointing/util.go b/chain/checkpointing/util.go index a906fd157..253458977 100644 --- a/chain/checkpointing/util.go +++ b/chain/checkpointing/util.go @@ -8,6 +8,7 @@ import ( "fmt" "io/ioutil" "net/http" + "strconv" "strings" "github.com/Zondax/multi-party-sig/pkg/math/curve" @@ -15,6 +16,17 @@ import ( "github.com/cronokirby/safenum" ) +type VerificationShare struct { + Share string +} + +type TaprootConfigTOML struct { + Thershold int + PrivateShare string + PublicKey string + VerificationShares map[string]VerificationShare +} + func TaggedHash(tag string, datas ...[]byte) []byte { tagSum := sha256.Sum256([]byte(tag)) @@ -219,6 +231,23 @@ func PrepareWitnessRawTransaction(rawtx string, sig []byte) string { return wtx } +func ParseUnspentTxOut(utxo []byte) (amount, script []byte) { + return utxo[0:8], utxo[9:] +} + +func GetTxOut(txid string, index int) (float64, []byte) { + payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"gettxout\", \"params\": [\"" + txid + "\", " + strconv.Itoa(index) + "]}" + result := jsonRPC(payload) + if result == nil { + panic("cant retrieve previous transaction") + } + taprootTxOut := result["result"].(map[string]interface{}) + scriptPubkey := taprootTxOut["scriptPubKey"].(map[string]interface{}) + scriptPubkeyBytes, _ := hex.DecodeString(scriptPubkey["hex"].(string)) + + return taprootTxOut["value"].(float64), scriptPubkeyBytes +} + func jsonRPC(payload string) map[string]interface{} { // ZONDAX TODO // This needs to be in a config file diff --git a/data/alice/share.toml b/data/alice/share.toml new file mode 100755 index 000000000..6395c5e0c --- /dev/null +++ b/data/alice/share.toml @@ -0,0 +1,15 @@ +Treshold=2 +PrivateShare="0fac81c461206928dcddcebe8c77343ddb3adba0f74f47dcf2d8d0461796df40" +PublicKey="66a554b8af6719851a936b0afc29dc59c3678f0e3f0b7bb081c57c5b77ad48ff" + +[VerificationShares] + +[VerificationShares.12D3KooWMBbLLKTM9Voo89TXLd98w4MjkJUych6QvECptousGtR4] +Share="02de7b1922283afa65adbacf74e543c0841fd84d948911d668d10835df07f5c203" + +[VerificationShares.12D3KooWNTyoBdMB9bpSkf7PVWR863ejGVPq9ssaaAipNvhPeQ4t] +Share="03dda30f606203bfa25da11375eaac64f915401b8bfb8067b0241d467a1cdab681" + +[VerificationShares.12D3KooWF1aFCGUtsGEaqNks3QADLUDZxW7ot7jZPSoDiAFKJuM6] +Share="034b172e82079d742c84c9ed0a6e4fc2d9172edae9507d81624446754f9eed709c" + diff --git a/data/bob/share.toml b/data/bob/share.toml new file mode 100755 index 000000000..8f69161f1 --- /dev/null +++ b/data/bob/share.toml @@ -0,0 +1,15 @@ +Treshold=2 +PrivateShare="93810b585c063419dd04555b37b7ba822b6309fcac8a6ff3ac5ef793139f4b1b" +PublicKey="66a554b8af6719851a936b0afc29dc59c3678f0e3f0b7bb081c57c5b77ad48ff" + +[VerificationShares] + +[VerificationShares.12D3KooWF1aFCGUtsGEaqNks3QADLUDZxW7ot7jZPSoDiAFKJuM6] +Share="034b172e82079d742c84c9ed0a6e4fc2d9172edae9507d81624446754f9eed709c" + +[VerificationShares.12D3KooWMBbLLKTM9Voo89TXLd98w4MjkJUych6QvECptousGtR4] +Share="02de7b1922283afa65adbacf74e543c0841fd84d948911d668d10835df07f5c203" + +[VerificationShares.12D3KooWNTyoBdMB9bpSkf7PVWR863ejGVPq9ssaaAipNvhPeQ4t] +Share="03dda30f606203bfa25da11375eaac64f915401b8bfb8067b0241d467a1cdab681" + diff --git a/data/charlie/share.toml b/data/charlie/share.toml new file mode 100755 index 000000000..da06fb57d --- /dev/null +++ b/data/charlie/share.toml @@ -0,0 +1,15 @@ +Treshold=2 +PrivateShare="68297d9dab2c0ba0f508eb30626eaca737951a70d7132dc7c7efaae3dd96db38" +PublicKey="66a554b8af6719851a936b0afc29dc59c3678f0e3f0b7bb081c57c5b77ad48ff" + +[VerificationShares] + +[VerificationShares.12D3KooWMBbLLKTM9Voo89TXLd98w4MjkJUych6QvECptousGtR4] +Share="02de7b1922283afa65adbacf74e543c0841fd84d948911d668d10835df07f5c203" + +[VerificationShares.12D3KooWNTyoBdMB9bpSkf7PVWR863ejGVPq9ssaaAipNvhPeQ4t] +Share="03dda30f606203bfa25da11375eaac64f915401b8bfb8067b0241d467a1cdab681" + +[VerificationShares.12D3KooWF1aFCGUtsGEaqNks3QADLUDZxW7ot7jZPSoDiAFKJuM6] +Share="034b172e82079d742c84c9ed0a6e4fc2d9172edae9507d81624446754f9eed709c" + From 842c8dbdffe561813d9b90f42a3f9b32370ff532 Mon Sep 17 00:00:00 2001 From: sleepy ramen Date: Fri, 3 Dec 2021 18:32:28 +0100 Subject: [PATCH 05/23] mocked power actor (#5) --- chain/checkpointing/sub.go | 12 +- chain/consensus/actors/actors.go | 2 + chain/consensus/actors/mpower/cbor_gen.go | 1079 +++++++++++++++++ chain/consensus/actors/mpower/policy.go | 12 + chain/consensus/actors/mpower/power_actor.go | 570 +++++++++ chain/consensus/actors/mpower/power_state.go | 344 ++++++ chain/consensus/actors/registry/registry.go | 2 + .../hierarchical/actors/subnet/genesis.go | 31 + 8 files changed, 2048 insertions(+), 4 deletions(-) create mode 100644 chain/consensus/actors/mpower/cbor_gen.go create mode 100644 chain/consensus/actors/mpower/policy.go create mode 100644 chain/consensus/actors/mpower/power_actor.go create mode 100644 chain/consensus/actors/mpower/power_state.go diff --git a/chain/checkpointing/sub.go b/chain/checkpointing/sub.go index edfafa0d8..4741747c8 100644 --- a/chain/checkpointing/sub.go +++ b/chain/checkpointing/sub.go @@ -17,6 +17,7 @@ import ( "github.com/Zondax/multi-party-sig/protocols/frost" "github.com/Zondax/multi-party-sig/protocols/frost/keygen" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/chain/consensus/actors/mpower" "github.com/filecoin-project/lotus/chain/events" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node/impl" @@ -190,15 +191,18 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { /* NOT WORKING WITHOUT THE MOCKED POWER ACTOR - oldAct, err := c.api.StateGetActor(ctx, mpoweractor.MpowerActorAddr, oldTs.Key()) - if err != nil { - return false, nil, err - } + newAct, err := c.api.StateGetActor(ctx, mpoweractor.MpowerActorAddr, newTs.Key()) if err != nil { return false, nil, err } */ + oldAct, err := c.api.StateGetActor(ctx, mpower.PowerActorAddr, oldTs.Key()) + if err != nil { + return false, nil, err + } + + fmt.Println(oldAct) // This is not actually what we want. Just here to check. oldTipset, err := c.api.ChainGetTipSet(ctx, oldTs.Key()) diff --git a/chain/consensus/actors/actors.go b/chain/consensus/actors/actors.go index f5dde3655..6b30833d5 100644 --- a/chain/consensus/actors/actors.go +++ b/chain/consensus/actors/actors.go @@ -9,6 +9,7 @@ var ( SplitActorCodeID cid.Cid SubnetCoordActorCodeID cid.Cid SubnetActorCodeID cid.Cid + MpowerActorCodeID cid.Cid ) var builtinActors map[cid.Cid]*actorInfo @@ -25,6 +26,7 @@ func init() { &SplitActorCodeID: {name: "example/0/split"}, &SubnetCoordActorCodeID: {name: "hierarchical/0/sca"}, &SubnetActorCodeID: {name: "hierarchical/0/subnet"}, + &MpowerActorCodeID: {name: "deleg/0/mpower"}, } { c, err := builder.Sum([]byte(info.name)) if err != nil { diff --git a/chain/consensus/actors/mpower/cbor_gen.go b/chain/consensus/actors/mpower/cbor_gen.go new file mode 100644 index 000000000..26c65811a --- /dev/null +++ b/chain/consensus/actors/mpower/cbor_gen.go @@ -0,0 +1,1079 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package mpower + +import ( + "fmt" + "io" + + address "github.com/filecoin-project/go-address" + abi "github.com/filecoin-project/go-state-types/abi" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +var lengthBufState = []byte{143} + +func (t *State) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufState); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.TotalRawBytePower (big.Int) (struct) + if err := t.TotalRawBytePower.MarshalCBOR(w); err != nil { + return err + } + + // t.TotalBytesCommitted (big.Int) (struct) + if err := t.TotalBytesCommitted.MarshalCBOR(w); err != nil { + return err + } + + // t.TotalQualityAdjPower (big.Int) (struct) + if err := t.TotalQualityAdjPower.MarshalCBOR(w); err != nil { + return err + } + + // t.TotalQABytesCommitted (big.Int) (struct) + if err := t.TotalQABytesCommitted.MarshalCBOR(w); err != nil { + return err + } + + // t.TotalPledgeCollateral (big.Int) (struct) + if err := t.TotalPledgeCollateral.MarshalCBOR(w); err != nil { + return err + } + + // t.ThisEpochRawBytePower (big.Int) (struct) + if err := t.ThisEpochRawBytePower.MarshalCBOR(w); err != nil { + return err + } + + // t.ThisEpochQualityAdjPower (big.Int) (struct) + if err := t.ThisEpochQualityAdjPower.MarshalCBOR(w); err != nil { + return err + } + + // t.ThisEpochPledgeCollateral (big.Int) (struct) + if err := t.ThisEpochPledgeCollateral.MarshalCBOR(w); err != nil { + return err + } + + // t.ThisEpochQAPowerSmoothed (smoothing.FilterEstimate) (struct) + if err := t.ThisEpochQAPowerSmoothed.MarshalCBOR(w); err != nil { + return err + } + + // t.MinerCount (int64) (int64) + if t.MinerCount >= 0 { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.MinerCount)); err != nil { + return err + } + } else { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.MinerCount-1)); err != nil { + return err + } + } + + // t.MinerAboveMinPowerCount (int64) (int64) + if t.MinerAboveMinPowerCount >= 0 { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.MinerAboveMinPowerCount)); err != nil { + return err + } + } else { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.MinerAboveMinPowerCount-1)); err != nil { + return err + } + } + + // t.CronEventQueue (cid.Cid) (struct) + + if err := cbg.WriteCidBuf(scratch, w, t.CronEventQueue); err != nil { + return xerrors.Errorf("failed to write cid field t.CronEventQueue: %w", err) + } + + // t.FirstCronEpoch (abi.ChainEpoch) (int64) + if t.FirstCronEpoch >= 0 { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.FirstCronEpoch)); err != nil { + return err + } + } else { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.FirstCronEpoch-1)); err != nil { + return err + } + } + + // t.Claims (cid.Cid) (struct) + + if err := cbg.WriteCidBuf(scratch, w, t.Claims); err != nil { + return xerrors.Errorf("failed to write cid field t.Claims: %w", err) + } + + // t.ProofValidationBatch (cid.Cid) (struct) + + if t.ProofValidationBatch == nil { + if _, err := w.Write(cbg.CborNull); err != nil { + return err + } + } else { + if err := cbg.WriteCidBuf(scratch, w, *t.ProofValidationBatch); err != nil { + return xerrors.Errorf("failed to write cid field t.ProofValidationBatch: %w", err) + } + } + + return nil +} + +func (t *State) UnmarshalCBOR(r io.Reader) error { + *t = State{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 15 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.TotalRawBytePower (big.Int) (struct) + + { + + if err := t.TotalRawBytePower.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.TotalRawBytePower: %w", err) + } + + } + // t.TotalBytesCommitted (big.Int) (struct) + + { + + if err := t.TotalBytesCommitted.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.TotalBytesCommitted: %w", err) + } + + } + // t.TotalQualityAdjPower (big.Int) (struct) + + { + + if err := t.TotalQualityAdjPower.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.TotalQualityAdjPower: %w", err) + } + + } + // t.TotalQABytesCommitted (big.Int) (struct) + + { + + if err := t.TotalQABytesCommitted.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.TotalQABytesCommitted: %w", err) + } + + } + // t.TotalPledgeCollateral (big.Int) (struct) + + { + + if err := t.TotalPledgeCollateral.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.TotalPledgeCollateral: %w", err) + } + + } + // t.ThisEpochRawBytePower (big.Int) (struct) + + { + + if err := t.ThisEpochRawBytePower.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.ThisEpochRawBytePower: %w", err) + } + + } + // t.ThisEpochQualityAdjPower (big.Int) (struct) + + { + + if err := t.ThisEpochQualityAdjPower.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.ThisEpochQualityAdjPower: %w", err) + } + + } + // t.ThisEpochPledgeCollateral (big.Int) (struct) + + { + + if err := t.ThisEpochPledgeCollateral.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.ThisEpochPledgeCollateral: %w", err) + } + + } + // t.ThisEpochQAPowerSmoothed (smoothing.FilterEstimate) (struct) + + { + + if err := t.ThisEpochQAPowerSmoothed.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.ThisEpochQAPowerSmoothed: %w", err) + } + + } + // t.MinerCount (int64) (int64) + { + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.MinerCount = int64(extraI) + } + // t.MinerAboveMinPowerCount (int64) (int64) + { + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.MinerAboveMinPowerCount = int64(extraI) + } + // t.CronEventQueue (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.CronEventQueue: %w", err) + } + + t.CronEventQueue = c + + } + // t.FirstCronEpoch (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.FirstCronEpoch = abi.ChainEpoch(extraI) + } + // t.Claims (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.Claims: %w", err) + } + + t.Claims = c + + } + // t.ProofValidationBatch (cid.Cid) (struct) + + { + + b, err := br.ReadByte() + if err != nil { + return err + } + if b != cbg.CborNull[0] { + if err := br.UnreadByte(); err != nil { + return err + } + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.ProofValidationBatch: %w", err) + } + + t.ProofValidationBatch = &c + } + + } + return nil +} + +var lengthBufClaim = []byte{131} + +func (t *Claim) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufClaim); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.WindowPoStProofType (abi.RegisteredPoStProof) (int64) + if t.WindowPoStProofType >= 0 { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.WindowPoStProofType)); err != nil { + return err + } + } else { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.WindowPoStProofType-1)); err != nil { + return err + } + } + + // t.RawBytePower (big.Int) (struct) + if err := t.RawBytePower.MarshalCBOR(w); err != nil { + return err + } + + // t.QualityAdjPower (big.Int) (struct) + if err := t.QualityAdjPower.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *Claim) UnmarshalCBOR(r io.Reader) error { + *t = Claim{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 3 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.WindowPoStProofType (abi.RegisteredPoStProof) (int64) + { + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.WindowPoStProofType = abi.RegisteredPoStProof(extraI) + } + // t.RawBytePower (big.Int) (struct) + + { + + if err := t.RawBytePower.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.RawBytePower: %w", err) + } + + } + // t.QualityAdjPower (big.Int) (struct) + + { + + if err := t.QualityAdjPower.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.QualityAdjPower: %w", err) + } + + } + return nil +} + +var lengthBufCronEvent = []byte{130} + +func (t *CronEvent) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufCronEvent); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.MinerAddr (address.Address) (struct) + if err := t.MinerAddr.MarshalCBOR(w); err != nil { + return err + } + + // t.CallbackPayload ([]uint8) (slice) + if len(t.CallbackPayload) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.CallbackPayload was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajByteString, uint64(len(t.CallbackPayload))); err != nil { + return err + } + + if _, err := w.Write(t.CallbackPayload[:]); err != nil { + return err + } + return nil +} + +func (t *CronEvent) UnmarshalCBOR(r io.Reader) error { + *t = CronEvent{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.MinerAddr (address.Address) (struct) + + { + + if err := t.MinerAddr.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.MinerAddr: %w", err) + } + + } + // t.CallbackPayload ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.CallbackPayload: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + + if extra > 0 { + t.CallbackPayload = make([]uint8, extra) + } + + if _, err := io.ReadFull(br, t.CallbackPayload[:]); err != nil { + return err + } + return nil +} + +var lengthBufCreateMinerParams = []byte{133} + +func (t *CreateMinerParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufCreateMinerParams); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.Owner (address.Address) (struct) + if err := t.Owner.MarshalCBOR(w); err != nil { + return err + } + + // t.Worker (address.Address) (struct) + if err := t.Worker.MarshalCBOR(w); err != nil { + return err + } + + // t.WindowPoStProofType (abi.RegisteredPoStProof) (int64) + if t.WindowPoStProofType >= 0 { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.WindowPoStProofType)); err != nil { + return err + } + } else { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.WindowPoStProofType-1)); err != nil { + return err + } + } + + // t.Peer ([]uint8) (slice) + if len(t.Peer) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Peer was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajByteString, uint64(len(t.Peer))); err != nil { + return err + } + + if _, err := w.Write(t.Peer[:]); err != nil { + return err + } + + // t.Multiaddrs ([][]uint8) (slice) + if len(t.Multiaddrs) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Multiaddrs was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.Multiaddrs))); err != nil { + return err + } + for _, v := range t.Multiaddrs { + if len(v) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field v was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajByteString, uint64(len(v))); err != nil { + return err + } + + if _, err := w.Write(v[:]); err != nil { + return err + } + } + return nil +} + +func (t *CreateMinerParams) UnmarshalCBOR(r io.Reader) error { + *t = CreateMinerParams{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 5 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Owner (address.Address) (struct) + + { + + if err := t.Owner.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Owner: %w", err) + } + + } + // t.Worker (address.Address) (struct) + + { + + if err := t.Worker.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Worker: %w", err) + } + + } + // t.WindowPoStProofType (abi.RegisteredPoStProof) (int64) + { + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.WindowPoStProofType = abi.RegisteredPoStProof(extraI) + } + // t.Peer ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Peer: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + + if extra > 0 { + t.Peer = make([]uint8, extra) + } + + if _, err := io.ReadFull(br, t.Peer[:]); err != nil { + return err + } + // t.Multiaddrs ([][]uint8) (slice) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Multiaddrs: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Multiaddrs = make([][]uint8, extra) + } + + for i := 0; i < int(extra); i++ { + { + var maj byte + var extra uint64 + var err error + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Multiaddrs[i]: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + + if extra > 0 { + t.Multiaddrs[i] = make([]uint8, extra) + } + + if _, err := io.ReadFull(br, t.Multiaddrs[i][:]); err != nil { + return err + } + } + } + + return nil +} + +var lengthBufCurrentTotalPowerReturn = []byte{132} + +func (t *CurrentTotalPowerReturn) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufCurrentTotalPowerReturn); err != nil { + return err + } + + // t.RawBytePower (big.Int) (struct) + if err := t.RawBytePower.MarshalCBOR(w); err != nil { + return err + } + + // t.QualityAdjPower (big.Int) (struct) + if err := t.QualityAdjPower.MarshalCBOR(w); err != nil { + return err + } + + // t.PledgeCollateral (big.Int) (struct) + if err := t.PledgeCollateral.MarshalCBOR(w); err != nil { + return err + } + + // t.QualityAdjPowerSmoothed (smoothing.FilterEstimate) (struct) + if err := t.QualityAdjPowerSmoothed.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *CurrentTotalPowerReturn) UnmarshalCBOR(r io.Reader) error { + *t = CurrentTotalPowerReturn{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 4 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.RawBytePower (big.Int) (struct) + + { + + if err := t.RawBytePower.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.RawBytePower: %w", err) + } + + } + // t.QualityAdjPower (big.Int) (struct) + + { + + if err := t.QualityAdjPower.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.QualityAdjPower: %w", err) + } + + } + // t.PledgeCollateral (big.Int) (struct) + + { + + if err := t.PledgeCollateral.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.PledgeCollateral: %w", err) + } + + } + // t.QualityAdjPowerSmoothed (smoothing.FilterEstimate) (struct) + + { + + if err := t.QualityAdjPowerSmoothed.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.QualityAdjPowerSmoothed: %w", err) + } + + } + return nil +} + +var lengthBufMinerConstructorParams = []byte{134} + +func (t *MinerConstructorParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufMinerConstructorParams); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.OwnerAddr (address.Address) (struct) + if err := t.OwnerAddr.MarshalCBOR(w); err != nil { + return err + } + + // t.WorkerAddr (address.Address) (struct) + if err := t.WorkerAddr.MarshalCBOR(w); err != nil { + return err + } + + // t.ControlAddrs ([]address.Address) (slice) + if len(t.ControlAddrs) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.ControlAddrs was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.ControlAddrs))); err != nil { + return err + } + for _, v := range t.ControlAddrs { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + + // t.WindowPoStProofType (abi.RegisteredPoStProof) (int64) + if t.WindowPoStProofType >= 0 { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.WindowPoStProofType)); err != nil { + return err + } + } else { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.WindowPoStProofType-1)); err != nil { + return err + } + } + + // t.PeerId ([]uint8) (slice) + if len(t.PeerId) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.PeerId was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajByteString, uint64(len(t.PeerId))); err != nil { + return err + } + + if _, err := w.Write(t.PeerId[:]); err != nil { + return err + } + + // t.Multiaddrs ([][]uint8) (slice) + if len(t.Multiaddrs) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Multiaddrs was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.Multiaddrs))); err != nil { + return err + } + for _, v := range t.Multiaddrs { + if len(v) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field v was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajByteString, uint64(len(v))); err != nil { + return err + } + + if _, err := w.Write(v[:]); err != nil { + return err + } + } + return nil +} + +func (t *MinerConstructorParams) UnmarshalCBOR(r io.Reader) error { + *t = MinerConstructorParams{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 6 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.OwnerAddr (address.Address) (struct) + + { + + if err := t.OwnerAddr.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.OwnerAddr: %w", err) + } + + } + // t.WorkerAddr (address.Address) (struct) + + { + + if err := t.WorkerAddr.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.WorkerAddr: %w", err) + } + + } + // t.ControlAddrs ([]address.Address) (slice) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.ControlAddrs: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.ControlAddrs = make([]address.Address, extra) + } + + for i := 0; i < int(extra); i++ { + + var v address.Address + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.ControlAddrs[i] = v + } + + // t.WindowPoStProofType (abi.RegisteredPoStProof) (int64) + { + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.WindowPoStProofType = abi.RegisteredPoStProof(extraI) + } + // t.PeerId ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.PeerId: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + + if extra > 0 { + t.PeerId = make([]uint8, extra) + } + + if _, err := io.ReadFull(br, t.PeerId[:]); err != nil { + return err + } + // t.Multiaddrs ([][]uint8) (slice) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Multiaddrs: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Multiaddrs = make([][]uint8, extra) + } + + for i := 0; i < int(extra); i++ { + { + var maj byte + var extra uint64 + var err error + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Multiaddrs[i]: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + + if extra > 0 { + t.Multiaddrs[i] = make([]uint8, extra) + } + + if _, err := io.ReadFull(br, t.Multiaddrs[i][:]); err != nil { + return err + } + } + } + + return nil +} diff --git a/chain/consensus/actors/mpower/policy.go b/chain/consensus/actors/mpower/policy.go new file mode 100644 index 000000000..909da4e4b --- /dev/null +++ b/chain/consensus/actors/mpower/policy.go @@ -0,0 +1,12 @@ +package mpower + +// The number of miners that must meet the consensus minimum miner power before that minimum power is enforced +// as a condition of leader election. +// This ensures a network still functions before any miners reach that threshold. +const ConsensusMinerMinMiners = 4 // PARAM_SPEC + +// Maximum number of prove-commits each miner can submit in one epoch. +// +// This limits the number of proof partitions we may need to load in the cron call path. +// Onboarding 1EiB/year requires at least 32 prove-commits per epoch. +const MaxMinerProveCommitsPerEpoch = 200 // PARAM_SPEC diff --git a/chain/consensus/actors/mpower/power_actor.go b/chain/consensus/actors/mpower/power_actor.go new file mode 100644 index 000000000..604fac97a --- /dev/null +++ b/chain/consensus/actors/mpower/power_actor.go @@ -0,0 +1,570 @@ +package mpower + +import ( + "bytes" + + addr "github.com/filecoin-project/go-address" + address "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/cbor" + "github.com/filecoin-project/go-state-types/exitcode" + rtt "github.com/filecoin-project/go-state-types/rt" + xerrors "golang.org/x/xerrors" + + power0 "github.com/filecoin-project/specs-actors/actors/builtin/power" + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/specs-actors/v6/actors/builtin" + initact "github.com/filecoin-project/specs-actors/v6/actors/builtin/init" + "github.com/filecoin-project/specs-actors/v6/actors/builtin/reward" + "github.com/filecoin-project/specs-actors/v6/actors/runtime" + "github.com/filecoin-project/specs-actors/v6/actors/runtime/proof" + "github.com/filecoin-project/specs-actors/v6/actors/util/adt" + "github.com/filecoin-project/specs-actors/v6/actors/util/smoothing" +) + +type Runtime = runtime.Runtime + +type SectorTermination int64 + +const ( + ErrTooManyProveCommits = exitcode.FirstActorSpecificExitCode + iota +) + +type Actor struct{} + +var PowerActorAddr = func() address.Address { + a, err := address.NewIDAddress(65) + if err != nil { + panic(err) + } + return a +}() + +func (a Actor) Exports() []interface{} { + return []interface{}{ + builtin.MethodConstructor: a.Constructor, + 2: a.CreateMiner, + 3: a.UpdateClaimedPower, + 4: a.EnrollCronEvent, + 5: a.OnEpochTickEnd, + 6: a.UpdatePledgeTotal, + 7: nil, // deprecated + 8: a.SubmitPoRepForBulkVerify, + 9: a.CurrentTotalPower, + } +} + +func (a Actor) Code() cid.Cid { + return builtin.StoragePowerActorCodeID +} + +func (a Actor) IsSingleton() bool { + return true +} + +func (a Actor) State() cbor.Er { + return new(State) +} + +var _ runtime.VMActor = Actor{} + +// Storage miner actor constructor params are defined here so the power actor can send them to the init actor +// to instantiate miners. +// Changed since v2: +// - Seal proof type replaced with PoSt proof type +type MinerConstructorParams struct { + OwnerAddr addr.Address + WorkerAddr addr.Address + ControlAddrs []addr.Address + WindowPoStProofType abi.RegisteredPoStProof + PeerId abi.PeerID + Multiaddrs []abi.Multiaddrs +} + +//////////////////////////////////////////////////////////////////////////////// +// Actor methods +//////////////////////////////////////////////////////////////////////////////// + +func (a Actor) Constructor(rt Runtime, _ *abi.EmptyValue) *abi.EmptyValue { + rt.ValidateImmediateCallerIs(builtin.SystemActorAddr) + + st, err := ConstructState(adt.AsStore(rt)) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to construct state") + rt.StateCreate(st) + return nil +} + +// Changed since v2: +// - Seal proof type replaced with PoSt proof types +type CreateMinerParams struct { + Owner addr.Address + Worker addr.Address + WindowPoStProofType abi.RegisteredPoStProof + Peer abi.PeerID + Multiaddrs []abi.Multiaddrs +} + +//type CreateMinerReturn struct { +// IDAddress addr.Address // The canonical ID-based address for the actor. +// RobustAddress addr.Address // A more expensive but re-org-safe address for the newly created actor. +//} +type CreateMinerReturn = power0.CreateMinerReturn + +func (a Actor) CreateMiner(rt Runtime, params *CreateMinerParams) *CreateMinerReturn { + rt.ValidateImmediateCallerType(builtin.CallerTypesSignable...) + + ctorParams := MinerConstructorParams{ + OwnerAddr: params.Owner, + WorkerAddr: params.Worker, + WindowPoStProofType: params.WindowPoStProofType, + PeerId: params.Peer, + Multiaddrs: params.Multiaddrs, + } + ctorParamBuf := new(bytes.Buffer) + err := ctorParams.MarshalCBOR(ctorParamBuf) + builtin.RequireNoErr(rt, err, exitcode.ErrSerialization, "failed to serialize miner constructor params %v", ctorParams) + + var addresses initact.ExecReturn + code := rt.Send( + builtin.InitActorAddr, + builtin.MethodsInit.Exec, + &initact.ExecParams{ + CodeCID: builtin.StorageMinerActorCodeID, + ConstructorParams: ctorParamBuf.Bytes(), + }, + rt.ValueReceived(), // Pass on any value to the new actor. + &addresses, + ) + builtin.RequireSuccess(rt, code, "failed to init new actor") + + var st State + rt.StateTransaction(&st, func() { + claims, err := adt.AsMap(adt.AsStore(rt), st.Claims, builtin.DefaultHamtBitwidth) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load claims") + + err = setClaim(claims, addresses.IDAddress, &Claim{params.WindowPoStProofType, abi.NewStoragePower(0), abi.NewStoragePower(0)}) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to put power in claimed table while creating miner") + + st.MinerCount += 1 + + // Ensure new claim updates all power stats + err = st.updateStatsForNewMiner(params.WindowPoStProofType) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed update power stats for new miner %v", addresses.IDAddress) + + st.Claims, err = claims.Root() + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to flush claims") + }) + return &CreateMinerReturn{ + IDAddress: addresses.IDAddress, + RobustAddress: addresses.RobustAddress, + } +} + +//type UpdateClaimedPowerParams struct { +// RawByteDelta abi.StoragePower +// QualityAdjustedDelta abi.StoragePower +//} +type UpdateClaimedPowerParams = power0.UpdateClaimedPowerParams + +// Adds or removes claimed power for the calling actor. +// May only be invoked by a miner actor. +func (a Actor) UpdateClaimedPower(rt Runtime, params *UpdateClaimedPowerParams) *abi.EmptyValue { + rt.ValidateImmediateCallerAcceptAny() + minerAddr := rt.Caller() + var st State + rt.StateTransaction(&st, func() { + claims, err := adt.AsMap(adt.AsStore(rt), st.Claims, builtin.DefaultHamtBitwidth) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load claims") + + err = st.addToClaim(claims, minerAddr, params.RawByteDelta, params.QualityAdjustedDelta) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to update power raw %s, qa %s", params.RawByteDelta, params.QualityAdjustedDelta) + + st.Claims, err = claims.Root() + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to flush claims") + }) + return nil +} + +//type EnrollCronEventParams struct { +// EventEpoch abi.ChainEpoch +// Payload []byte +//} +type EnrollCronEventParams = power0.EnrollCronEventParams + +func (a Actor) EnrollCronEvent(rt Runtime, params *EnrollCronEventParams) *abi.EmptyValue { + rt.ValidateImmediateCallerType(builtin.StorageMinerActorCodeID) + minerAddr := rt.Caller() + minerEvent := CronEvent{ + MinerAddr: minerAddr, + CallbackPayload: params.Payload, + } + + // Ensure it is not possible to enter a large negative number which would cause problems in cron processing. + if params.EventEpoch < 0 { + rt.Abortf(exitcode.ErrIllegalArgument, "cron event epoch %d cannot be less than zero", params.EventEpoch) + } + + var st State + rt.StateTransaction(&st, func() { + events, err := adt.AsMultimap(adt.AsStore(rt), st.CronEventQueue, CronQueueHamtBitwidth, CronQueueAmtBitwidth) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load cron events") + + err = st.appendCronEvent(events, params.EventEpoch, &minerEvent) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to enroll cron event") + + st.CronEventQueue, err = events.Root() + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to flush cron events") + }) + return nil +} + +// Called by Cron. +func (a Actor) OnEpochTickEnd(rt Runtime, _ *abi.EmptyValue) *abi.EmptyValue { + rt.ValidateImmediateCallerIs(builtin.CronActorAddr) + + var rewret reward.ThisEpochRewardReturn + rewretcode := rt.Send(builtin.RewardActorAddr, builtin.MethodsReward.ThisEpochReward, nil, big.Zero(), &rewret) + builtin.RequireSuccess(rt, rewretcode, "failed to check epoch baseline power") + + if err := a.processBatchProofVerifies(rt, rewret); err != nil { + rt.Log(rtt.ERROR, "unexpected error processing batch proof verifies: %s. Skipping all verification for epoch %d", err, rt.CurrEpoch()) + } + a.processDeferredCronEvents(rt, rewret) + + var st State + rt.StateTransaction(&st, func() { + // update next epoch's power and pledge values + // this must come before the next epoch's rewards are calculated + // so that next epoch reward reflects power added this epoch + rawBytePower, qaPower := CurrentTotalPower(&st) + st.ThisEpochPledgeCollateral = st.TotalPledgeCollateral + st.ThisEpochQualityAdjPower = qaPower + st.ThisEpochRawBytePower = rawBytePower + // we can now assume delta is one since cron is invoked on every epoch. + st.updateSmoothedEstimate(abi.ChainEpoch(1)) + }) + + // update network KPI in RewardActor + code := rt.Send( + builtin.RewardActorAddr, + builtin.MethodsReward.UpdateNetworkKPI, + &st.ThisEpochRawBytePower, + abi.NewTokenAmount(0), + &builtin.Discard{}, + ) + builtin.RequireSuccess(rt, code, "failed to update network KPI with Reward Actor") + + return nil +} + +func (a Actor) UpdatePledgeTotal(rt Runtime, pledgeDelta *abi.TokenAmount) *abi.EmptyValue { + rt.ValidateImmediateCallerType(builtin.StorageMinerActorCodeID) + var st State + rt.StateTransaction(&st, func() { + validateMinerHasClaim(rt, st, rt.Caller()) + st.addPledgeTotal(*pledgeDelta) + builtin.RequireState(rt, st.TotalPledgeCollateral.GreaterThanEqual(big.Zero()), "negative total pledge collateral %v", st.TotalPledgeCollateral) + }) + return nil +} + +// GasOnSubmitVerifySeal is amount of gas charged for SubmitPoRepForBulkVerify +// This number is empirically determined +const GasOnSubmitVerifySeal = 34721049 + +func (a Actor) SubmitPoRepForBulkVerify(rt Runtime, sealInfo *proof.SealVerifyInfo) *abi.EmptyValue { + rt.ValidateImmediateCallerType(builtin.StorageMinerActorCodeID) + + minerAddr := rt.Caller() + + var st State + rt.StateTransaction(&st, func() { + validateMinerHasClaim(rt, st, minerAddr) + + store := adt.AsStore(rt) + var mmap *adt.Multimap + var err error + if st.ProofValidationBatch == nil { + mmap, err = adt.MakeEmptyMultimap(store, builtin.DefaultHamtBitwidth, ProofValidationBatchAmtBitwidth) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to create empty proof validation set") + rt.Log(rtt.DEBUG, "ProofValidationBatch created") + } else { + mmap, err = adt.AsMultimap(adt.AsStore(rt), *st.ProofValidationBatch, builtin.DefaultHamtBitwidth, ProofValidationBatchAmtBitwidth) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load proof batch set") + } + + arr, found, err := mmap.Get(abi.AddrKey(minerAddr)) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to get get seal verify infos at addr %s", minerAddr) + if found && arr.Length() >= MaxMinerProveCommitsPerEpoch { + rt.Abortf(ErrTooManyProveCommits, "miner %s attempting to prove commit over %d sectors in epoch", minerAddr, MaxMinerProveCommitsPerEpoch) + } + + err = mmap.Add(abi.AddrKey(minerAddr), sealInfo) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to insert proof into batch") + + mmrc, err := mmap.Root() + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to flush proof batch") + + rt.ChargeGas("OnSubmitVerifySeal", GasOnSubmitVerifySeal, 0) + st.ProofValidationBatch = &mmrc + }) + + return nil +} + +// Changed since v0: +// - QualityAdjPowerSmoothed is not a pointer +type CurrentTotalPowerReturn struct { + RawBytePower abi.StoragePower + QualityAdjPower abi.StoragePower + PledgeCollateral abi.TokenAmount + QualityAdjPowerSmoothed smoothing.FilterEstimate +} + +// Returns the total power and pledge recorded by the power actor. +// The returned values are frozen during the cron tick before this epoch +// so that this method returns consistent values while processing all messages +// of an epoch. +func (a Actor) CurrentTotalPower(rt Runtime, _ *abi.EmptyValue) *CurrentTotalPowerReturn { + rt.ValidateImmediateCallerAcceptAny() + var st State + rt.StateReadonly(&st) + + return &CurrentTotalPowerReturn{ + RawBytePower: st.ThisEpochRawBytePower, + QualityAdjPower: st.ThisEpochQualityAdjPower, + PledgeCollateral: st.ThisEpochPledgeCollateral, + QualityAdjPowerSmoothed: st.ThisEpochQAPowerSmoothed, + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Method utility functions +//////////////////////////////////////////////////////////////////////////////// + +func validateMinerHasClaim(rt Runtime, st State, minerAddr addr.Address) { + claims, err := adt.AsMap(adt.AsStore(rt), st.Claims, builtin.DefaultHamtBitwidth) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load claims") + + found, err := claims.Has(abi.AddrKey(minerAddr)) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to look up claim") + if !found { + rt.Abortf(exitcode.ErrForbidden, "unknown miner %s forbidden to interact with power actor", minerAddr) + } +} + +func (a Actor) processBatchProofVerifies(rt Runtime, rewret reward.ThisEpochRewardReturn) error { + var st State + + var miners []addr.Address + verifies := make(map[addr.Address][]proof.SealVerifyInfo) + + var stErr error + rt.StateTransaction(&st, func() { + store := adt.AsStore(rt) + if st.ProofValidationBatch == nil { + rt.Log(rtt.DEBUG, "ProofValidationBatch was nil, quitting verification") + return + } + mmap, err := adt.AsMultimap(store, *st.ProofValidationBatch, builtin.DefaultHamtBitwidth, ProofValidationBatchAmtBitwidth) + if err != nil { + stErr = xerrors.Errorf("failed to load proofs validation batch: %w", err) + return + } + + claims, err := adt.AsMap(adt.AsStore(rt), st.Claims, builtin.DefaultHamtBitwidth) + if err != nil { + stErr = xerrors.Errorf("failed to load claims: %w", err) + return + } + + err = mmap.ForAll(func(k string, arr *adt.Array) error { + a, err := addr.NewFromBytes([]byte(k)) + if err != nil { + return xerrors.Errorf("failed to parse address key: %w", err) + } + + // refuse to process proofs for miner with no claim + found, err := claims.Has(abi.AddrKey(a)) + if err != nil { + return xerrors.Errorf("failed to look up claim: %w", err) + } + if !found { + rt.Log(rtt.WARN, "skipping batch verifies for unknown miner %s", a) + return nil + } + + miners = append(miners, a) + + var infos []proof.SealVerifyInfo + var svi proof.SealVerifyInfo + err = arr.ForEach(&svi, func(i int64) error { + infos = append(infos, svi) + return nil + }) + if err != nil { + return xerrors.Errorf("failed to iterate over proof verify array for miner %s: %w", a, err) + } + + verifies[a] = infos + return nil + }) + // Do not return immediately, all runs that get this far should wipe the ProofValidationBatchQueue. + // If we leave the validation batch then in the case of a repeating state error the queue + // will quickly fill up and repeated traversals will start ballooning cron execution time. + if err != nil { + stErr = xerrors.Errorf("failed to iterate proof batch: %w", err) + } + st.ProofValidationBatch = nil + }) + if stErr != nil { + return stErr + } + + res, err := rt.BatchVerifySeals(verifies) + if err != nil { + return xerrors.Errorf("failed to batch verify: %w", err) + } + + for _, m := range miners { + vres, ok := res[m] + if !ok { + return xerrors.Errorf("batch verify seals syscall implemented incorrectly, result not found for miner: %s", m) + } + + verifs := verifies[m] + + seen := map[abi.SectorNumber]struct{}{} + var successful []abi.SectorNumber + for i, r := range vres { + if r { + snum := verifs[i].SectorID.Number + + if _, exists := seen[snum]; exists { + // filter-out duplicates + rt.Log(rtt.INFO, "skipped over a duplicate proof") + continue + } + + seen[snum] = struct{}{} + successful = append(successful, snum) + } else { + rt.Log(rtt.INFO, "a proof failed from miner %s", m) + } + } + + if len(successful) > 0 { + code := rt.Send( + m, + builtin.MethodsMiner.ConfirmSectorProofsValid, + &builtin.ConfirmSectorProofsParams{ + Sectors: successful, + RewardSmoothed: rewret.ThisEpochRewardSmoothed, + RewardBaselinePower: rewret.ThisEpochBaselinePower, + QualityAdjPowerSmoothed: st.ThisEpochQAPowerSmoothed}, + abi.NewTokenAmount(0), + &builtin.Discard{}, + ) + if code.IsError() { + rt.Log(rtt.ERROR, + "failed to confirm sector proof validity to %s, error code %d", + m, code) + } + } + } + return nil +} + +func (a Actor) processDeferredCronEvents(rt Runtime, rewret reward.ThisEpochRewardReturn) { + rtEpoch := rt.CurrEpoch() + + var cronEvents []CronEvent + var st State + rt.StateTransaction(&st, func() { + events, err := adt.AsMultimap(adt.AsStore(rt), st.CronEventQueue, CronQueueHamtBitwidth, CronQueueAmtBitwidth) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load cron events") + + claims, err := adt.AsMap(adt.AsStore(rt), st.Claims, builtin.DefaultHamtBitwidth) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load claims") + + for epoch := st.FirstCronEpoch; epoch <= rtEpoch; epoch++ { + epochEvents, err := loadCronEvents(events, epoch) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load cron events at %v", epoch) + + for _, evt := range epochEvents { + // refuse to process proofs for miner with no claim + found, err := claims.Has(abi.AddrKey(evt.MinerAddr)) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to look up claim") + if !found { + rt.Log(rtt.WARN, "skipping cron event for unknown miner %v", evt.MinerAddr) + continue + } + cronEvents = append(cronEvents, evt) + } + + if len(epochEvents) > 0 { + err = events.RemoveAll(epochKey(epoch)) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to clear cron events at %v", epoch) + } else { + rt.Log(rtt.DEBUG, "no epoch events were loaded") + } + } + + st.FirstCronEpoch = rtEpoch + 1 + + st.CronEventQueue, err = events.Root() + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to flush events") + }) + failedMinerCrons := make([]addr.Address, 0) + + for _, event := range cronEvents { + + params := builtin.DeferredCronEventParams{ + EventPayload: event.CallbackPayload, + RewardSmoothed: rewret.ThisEpochRewardSmoothed, + QualityAdjPowerSmoothed: st.ThisEpochQAPowerSmoothed, + } + + code := rt.Send( + event.MinerAddr, + builtin.MethodsMiner.OnDeferredCronEvent, + ¶ms, + abi.NewTokenAmount(0), + &builtin.Discard{}, + ) + // If a callback fails, this actor continues to invoke other callbacks + // and persists state removing the failed event from the event queue. It won't be tried again. + // Failures are unexpected here but will result in removal of miner power as a defensive measure. + if code != exitcode.Ok { + rt.Log(rtt.ERROR, "OnDeferredCronEvent failed for miner %s: exitcode %d", event.MinerAddr, code) + failedMinerCrons = append(failedMinerCrons, event.MinerAddr) + } + } + + if len(failedMinerCrons) > 0 { + rt.StateTransaction(&st, func() { + claims, err := adt.AsMap(adt.AsStore(rt), st.Claims, builtin.DefaultHamtBitwidth) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load claims") + + // Remove miner claim and leave miner frozen + for _, minerAddr := range failedMinerCrons { + found, err := st.deleteClaim(claims, minerAddr) + if err != nil { + rt.Log(rtt.ERROR, "failed to delete claim for miner %s after failing OnDeferredCronEvent: %s", minerAddr, err) + continue + } else if !found { + rt.Log(rtt.ERROR, "can't find claim for miner %s after failing OnDeferredCronEvent: %s", minerAddr, err) + continue + } + + // Decrement miner count to keep stats consistent. + st.MinerCount-- + } + + st.Claims, err = claims.Root() + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to flush claims") + }) + } +} diff --git a/chain/consensus/actors/mpower/power_state.go b/chain/consensus/actors/mpower/power_state.go new file mode 100644 index 000000000..c934c77c5 --- /dev/null +++ b/chain/consensus/actors/mpower/power_state.go @@ -0,0 +1,344 @@ +package mpower + +import ( + "fmt" + "reflect" + + addr "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/exitcode" + cid "github.com/ipfs/go-cid" + "golang.org/x/xerrors" + + "github.com/filecoin-project/specs-actors/v6/actors/builtin" + "github.com/filecoin-project/specs-actors/v6/actors/util/adt" + "github.com/filecoin-project/specs-actors/v6/actors/util/smoothing" +) + +// genesis power in bytes = 750,000 GiB +var InitialQAPowerEstimatePosition = big.Mul(big.NewInt(750_000), big.NewInt(1<<30)) + +// max chain throughput in bytes per epoch = 120 ProveCommits / epoch = 3,840 GiB +var InitialQAPowerEstimateVelocity = big.Mul(big.NewInt(3_840), big.NewInt(1<<30)) + +// Bitwidth of CronEventQueue HAMT determined empirically from mutation +// patterns and projections of mainnet data. +const CronQueueHamtBitwidth = 6 + +// Bitwidth of CronEventQueue AMT determined empirically from mutation +// patterns and projections of mainnet data. +const CronQueueAmtBitwidth = 6 + +// Bitwidth of ProofValidationBatch AMT determined empirically from mutation +// pattersn and projections of mainnet data. +const ProofValidationBatchAmtBitwidth = 4 + +type State struct { + TotalRawBytePower abi.StoragePower + // TotalBytesCommitted includes claims from miners below min power threshold + TotalBytesCommitted abi.StoragePower + TotalQualityAdjPower abi.StoragePower + // TotalQABytesCommitted includes claims from miners below min power threshold + TotalQABytesCommitted abi.StoragePower + TotalPledgeCollateral abi.TokenAmount + + // These fields are set once per epoch in the previous cron tick and used + // for consistent values across a single epoch's state transition. + ThisEpochRawBytePower abi.StoragePower + ThisEpochQualityAdjPower abi.StoragePower + ThisEpochPledgeCollateral abi.TokenAmount + ThisEpochQAPowerSmoothed smoothing.FilterEstimate + + MinerCount int64 + // Number of miners having proven the minimum consensus power. + MinerAboveMinPowerCount int64 + + // A queue of events to be triggered by cron, indexed by epoch. + CronEventQueue cid.Cid // Multimap, (HAMT[ChainEpoch]AMT[CronEvent]) + + // First epoch in which a cron task may be stored. + // Cron will iterate every epoch between this and the current epoch inclusively to find tasks to execute. + FirstCronEpoch abi.ChainEpoch + + // Claimed power for each miner. + Claims cid.Cid // Map, HAMT[address]Claim + + ProofValidationBatch *cid.Cid // Multimap, (HAMT[Address]AMT[SealVerifyInfo]) +} + +type Claim struct { + // Miner's proof type used to determine minimum miner size + WindowPoStProofType abi.RegisteredPoStProof + + // Sum of raw byte power for a miner's sectors. + RawBytePower abi.StoragePower + + // Sum of quality adjusted power for a miner's sectors. + QualityAdjPower abi.StoragePower +} + +type CronEvent struct { + MinerAddr addr.Address + CallbackPayload []byte +} + +func ConstructState(store adt.Store) (*State, error) { + emptyClaimsMapCid, err := adt.StoreEmptyMap(store, builtin.DefaultHamtBitwidth) + if err != nil { + return nil, xerrors.Errorf("failed to create empty map: %w", err) + } + emptyCronQueueMMapCid, err := adt.StoreEmptyMultimap(store, CronQueueHamtBitwidth, CronQueueAmtBitwidth) + if err != nil { + return nil, xerrors.Errorf("failed to create empty multimap: %w", err) + } + + return &State{ + TotalRawBytePower: abi.NewStoragePower(0), + TotalBytesCommitted: abi.NewStoragePower(0), + TotalQualityAdjPower: abi.NewStoragePower(0), + TotalQABytesCommitted: abi.NewStoragePower(0), + TotalPledgeCollateral: abi.NewTokenAmount(0), + ThisEpochRawBytePower: abi.NewStoragePower(0), + ThisEpochQualityAdjPower: abi.NewStoragePower(0), + ThisEpochPledgeCollateral: abi.NewTokenAmount(0), + ThisEpochQAPowerSmoothed: smoothing.NewEstimate(InitialQAPowerEstimatePosition, InitialQAPowerEstimateVelocity), + FirstCronEpoch: 0, + CronEventQueue: emptyCronQueueMMapCid, + Claims: emptyClaimsMapCid, + MinerCount: 0, + MinerAboveMinPowerCount: 0, + }, nil +} + +// MinerNominalPowerMeetsConsensusMinimum is used to validate Election PoSt +// winners outside the chain state. If the miner has over a threshold of power +// the miner meets the minimum. If the network is a below a threshold of +// miners and has power > zero the miner meets the minimum. +func (st *State) MinerNominalPowerMeetsConsensusMinimum(s adt.Store, miner addr.Address) (bool, error) { //nolint:deadcode,unused + claims, err := adt.AsMap(s, st.Claims, builtin.DefaultHamtBitwidth) + if err != nil { + return false, xerrors.Errorf("failed to load claims: %w", err) + } + + claim, ok, err := getClaim(claims, miner) + if err != nil { + return false, err + } + if !ok { + return false, xerrors.Errorf("no claim for actor %w", miner) + } + + minerNominalPower := claim.RawBytePower + minerMinPower, err := builtin.ConsensusMinerMinPower(claim.WindowPoStProofType) + if err != nil { + return false, xerrors.Errorf("could not get miner min power from proof type: %w", err) + } + + // if miner is larger than min power requirement, we're set + if minerNominalPower.GreaterThanEqual(minerMinPower) { + return true, nil + } + + // otherwise, if ConsensusMinerMinMiners miners meet min power requirement, return false + if st.MinerAboveMinPowerCount >= ConsensusMinerMinMiners { + return false, nil + } + + // If fewer than ConsensusMinerMinMiners over threshold miner can win a block with non-zero power + return minerNominalPower.GreaterThan(abi.NewStoragePower(0)), nil +} + +// Parameters may be negative to subtract. +func (st *State) AddToClaim(s adt.Store, miner addr.Address, power abi.StoragePower, qapower abi.StoragePower) error { + claims, err := adt.AsMap(s, st.Claims, builtin.DefaultHamtBitwidth) + if err != nil { + return xerrors.Errorf("failed to load claims: %w", err) + } + + if err := st.addToClaim(claims, miner, power, qapower); err != nil { + return xerrors.Errorf("failed to add claim: %w", err) + } + + st.Claims, err = claims.Root() + if err != nil { + return xerrors.Errorf("failed to flush claims: %w", err) + } + + return nil +} + +func (st *State) GetClaim(s adt.Store, a addr.Address) (*Claim, bool, error) { + claims, err := adt.AsMap(s, st.Claims, builtin.DefaultHamtBitwidth) + if err != nil { + return nil, false, xerrors.Errorf("failed to load claims: %w", err) + } + return getClaim(claims, a) +} + +func (st *State) addToClaim(claims *adt.Map, miner addr.Address, power abi.StoragePower, qapower abi.StoragePower) error { + oldClaim, ok, err := getClaim(claims, miner) + if err != nil { + return fmt.Errorf("failed to get claim: %w", err) + } + if !ok { + return exitcode.ErrNotFound.Wrapf("no claim for actor %v", miner) + } + + // TotalBytes always update directly + st.TotalQABytesCommitted = big.Add(st.TotalQABytesCommitted, qapower) + st.TotalBytesCommitted = big.Add(st.TotalBytesCommitted, power) + + newClaim := Claim{ + WindowPoStProofType: oldClaim.WindowPoStProofType, + RawBytePower: big.Add(oldClaim.RawBytePower, power), + QualityAdjPower: big.Add(oldClaim.QualityAdjPower, qapower), + } + + minPower, err := builtin.ConsensusMinerMinPower(oldClaim.WindowPoStProofType) + if err != nil { + return fmt.Errorf("could not get consensus miner min power: %w", err) + } + + prevBelow := oldClaim.RawBytePower.LessThan(minPower) + stillBelow := newClaim.RawBytePower.LessThan(minPower) + + if prevBelow && !stillBelow { + // just passed min miner size + st.MinerAboveMinPowerCount++ + st.TotalQualityAdjPower = big.Add(st.TotalQualityAdjPower, newClaim.QualityAdjPower) + st.TotalRawBytePower = big.Add(st.TotalRawBytePower, newClaim.RawBytePower) + } else if !prevBelow && stillBelow { + // just went below min miner size + st.MinerAboveMinPowerCount-- + st.TotalQualityAdjPower = big.Sub(st.TotalQualityAdjPower, oldClaim.QualityAdjPower) + st.TotalRawBytePower = big.Sub(st.TotalRawBytePower, oldClaim.RawBytePower) + } else if !prevBelow && !stillBelow { + // Was above the threshold, still above + st.TotalQualityAdjPower = big.Add(st.TotalQualityAdjPower, qapower) + st.TotalRawBytePower = big.Add(st.TotalRawBytePower, power) + } + + if newClaim.RawBytePower.LessThan(big.Zero()) { + return xerrors.Errorf("negative claimed raw byte power: %v", newClaim.RawBytePower) + } + if newClaim.QualityAdjPower.LessThan(big.Zero()) { + return xerrors.Errorf("negative claimed quality adjusted power: %v", newClaim.QualityAdjPower) + } + if st.MinerAboveMinPowerCount < 0 { + return xerrors.Errorf("negative number of miners larger than min: %v", st.MinerAboveMinPowerCount) + } + return setClaim(claims, miner, &newClaim) +} + +func (st *State) updateStatsForNewMiner(windowPoStProof abi.RegisteredPoStProof) error { + minPower, err := builtin.ConsensusMinerMinPower(windowPoStProof) + if err != nil { + return fmt.Errorf("could not get consensus miner min power: %w", err) + } + + if minPower.LessThanEqual(big.Zero()) { + st.MinerAboveMinPowerCount++ + } + return nil +} + +func (st *State) deleteClaim(claims *adt.Map, miner addr.Address) (bool, error) { + // Note: this flow loads the claim multiple times, unnecessarily. + // We should refactor to use claims.Pop(). + oldClaim, ok, err := getClaim(claims, miner) + if err != nil { + return false, fmt.Errorf("failed to get claim: %w", err) + } + if !ok { + return false, nil // no record, we're done + } + + // subtract from stats as if we were simply removing power + err = st.addToClaim(claims, miner, oldClaim.RawBytePower.Neg(), oldClaim.QualityAdjPower.Neg()) + if err != nil { + return false, fmt.Errorf("failed to subtract miner power before deleting claim: %w", err) + } + + // delete claim from state to invalidate miner + return true, claims.Delete(abi.AddrKey(miner)) +} + +func getClaim(claims *adt.Map, a addr.Address) (*Claim, bool, error) { + var out Claim + found, err := claims.Get(abi.AddrKey(a), &out) + if err != nil { + return nil, false, xerrors.Errorf("failed to get claim for address %v: %w", a, err) + } + if !found { + return nil, false, nil + } + return &out, true, nil +} + +func (st *State) addPledgeTotal(amount abi.TokenAmount) { + st.TotalPledgeCollateral = big.Add(st.TotalPledgeCollateral, amount) +} + +func (st *State) appendCronEvent(events *adt.Multimap, epoch abi.ChainEpoch, event *CronEvent) error { + // if event is in past, alter FirstCronEpoch so it will be found. + if epoch < st.FirstCronEpoch { + st.FirstCronEpoch = epoch + } + + if err := events.Add(epochKey(epoch), event); err != nil { + return xerrors.Errorf("failed to store cron event at epoch %v for miner %v: %w", epoch, event, err) + } + + return nil +} + +func (st *State) updateSmoothedEstimate(delta abi.ChainEpoch) { + filterQAPower := smoothing.LoadFilter(st.ThisEpochQAPowerSmoothed, smoothing.DefaultAlpha, smoothing.DefaultBeta) + st.ThisEpochQAPowerSmoothed = filterQAPower.NextEstimate(st.ThisEpochQualityAdjPower, delta) +} + +func loadCronEvents(mmap *adt.Multimap, epoch abi.ChainEpoch) ([]CronEvent, error) { + var events []CronEvent + var ev CronEvent + err := mmap.ForEach(epochKey(epoch), &ev, func(i int64) error { + events = append(events, ev) + return nil + }) + return events, err +} + +func setClaim(claims *adt.Map, a addr.Address, claim *Claim) error { + if claim.RawBytePower.LessThan(big.Zero()) { + return xerrors.Errorf("negative claim raw power %v", claim.RawBytePower) + } + if claim.QualityAdjPower.LessThan(big.Zero()) { + return xerrors.Errorf("negative claim quality-adjusted power %v", claim.QualityAdjPower) + } + if err := claims.Put(abi.AddrKey(a), claim); err != nil { + return xerrors.Errorf("failed to put claim with address %s power %v: %w", a, claim, err) + } + return nil +} + +// CurrentTotalPower returns current power values accounting for minimum miner +// and minimum power +func CurrentTotalPower(st *State) (abi.StoragePower, abi.StoragePower) { + if st.MinerAboveMinPowerCount < ConsensusMinerMinMiners { + return st.TotalBytesCommitted, st.TotalQABytesCommitted + } + return st.TotalRawBytePower, st.TotalQualityAdjPower +} + +func epochKey(e abi.ChainEpoch) abi.Keyer { + return abi.IntKey(int64(e)) +} + +func init() { + // Check that ChainEpoch is indeed a signed integer to confirm that epochKey is making the right interpretation. + var e abi.ChainEpoch + if reflect.TypeOf(e).Kind() != reflect.Int64 { + panic("incorrect chain epoch encoding") + } + +} diff --git a/chain/consensus/actors/registry/registry.go b/chain/consensus/actors/registry/registry.go index e89406786..b4839bacf 100644 --- a/chain/consensus/actors/registry/registry.go +++ b/chain/consensus/actors/registry/registry.go @@ -3,6 +3,7 @@ package registry import ( "github.com/filecoin-project/lotus/chain/actors" initactor "github.com/filecoin-project/lotus/chain/consensus/actors/init" + "github.com/filecoin-project/lotus/chain/consensus/actors/mpower" "github.com/filecoin-project/lotus/chain/consensus/actors/split" "github.com/filecoin-project/lotus/chain/consensus/hierarchical/actors/sca" "github.com/filecoin-project/lotus/chain/consensus/hierarchical/actors/subnet" @@ -20,6 +21,7 @@ func NewActorRegistry() *vm.ActorRegistry { inv.Register(nil, split.SplitActor{}) inv.Register(nil, subnet.SubnetActor{}) inv.Register(nil, sca.SubnetCoordActor{}) + inv.Register(nil, mpower.Actor{}) return inv } diff --git a/chain/consensus/hierarchical/actors/subnet/genesis.go b/chain/consensus/hierarchical/actors/subnet/genesis.go index 1d19c8202..1c1fb1b2c 100644 --- a/chain/consensus/hierarchical/actors/subnet/genesis.go +++ b/chain/consensus/hierarchical/actors/subnet/genesis.go @@ -18,6 +18,7 @@ import ( "github.com/filecoin-project/lotus/chain/actors/builtin/reward" "github.com/filecoin-project/lotus/chain/actors/builtin/system" actor "github.com/filecoin-project/lotus/chain/consensus/actors" + "github.com/filecoin-project/lotus/chain/consensus/actors/mpower" "github.com/filecoin-project/lotus/chain/consensus/hierarchical" "github.com/filecoin-project/lotus/chain/consensus/hierarchical/actors/sca" "github.com/filecoin-project/lotus/chain/gen" @@ -120,6 +121,15 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge return nil, nil, xerrors.Errorf("set init actor: %w", err) } + // Create empty power actor + spact, err := SetupStoragePowerActor(ctx, bs, av) + if err != nil { + return nil, nil, xerrors.Errorf("setup storage power actor: %w", err) + } + if err := state.SetActor(mpower.PowerActorAddr, spact); err != nil { + return nil, nil, xerrors.Errorf("set storage power actor: %w", err) + } + // Setup sca actor scaact, err := SetupSubnetActor(ctx, bs, template.NetworkName) if err != nil { @@ -246,3 +256,24 @@ func SetupSubnetActor(ctx context.Context, bs bstore.Blockstore, networkName str return act, nil } + +func SetupStoragePowerActor(ctx context.Context, bs bstore.Blockstore, av actors.Version) (*types.Actor, error) { + cst := cbor.NewCborStore(bs) + pst, err := mpower.ConstructState(adt.WrapStore(ctx, cbor.NewCborStore(bs))) + if err != nil { + return nil, err + } + + statecid, err := cst.Put(ctx, pst) + if err != nil { + return nil, err + } + + act := &types.Actor{ + Code: actor.MpowerActorCodeID, + Head: statecid, + Balance: big.Zero(), + } + + return act, nil +} From be8bc19b1cb8ebb02a45ed38d9db25cee714fc8d Mon Sep 17 00:00:00 2001 From: sleepy ramen Date: Tue, 7 Dec 2021 13:15:28 +0100 Subject: [PATCH 06/23] Update mocked power actor (#6) * fail to detect actor code * working but need clean * remove println --- chain/checkpointing/sub.go | 38 +++++++++------- chain/consensus/actors/init/actor_init.go | 3 +- chain/consensus/actors/mpower/power_actor.go | 5 +- chain/consensus/actors/mpower/power_state.go | 48 +++----------------- chain/vm/invoker.go | 1 + chain/vm/runtime.go | 1 - 6 files changed, 33 insertions(+), 63 deletions(-) diff --git a/chain/checkpointing/sub.go b/chain/checkpointing/sub.go index 4741747c8..e1927597d 100644 --- a/chain/checkpointing/sub.go +++ b/chain/checkpointing/sub.go @@ -17,11 +17,13 @@ import ( "github.com/Zondax/multi-party-sig/protocols/frost" "github.com/Zondax/multi-party-sig/protocols/frost/keygen" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/blockstore" "github.com/filecoin-project/lotus/chain/consensus/actors/mpower" "github.com/filecoin-project/lotus/chain/events" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node/impl" "github.com/filecoin-project/lotus/node/modules/helpers" + cbor "github.com/ipfs/go-ipld-cbor" logging "github.com/ipfs/go-log/v2" "github.com/libp2p/go-libp2p-core/host" pubsub "github.com/libp2p/go-libp2p-pubsub" @@ -188,28 +190,30 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { } match := func(oldTs, newTs *types.TipSet) (bool, events.StateChange, error) { - /* - NOT WORKING WITHOUT THE MOCKED POWER ACTOR - + newAct, err := c.api.StateGetActor(ctx, mpower.PowerActorAddr, newTs.Key()) + if err != nil { + return false, nil, err + } - newAct, err := c.api.StateGetActor(ctx, mpoweractor.MpowerActorAddr, newTs.Key()) - if err != nil { - return false, nil, err - } - */ oldAct, err := c.api.StateGetActor(ctx, mpower.PowerActorAddr, oldTs.Key()) if err != nil { return false, nil, err } - fmt.Println(oldAct) + var oldSt, newSt mpower.State - // This is not actually what we want. Just here to check. - oldTipset, err := c.api.ChainGetTipSet(ctx, oldTs.Key()) - if err != nil { + bs := blockstore.NewAPIBlockstore(c.api) + cst := cbor.NewCborStore(bs) + if err := cst.Get(ctx, oldAct.Head, &oldSt); err != nil { + return false, nil, err + } + if err := cst.Get(ctx, newAct.Head, &newSt); err != nil { return false, nil, err } + fmt.Println(oldSt) + fmt.Println(newSt) + // If Power Actors list has changed start DKG if !c.init { ts, err := c.api.ChainGetTipSetByHeight(ctx, 0, oldTs.Key()) @@ -226,26 +230,26 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { // ZONDAX TODO // Activate checkpointing every 20 blocks - fmt.Println("Height:", oldTipset.Height()) - if oldTipset.Height()%20 == 0 { + fmt.Println("Height:", newTs.Height()) + if newTs.Height()%20 == 0 { fmt.Println("Check point time") // Initiation and config should be happening at start if c.init && c.config != nil { fmt.Println("We have a taproot config") - data := oldTipset.Cids()[0] + data := oldTs.Cids()[0] c.CreateCheckpoint(ctx, data.Bytes()) } } // Generating new config every 50 blocks - if oldTipset.Height()%50 == 0 { + /*if newTs.Height()%50 == 0 { fmt.Println("Generate new config") return true, nil, nil - } + }*/ return false, nil, nil } diff --git a/chain/consensus/actors/init/actor_init.go b/chain/consensus/actors/init/actor_init.go index ad53b9b82..d8cb1d9f5 100644 --- a/chain/consensus/actors/init/actor_init.go +++ b/chain/consensus/actors/init/actor_init.go @@ -110,7 +110,8 @@ func canExec(callerCodeID cid.Cid, execCodeID cid.Cid) bool { case builtin.PaymentChannelActorCodeID, builtin.MultisigActorCodeID, actor.SplitActorCodeID, - actor.SubnetActorCodeID: + actor.SubnetActorCodeID, + actor.MpowerActorCodeID: return true default: return false diff --git a/chain/consensus/actors/mpower/power_actor.go b/chain/consensus/actors/mpower/power_actor.go index 604fac97a..8caa0e5c8 100644 --- a/chain/consensus/actors/mpower/power_actor.go +++ b/chain/consensus/actors/mpower/power_actor.go @@ -10,6 +10,7 @@ import ( "github.com/filecoin-project/go-state-types/cbor" "github.com/filecoin-project/go-state-types/exitcode" rtt "github.com/filecoin-project/go-state-types/rt" + actor "github.com/filecoin-project/lotus/chain/consensus/actors" xerrors "golang.org/x/xerrors" power0 "github.com/filecoin-project/specs-actors/actors/builtin/power" @@ -57,7 +58,7 @@ func (a Actor) Exports() []interface{} { } func (a Actor) Code() cid.Cid { - return builtin.StoragePowerActorCodeID + return actor.MpowerActorCodeID } func (a Actor) IsSingleton() bool { @@ -113,7 +114,7 @@ type CreateMinerParams struct { type CreateMinerReturn = power0.CreateMinerReturn func (a Actor) CreateMiner(rt Runtime, params *CreateMinerParams) *CreateMinerReturn { - rt.ValidateImmediateCallerType(builtin.CallerTypesSignable...) + rt.ValidateImmediateCallerAcceptAny() ctorParams := MinerConstructorParams{ OwnerAddr: params.Owner, diff --git a/chain/consensus/actors/mpower/power_state.go b/chain/consensus/actors/mpower/power_state.go index c934c77c5..0bd4289ae 100644 --- a/chain/consensus/actors/mpower/power_state.go +++ b/chain/consensus/actors/mpower/power_state.go @@ -7,7 +7,6 @@ import ( addr "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/go-state-types/exitcode" cid "github.com/ipfs/go-cid" "golang.org/x/xerrors" @@ -177,57 +176,22 @@ func (st *State) GetClaim(s adt.Store, a addr.Address) (*Claim, bool, error) { } func (st *State) addToClaim(claims *adt.Map, miner addr.Address, power abi.StoragePower, qapower abi.StoragePower) error { - oldClaim, ok, err := getClaim(claims, miner) - if err != nil { - return fmt.Errorf("failed to get claim: %w", err) - } - if !ok { - return exitcode.ErrNotFound.Wrapf("no claim for actor %v", miner) - } - // TotalBytes always update directly st.TotalQABytesCommitted = big.Add(st.TotalQABytesCommitted, qapower) st.TotalBytesCommitted = big.Add(st.TotalBytesCommitted, power) + oldClaim := Claim{ + WindowPoStProofType: 0, + RawBytePower: big.NewInt(0), + QualityAdjPower: big.NewInt(0), + } + newClaim := Claim{ WindowPoStProofType: oldClaim.WindowPoStProofType, RawBytePower: big.Add(oldClaim.RawBytePower, power), QualityAdjPower: big.Add(oldClaim.QualityAdjPower, qapower), } - minPower, err := builtin.ConsensusMinerMinPower(oldClaim.WindowPoStProofType) - if err != nil { - return fmt.Errorf("could not get consensus miner min power: %w", err) - } - - prevBelow := oldClaim.RawBytePower.LessThan(minPower) - stillBelow := newClaim.RawBytePower.LessThan(minPower) - - if prevBelow && !stillBelow { - // just passed min miner size - st.MinerAboveMinPowerCount++ - st.TotalQualityAdjPower = big.Add(st.TotalQualityAdjPower, newClaim.QualityAdjPower) - st.TotalRawBytePower = big.Add(st.TotalRawBytePower, newClaim.RawBytePower) - } else if !prevBelow && stillBelow { - // just went below min miner size - st.MinerAboveMinPowerCount-- - st.TotalQualityAdjPower = big.Sub(st.TotalQualityAdjPower, oldClaim.QualityAdjPower) - st.TotalRawBytePower = big.Sub(st.TotalRawBytePower, oldClaim.RawBytePower) - } else if !prevBelow && !stillBelow { - // Was above the threshold, still above - st.TotalQualityAdjPower = big.Add(st.TotalQualityAdjPower, qapower) - st.TotalRawBytePower = big.Add(st.TotalRawBytePower, power) - } - - if newClaim.RawBytePower.LessThan(big.Zero()) { - return xerrors.Errorf("negative claimed raw byte power: %v", newClaim.RawBytePower) - } - if newClaim.QualityAdjPower.LessThan(big.Zero()) { - return xerrors.Errorf("negative claimed quality adjusted power: %v", newClaim.QualityAdjPower) - } - if st.MinerAboveMinPowerCount < 0 { - return xerrors.Errorf("negative number of miners larger than min: %v", st.MinerAboveMinPowerCount) - } return setClaim(claims, miner, &newClaim) } diff --git a/chain/vm/invoker.go b/chain/vm/invoker.go index 85357e51b..3c8a924f6 100644 --- a/chain/vm/invoker.go +++ b/chain/vm/invoker.go @@ -99,6 +99,7 @@ func (ar *ActorRegistry) Register(pred ActorPredicate, actors ...rtt.VMActor) { if err != nil { panic(xerrors.Errorf("%s: %w", string(a.Code().Hash()), err)) } + ar.actors[a.Code()] = &actorInfo{ methods: code, vmActor: a, diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index 6e94030bd..b3e013e5a 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -280,7 +280,6 @@ func (rt *Runtime) CreateActor(codeID cid.Cid, addr address.Address) { if aerr != nil { rt.Abortf(aerr.RetCode(), aerr.Error()) } - _, err := rt.state.GetActor(addr) if err == nil { rt.Abortf(exitcode.SysErrorIllegalArgument, "Actor address already exists") From f8b5a7651f1935ce009deb874a7917474a10cc96 Mon Sep 17 00:00:00 2001 From: sleepy ramen Date: Tue, 7 Dec 2021 23:51:59 +0100 Subject: [PATCH 07/23] Create config file (#7) * saving file /tmp * verify if share file exist --- chain/checkpointing/constant.go | 4 + chain/checkpointing/network.go | 3 - chain/checkpointing/storage.go | 36 +++++++ chain/checkpointing/sub.go | 160 ++++++++++++++++---------------- chain/checkpointing/util.go | 1 + go.mod | 1 + go.sum | 15 +++ 7 files changed, 136 insertions(+), 84 deletions(-) create mode 100644 chain/checkpointing/storage.go diff --git a/chain/checkpointing/constant.go b/chain/checkpointing/constant.go index 3cc7c15a1..64bdfc96e 100644 --- a/chain/checkpointing/constant.go +++ b/chain/checkpointing/constant.go @@ -1,3 +1,7 @@ package checkpointing var FEE float64 = 0.01 +var S3_HOST string = "minio.deadbrain.corp" +var ACCESS_KEY_ID string = "" +var SECRET_ACCESS_KEY string = "" +var BUCKET_NAME string = "eudico" diff --git a/chain/checkpointing/network.go b/chain/checkpointing/network.go index 8074d1487..fbc203d50 100644 --- a/chain/checkpointing/network.go +++ b/chain/checkpointing/network.go @@ -25,14 +25,11 @@ func NewNetwork(parties party.IDSlice, sub *pubsub.Subscription, topic *pubsub.T } func (n *Network) Next(ctx context.Context) *protocol.Message { - fmt.Println("Waiting for message") msg, err := n.sub.Next(ctx) if err != nil { panic(err) } - fmt.Println("Message received") - // Converting a pubsub.Message into a protocol.Message // see https://pkg.go.dev/github.com/libp2p/go-libp2p-pubsub@v0.5.3/pb#Message // https://pkg.go.dev/github.com/taurusgroup/multi-party-sig@v0.6.0-alpha-2021-09-21/pkg/protocol?utm_source=gopls#Message diff --git a/chain/checkpointing/storage.go b/chain/checkpointing/storage.go new file mode 100644 index 000000000..e7c1b82b0 --- /dev/null +++ b/chain/checkpointing/storage.go @@ -0,0 +1,36 @@ +package checkpointing + +import ( + "crypto/sha256" + "encoding/hex" + "fmt" + "os" + + "github.com/minio/minio-go/v7" + "github.com/minio/minio-go/v7/pkg/credentials" +) + +func StoreConfig() { + // Initialize minio client object. + minioClient, err := minio.New(S3_HOST, &minio.Options{ + Creds: credentials.NewStaticV4(ACCESS_KEY_ID, SECRET_ACCESS_KEY, ""), + Secure: false, + }) + if err != nil { + panic(err) + } + + fmt.Println(minioClient) +} + +func CreateConfig(data []byte) ([]byte, error) { + hash := sha256.Sum256(data) + + fmt.Println(hex.EncodeToString(hash[:])) + err := os.WriteFile("/tmp/"+hex.EncodeToString(hash[:]), data, 0644) + if err != nil { + return nil, err + } + + return hash[:], nil +} diff --git a/chain/checkpointing/sub.go b/chain/checkpointing/sub.go index e1927597d..439e01595 100644 --- a/chain/checkpointing/sub.go +++ b/chain/checkpointing/sub.go @@ -8,6 +8,7 @@ import ( "fmt" "os" "sort" + "strconv" "github.com/BurntSushi/toml" "github.com/Zondax/multi-party-sig/pkg/math/curve" @@ -72,61 +73,67 @@ func NewCheckpointSub( return nil, err } + var config *keygen.TaprootConfig // Load configTaproot - content, err := os.ReadFile(os.Getenv("EUDICO_PATH") + "/share.toml") - if err != nil { - return nil, err - } + if _, err := os.Stat(os.Getenv("EUDICO_PATH") + "/share.toml"); errors.Is(err, os.ErrNotExist) { + // path/to/whatever does not exist + fmt.Println("No share file saved") + } else { + content, err := os.ReadFile(os.Getenv("EUDICO_PATH") + "/share.toml") + if err != nil { + return nil, err + } - var configTOML TaprootConfigTOML - _, err = toml.Decode(string(content), &configTOML) - if err != nil { - return nil, err - } + var configTOML TaprootConfigTOML + _, err = toml.Decode(string(content), &configTOML) + if err != nil { + return nil, err + } - privateSharePath, err := hex.DecodeString(configTOML.PrivateShare) - if err != nil { - return nil, err - } + privateSharePath, err := hex.DecodeString(configTOML.PrivateShare) + if err != nil { + return nil, err + } - publickey, err := hex.DecodeString(configTOML.PublicKey) - if err != nil { - return nil, err - } + publickey, err := hex.DecodeString(configTOML.PublicKey) + if err != nil { + return nil, err + } - var privateShare curve.Secp256k1Scalar - err = privateShare.UnmarshalBinary(privateSharePath) - if err != nil { - return nil, err - } + var privateShare curve.Secp256k1Scalar + err = privateShare.UnmarshalBinary(privateSharePath) + if err != nil { + return nil, err + } - verificationShares := make(map[party.ID]*curve.Secp256k1Point) + verificationShares := make(map[party.ID]*curve.Secp256k1Point) - fmt.Println(configTOML.VerificationShares) + fmt.Println(configTOML.VerificationShares) - for key, vshare := range configTOML.VerificationShares { + for key, vshare := range configTOML.VerificationShares { - fmt.Println(key) - fmt.Println(vshare) + fmt.Println(key) + fmt.Println(vshare) - var p curve.Secp256k1Point - pByte, err := hex.DecodeString(vshare.Share) - if err != nil { - return nil, err - } - err = p.UnmarshalBinary(pByte) - if err != nil { - return nil, err + var p curve.Secp256k1Point + pByte, err := hex.DecodeString(vshare.Share) + if err != nil { + return nil, err + } + err = p.UnmarshalBinary(pByte) + if err != nil { + return nil, err + } + verificationShares[party.ID(key)] = &p } - verificationShares[party.ID(key)] = &p - } - config := keygen.TaprootConfig{ - ID: party.ID(host.ID().String()), - Threshold: configTOML.Thershold, - PrivateShare: &privateShare, - PublicKey: publickey, - VerificationShares: verificationShares, + config = &keygen.TaprootConfig{ + ID: party.ID(host.ID().String()), + Threshold: configTOML.Thershold, + PrivateShare: &privateShare, + PublicKey: publickey, + VerificationShares: verificationShares, + } } return &CheckpointingSub{ @@ -138,7 +145,7 @@ func NewCheckpointSub( events: e, init: false, ptxid: "", - config: &config, + config: config, newconfig: nil, }, nil } @@ -165,18 +172,15 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { f := frost.KeygenTaproot(id, ids, threshold) handler, err := protocol.NewMultiHandler(f, []byte{1, 2, 3}) - - fmt.Println(handler) - if err != nil { fmt.Println(err) - log.Fatal("Not working") + panic(err) } c.LoopHandler(ctx, handler, n) r, err := handler.Result() if err != nil { fmt.Println(err) - log.Fatal("Not working neither") + panic(err) } fmt.Println("Result :", r) @@ -211,9 +215,6 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { return false, nil, err } - fmt.Println(oldSt) - fmt.Println(newSt) - // If Power Actors list has changed start DKG if !c.init { ts, err := c.api.ChainGetTipSetByHeight(ctx, 0, oldTs.Key()) @@ -236,20 +237,28 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { // Initiation and config should be happening at start if c.init && c.config != nil { - fmt.Println("We have a taproot config") data := oldTs.Cids()[0] - c.CreateCheckpoint(ctx, data.Bytes()) + var partyList string = "" + for _, partyId := range c.orderParticipantsList() { + partyList += partyId + "\n" + } + hash, err := CreateConfig([]byte(partyList)) + if err != nil { + panic(err) + } + + c.CreateCheckpoint(ctx, data.Bytes(), hash) } } - // Generating new config every 50 blocks - /*if newTs.Height()%50 == 0 { + // Changes detected so generate new key + if oldSt.MinerCount != newSt.MinerCount { fmt.Println("Generate new config") return true, nil, nil - }*/ + } return false, nil, nil } @@ -295,9 +304,7 @@ func (c *CheckpointingSub) LoopHandler(ctx context.Context, h protocol.Handler, } } -func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, data []byte) { - fmt.Println("Create Checkpoint!!!") - +func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, cp, data []byte) { idsStrings := c.orderParticipantsList() fmt.Println("Participants list :", idsStrings) fmt.Println("Precedent tx", c.ptxid) @@ -309,7 +316,7 @@ func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, data []byte) { pubkey = c.newconfig.PublicKey } - pubkeyShort := GenCheckpointPublicKeyTaproot(pubkey, data) + pubkeyShort := GenCheckpointPublicKeyTaproot(pubkey, cp) newTaprootAddress := PubkeyToTapprootAddress(pubkeyShort) if c.ptxid == "" { @@ -329,27 +336,19 @@ func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, data []byte) { fmt.Println("Found precedent txid:", c.ptxid) } - /*payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"gettxout\", \"params\": [\"" + c.ptxid + "\", 0]}" - result := jsonRPC(payload) - if result == nil { - panic("cant retrieve previous transaction") - } - taprootTxOut := result["result"].(map[string]interface{}) - newValue := taprootTxOut["value"].(float64) - FEE - - scriptPubkey := taprootTxOut["scriptPubKey"].(map[string]interface{}) - scriptPubkeyBytes, _ := hex.DecodeString(scriptPubkey["hex"].(string))*/ - - value, scriptPubkeyBytes := GetTxOut(c.ptxid, 0) + index := 0 + value, scriptPubkeyBytes := GetTxOut(c.ptxid, index) if scriptPubkeyBytes[0] != 0x51 { fmt.Println("Wrong txout") - value, scriptPubkeyBytes = GetTxOut(c.ptxid, 1) + index = 1 + value, scriptPubkeyBytes = GetTxOut(c.ptxid, index) } newValue := value - FEE - payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"createrawtransaction\", \"params\": [[{\"txid\":\"" + c.ptxid + "\",\"vout\": 0, \"sequence\": 4294967295}], [{\"" + newTaprootAddress + "\": \"" + fmt.Sprintf("%.2f", newValue) + "\"}, {\"data\": \"" + hex.EncodeToString(data) + "\"}]]}" + payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"createrawtransaction\", \"params\": [[{\"txid\":\"" + c.ptxid + "\",\"vout\": " + strconv.Itoa(index) + ", \"sequence\": 4294967295}], [{\"" + newTaprootAddress + "\": \"" + fmt.Sprintf("%.2f", newValue) + "\"}, {\"data\": \"" + hex.EncodeToString(data) + "\"}]]}" result := jsonRPC(payload) + fmt.Println(result) if result == nil { panic("cant create new transaction") } @@ -385,12 +384,12 @@ func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, data []byte) { r, err := handler.Result() if err != nil { fmt.Println(err) - log.Fatal("Not working neither") + panic(err) } fmt.Println("Result :", r) // if signing is a success we register the new value - merkleRoot := HashMerkleRoot(pubkey, data) + merkleRoot := HashMerkleRoot(pubkey, cp) c.tweakedValue = HashTweakedValue(pubkey, merkleRoot) c.pubkey = pubkeyShort // If new config used @@ -418,7 +417,6 @@ func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, data []byte) { fmt.Println("New Txid:", newtxid) c.ptxid = newtxid } - } func (c *CheckpointingSub) orderParticipantsList() []string { @@ -462,8 +460,8 @@ func (c *CheckpointingSub) prefundTaproot() error { return nil } -func (c *CheckpointingSub) initiate(data []byte) error { - pubkeyShort := GenCheckpointPublicKeyTaproot(c.config.PublicKey, data) +func (c *CheckpointingSub) initiate(cp []byte) error { + pubkeyShort := GenCheckpointPublicKeyTaproot(c.config.PublicKey, cp) c.pubkey = pubkeyShort idsStrings := c.orderParticipantsList() @@ -476,7 +474,7 @@ func (c *CheckpointingSub) initiate(data []byte) error { } // Save tweaked value - merkleRoot := HashMerkleRoot(c.config.PublicKey, data) + merkleRoot := HashMerkleRoot(c.config.PublicKey, cp) c.tweakedValue = HashTweakedValue(c.config.PublicKey, merkleRoot) c.init = true diff --git a/chain/checkpointing/util.go b/chain/checkpointing/util.go index 253458977..9b1017da8 100644 --- a/chain/checkpointing/util.go +++ b/chain/checkpointing/util.go @@ -238,6 +238,7 @@ func ParseUnspentTxOut(utxo []byte) (amount, script []byte) { func GetTxOut(txid string, index int) (float64, []byte) { payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"gettxout\", \"params\": [\"" + txid + "\", " + strconv.Itoa(index) + "]}" result := jsonRPC(payload) + fmt.Println(result) if result == nil { panic("cant retrieve previous transaction") } diff --git a/go.mod b/go.mod index ba01fae2f..2ae7461c2 100644 --- a/go.mod +++ b/go.mod @@ -127,6 +127,7 @@ require ( github.com/libp2p/go-maddr-filter v0.1.0 github.com/mattn/go-isatty v0.0.14 github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 + github.com/minio/minio-go/v7 v7.0.16 // indirect github.com/mitchellh/go-homedir v1.1.0 github.com/multiformats/go-base32 v0.0.4 github.com/multiformats/go-multiaddr v0.4.1 diff --git a/go.sum b/go.sum index 846f98314..7405b42be 100644 --- a/go.sum +++ b/go.sum @@ -946,6 +946,7 @@ github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= @@ -970,8 +971,12 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s= +github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.8/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= @@ -1399,6 +1404,10 @@ github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0 github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/minio/md5-simd v1.1.0 h1:QPfiOqlZH+Cj9teu0t9b1nTBfPbyTl16Of5MeuShdK4= +github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= +github.com/minio/minio-go/v7 v7.0.16 h1:GspaSBS8lOuEUCAqMe0W3UxSoyOA4b4F8PTspRVI+k4= +github.com/minio/minio-go/v7 v7.0.16/go.mod h1:pUV0Pc+hPd1nccgmzQF/EXh48l/Z/yps6QPF1aaie4g= github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= @@ -1418,9 +1427,11 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= @@ -1662,6 +1673,7 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.21.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM= github.com/rs/zerolog v1.23.0/go.mod h1:6c7hFfxPOy7TacJc4Fcdi24/J0NKYGzjG8FWRI916Qo= @@ -1981,6 +1993,7 @@ golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= @@ -2455,6 +2468,8 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww= +gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= From ebca6a61bf52f62d47a5426663870f1eb7862677 Mon Sep 17 00:00:00 2001 From: sleepy ramen Date: Fri, 10 Dec 2021 00:22:26 +0100 Subject: [PATCH 08/23] adding permissions scripts (#8) --- scripts/data-permissions.sh | 3 +++ 1 file changed, 3 insertions(+) create mode 100755 scripts/data-permissions.sh diff --git a/scripts/data-permissions.sh b/scripts/data-permissions.sh new file mode 100755 index 000000000..14e9c0198 --- /dev/null +++ b/scripts/data-permissions.sh @@ -0,0 +1,3 @@ +chmod 600 data/alice/keystore/* +chmod 600 data/bob/keystore/* +chmod 600 data/charlie/keystore/* \ No newline at end of file From 4a822c69905ab68bc27d14208360b9c890be8a6b Mon Sep 17 00:00:00 2001 From: sleepy ramen Date: Sun, 12 Dec 2021 11:06:48 +0100 Subject: [PATCH 09/23] remove constant; create specific checkpoint config; (#9) --- chain/checkpointing/constant.go | 7 ------- chain/checkpointing/storage.go | 24 ++++++++++++++++-------- chain/checkpointing/sub.go | 22 +++++++++++++++++++++- data/alice/config.toml | 7 +++++++ data/bob/config.toml | 7 +++++++ data/charlie/config.toml | 7 +++++++ go.mod | 2 +- go.sum | 2 ++ node/config/types.go | 9 +++++++++ scripts/generate-bitcoin-blocks.sh | 2 +- 10 files changed, 71 insertions(+), 18 deletions(-) delete mode 100644 chain/checkpointing/constant.go diff --git a/chain/checkpointing/constant.go b/chain/checkpointing/constant.go deleted file mode 100644 index 64bdfc96e..000000000 --- a/chain/checkpointing/constant.go +++ /dev/null @@ -1,7 +0,0 @@ -package checkpointing - -var FEE float64 = 0.01 -var S3_HOST string = "minio.deadbrain.corp" -var ACCESS_KEY_ID string = "" -var SECRET_ACCESS_KEY string = "" -var BUCKET_NAME string = "eudico" diff --git a/chain/checkpointing/storage.go b/chain/checkpointing/storage.go index e7c1b82b0..9e12b1406 100644 --- a/chain/checkpointing/storage.go +++ b/chain/checkpointing/storage.go @@ -1,33 +1,41 @@ package checkpointing import ( + "context" "crypto/sha256" "encoding/hex" - "fmt" "os" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" ) -func StoreConfig() { +func StoreConfig(ctx context.Context, host, accessKeyId, secretAccessKey, bucketName, hash string) error { // Initialize minio client object. - minioClient, err := minio.New(S3_HOST, &minio.Options{ - Creds: credentials.NewStaticV4(ACCESS_KEY_ID, SECRET_ACCESS_KEY, ""), + minioClient, err := minio.New(host, &minio.Options{ + Creds: credentials.NewStaticV4(accessKeyId, secretAccessKey, ""), Secure: false, }) if err != nil { - panic(err) + return err } - fmt.Println(minioClient) + filename := hash+".txt" + filePath := "/tmp/"+filename + contentType := "text/plain" + + _, err = minioClient.FPutObject(ctx, bucketName, filename, filePath, minio.PutObjectOptions{ContentType: contentType}) + if err != nil { + return err + } + + return nil } func CreateConfig(data []byte) ([]byte, error) { hash := sha256.Sum256(data) - fmt.Println(hex.EncodeToString(hash[:])) - err := os.WriteFile("/tmp/"+hex.EncodeToString(hash[:]), data, 0644) + err := os.WriteFile("/tmp/"+hex.EncodeToString(hash[:])+".txt", data, 0644) if err != nil { return nil, err } diff --git a/chain/checkpointing/sub.go b/chain/checkpointing/sub.go index 439e01595..bedacb1b1 100644 --- a/chain/checkpointing/sub.go +++ b/chain/checkpointing/sub.go @@ -24,6 +24,7 @@ import ( "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node/impl" "github.com/filecoin-project/lotus/node/modules/helpers" + "github.com/filecoin-project/lotus/node/config" cbor "github.com/ipfs/go-ipld-cbor" logging "github.com/ipfs/go-log/v2" "github.com/libp2p/go-libp2p-core/host" @@ -56,6 +57,8 @@ type CheckpointingSub struct { ptxid string // Tweaked value tweakedValue []byte + // minio config + cpconfig *config.Checkpoint } func NewCheckpointSub( @@ -73,6 +76,14 @@ func NewCheckpointSub( return nil, err } + var ccfg config.FullNode + result, err := config.FromFile(os.Getenv("EUDICO_PATH")+"/config.toml", &ccfg) + if err != nil { + return nil, err + } + + cpconfig := result.(*config.FullNode).Checkpoint + var config *keygen.TaprootConfig // Load configTaproot if _, err := os.Stat(os.Getenv("EUDICO_PATH") + "/share.toml"); errors.Is(err, os.ErrNotExist) { @@ -147,6 +158,7 @@ func NewCheckpointSub( ptxid: "", config: config, newconfig: nil, + cpconfig: &cpconfig, }, nil } @@ -249,6 +261,12 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { panic(err) } + // Push config to S3 + err = StoreConfig(ctx, c.cpconfig.MinioHost, c.cpconfig.MinioAccessKeyID, c.cpconfig.MinioSecretAccessKey, c.cpconfig.MinioBucketName ,hex.EncodeToString(hash)) + if err != nil { + panic(err) + } + c.CreateCheckpoint(ctx, data.Bytes(), hash) } } @@ -344,7 +362,7 @@ func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, cp, data []byte index = 1 value, scriptPubkeyBytes = GetTxOut(c.ptxid, index) } - newValue := value - FEE + newValue := value - c.cpconfig.Fee payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"createrawtransaction\", \"params\": [[{\"txid\":\"" + c.ptxid + "\",\"vout\": " + strconv.Itoa(index) + ", \"sequence\": 4294967295}], [{\"" + newTaprootAddress + "\": \"" + fmt.Sprintf("%.2f", newValue) + "\"}, {\"data\": \"" + hex.EncodeToString(data) + "\"}]]}" result := jsonRPC(payload) @@ -398,6 +416,8 @@ func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, cp, data []byte c.newconfig = nil } + c.ptxid = "" + if idsStrings[0] == c.host.ID().String() { // Only first one broadcast the transaction ? // Actually all participants can broadcast the transcation. It will be the same everywhere. diff --git a/data/alice/config.toml b/data/alice/config.toml index 567bdf27c..f780f7bb7 100644 --- a/data/alice/config.toml +++ b/data/alice/config.toml @@ -183,3 +183,10 @@ # type: uint64 # env var: LOTUS_CHAINSTORE_SPLITSTORE_HOTSTOREFULLGCFREQUENCY #HotStoreFullGCFrequency = 20 + +[Checkpoint] + Fee = 0.01 + MinioHost = "127.0.0.1:9000" + MinioAccessKeyID = "JLVSCVFWEPJGTFL67Z4C" + MinioSecretAccessKey = "4MjUvWBrtzYdJESCBQF+CYWKzhagvUZn2WRqkHnz" + MinioBucketName = "eudico" \ No newline at end of file diff --git a/data/bob/config.toml b/data/bob/config.toml index 1e80a901f..11b5d0cb9 100644 --- a/data/bob/config.toml +++ b/data/bob/config.toml @@ -183,3 +183,10 @@ # type: uint64 # env var: LOTUS_CHAINSTORE_SPLITSTORE_HOTSTOREFULLGCFREQUENCY #HotStoreFullGCFrequency = 20 + +[Checkpoint] + Fee = 0.01 + MinioHost = "127.0.0.1:9000" + MinioAccessKeyID = "JLVSCVFWEPJGTFL67Z4C" + MinioSecretAccessKey = "4MjUvWBrtzYdJESCBQF+CYWKzhagvUZn2WRqkHnz" + MinioBucketName = "eudico" \ No newline at end of file diff --git a/data/charlie/config.toml b/data/charlie/config.toml index 67ad510b0..ba06ea354 100644 --- a/data/charlie/config.toml +++ b/data/charlie/config.toml @@ -183,3 +183,10 @@ # type: uint64 # env var: LOTUS_CHAINSTORE_SPLITSTORE_HOTSTOREFULLGCFREQUENCY #HotStoreFullGCFrequency = 20 + +[Checkpoint] + Fee = 0.01 + MinioHost = "127.0.0.1:9000" + MinioAccessKeyID = "JLVSCVFWEPJGTFL67Z4C" + MinioSecretAccessKey = "4MjUvWBrtzYdJESCBQF+CYWKzhagvUZn2WRqkHnz" + MinioBucketName = "eudico" \ No newline at end of file diff --git a/go.mod b/go.mod index 2ae7461c2..04339ce05 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee github.com/Kubuxu/imtui v0.0.0-20210401140320-41663d68d0fa github.com/StackExchange/wmi v1.2.1 // indirect - github.com/Zondax/multi-party-sig v0.6.0-alpha-2021-09-21.0.20211117140501-65990deeb804 + github.com/Zondax/multi-party-sig v0.6.0-alpha-2021-09-21.0.20211202131736-ca8cb1c7e1a1 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d github.com/alecthomas/jsonschema v0.0.0-20200530073317-71f438968921 github.com/btcsuite/btcutil v1.0.3-0.20210929233259-9cdf59f60c51 diff --git a/go.sum b/go.sum index 7405b42be..9561261a3 100644 --- a/go.sum +++ b/go.sum @@ -84,6 +84,8 @@ github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/Zondax/multi-party-sig v0.6.0-alpha-2021-09-21.0.20211117140501-65990deeb804 h1:zQrDkZ4qvHYKvqCJ2ljZ8VVSwHa1YC6nT8FFNQIahf0= github.com/Zondax/multi-party-sig v0.6.0-alpha-2021-09-21.0.20211117140501-65990deeb804/go.mod h1:KOfSxMrl13ge7DX30LdWQyw4zrVzyZc9uykL77Q/TXc= +github.com/Zondax/multi-party-sig v0.6.0-alpha-2021-09-21.0.20211202131736-ca8cb1c7e1a1 h1:txHoW8OAMuzzEJqKy/krlsq45hMtySGKxW6W5LIlveM= +github.com/Zondax/multi-party-sig v0.6.0-alpha-2021-09-21.0.20211202131736-ca8cb1c7e1a1/go.mod h1:KOfSxMrl13ge7DX30LdWQyw4zrVzyZc9uykL77Q/TXc= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= diff --git a/node/config/types.go b/node/config/types.go index 1be40029e..c40fab2e2 100644 --- a/node/config/types.go +++ b/node/config/types.go @@ -26,6 +26,7 @@ type FullNode struct { Wallet Wallet Fees FeeConfig Chainstore Chainstore + Checkpoint Checkpoint } // // Common @@ -382,3 +383,11 @@ type Wallet struct { type FeeConfig struct { DefaultMaxFee types.FIL } + +type Checkpoint struct { + Fee float64 + MinioHost string + MinioAccessKeyID string + MinioSecretAccessKey string + MinioBucketName string +} \ No newline at end of file diff --git a/scripts/generate-bitcoin-blocks.sh b/scripts/generate-bitcoin-blocks.sh index 299976527..2c3066a92 100755 --- a/scripts/generate-bitcoin-blocks.sh +++ b/scripts/generate-bitcoin-blocks.sh @@ -1,6 +1,6 @@ #! /bin/bash -while sleep 10; do curl -u satoshi:amiens -X POST \ +while sleep 1; do curl -u satoshi:amiens -X POST \ 127.0.0.1:18443 \ -d "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"generatetoaddress\", \"params\": [1, \"bcrt1qgp62tlj8hwd7lpp0thz0ujjvgxsjug5hr4l8xj\"]}" \ -H 'Content-Type:application/json'; done \ No newline at end of file From 04171356eedc13505402a1d2f8fd903e0ca0b9b4 Mon Sep 17 00:00:00 2001 From: sleepy ramen Date: Tue, 14 Dec 2021 15:52:39 +0100 Subject: [PATCH 10/23] Verification (#10) --- chain/checkpointing/storage.go | 44 +++-- chain/checkpointing/sub.go | 140 +++++++++---- chain/checkpointing/util.go | 17 +- chain/checkpointing/verification.go | 86 ++++++++ data/alice/config.toml | 1 + data/bob/config.toml | 1 + data/charlie/config.toml | 1 + data/dom/config.toml | 195 +++++++++++++++++++ data/dom/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU | 1 + data/dom/keystore/NRUWE4BSOAWWQ33TOQ | 1 + data/dom/token | 1 + node/config/types.go | 11 +- scripts/data-clean.sh | 31 +++ scripts/data-permissions.sh | 3 +- scripts/verification.sh | 5 + 15 files changed, 473 insertions(+), 65 deletions(-) create mode 100644 chain/checkpointing/verification.go create mode 100644 data/dom/config.toml create mode 100644 data/dom/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU create mode 100644 data/dom/keystore/NRUWE4BSOAWWQ33TOQ create mode 100644 data/dom/token create mode 100755 scripts/data-clean.sh create mode 100755 scripts/verification.sh diff --git a/chain/checkpointing/storage.go b/chain/checkpointing/storage.go index 9e12b1406..4f353da44 100644 --- a/chain/checkpointing/storage.go +++ b/chain/checkpointing/storage.go @@ -4,31 +4,24 @@ import ( "context" "crypto/sha256" "encoding/hex" + "fmt" + "io/ioutil" "os" + "strings" "github.com/minio/minio-go/v7" - "github.com/minio/minio-go/v7/pkg/credentials" ) -func StoreConfig(ctx context.Context, host, accessKeyId, secretAccessKey, bucketName, hash string) error { - // Initialize minio client object. - minioClient, err := minio.New(host, &minio.Options{ - Creds: credentials.NewStaticV4(accessKeyId, secretAccessKey, ""), - Secure: false, - }) +func StoreConfig(ctx context.Context, minioClient *minio.Client, bucketName, hash string) error { + filename := hash + ".txt" + filePath := "/tmp/" + filename + contentType := "text/plain" + + _, err := minioClient.FPutObject(ctx, bucketName, filename, filePath, minio.PutObjectOptions{ContentType: contentType}) if err != nil { return err } - filename := hash+".txt" - filePath := "/tmp/"+filename - contentType := "text/plain" - - _, err = minioClient.FPutObject(ctx, bucketName, filename, filePath, minio.PutObjectOptions{ContentType: contentType}) - if err != nil { - return err - } - return nil } @@ -42,3 +35,22 @@ func CreateConfig(data []byte) ([]byte, error) { return hash[:], nil } + +func GetConfig(ctx context.Context, minioClient *minio.Client, bucketName, hash string) (string, error) { + filename := hash + ".txt" + filePath := "/tmp/dom/" + filename + + err := minioClient.FGetObject(context.Background(), bucketName, filename, filePath, minio.GetObjectOptions{}) + if err != nil { + return "", err + } + + content, err := ioutil.ReadFile(filePath) // the file is inside the local directory + if err != nil { + return "", err + } + cpCid := strings.Split(string(content), "\n")[0] + fmt.Println(cpCid) + + return cpCid, nil +} diff --git a/chain/checkpointing/sub.go b/chain/checkpointing/sub.go index bedacb1b1..8cd5a859f 100644 --- a/chain/checkpointing/sub.go +++ b/chain/checkpointing/sub.go @@ -22,13 +22,15 @@ import ( "github.com/filecoin-project/lotus/chain/consensus/actors/mpower" "github.com/filecoin-project/lotus/chain/events" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/node/config" "github.com/filecoin-project/lotus/node/impl" "github.com/filecoin-project/lotus/node/modules/helpers" - "github.com/filecoin-project/lotus/node/config" cbor "github.com/ipfs/go-ipld-cbor" logging "github.com/ipfs/go-log/v2" "github.com/libp2p/go-libp2p-core/host" pubsub "github.com/libp2p/go-libp2p-pubsub" + "github.com/minio/minio-go/v7" + "github.com/minio/minio-go/v7/pkg/credentials" "go.uber.org/fx" ) @@ -59,6 +61,14 @@ type CheckpointingSub struct { tweakedValue []byte // minio config cpconfig *config.Checkpoint + // minio client + minioClient *minio.Client + // Bitcoin latest checkpoint + latestConfigCheckpoint types.TipSetKey + // Is synced + synced bool + // height verified! + height abi.ChainEpoch } func NewCheckpointSub( @@ -84,12 +94,14 @@ func NewCheckpointSub( cpconfig := result.(*config.FullNode).Checkpoint + synced := false var config *keygen.TaprootConfig // Load configTaproot if _, err := os.Stat(os.Getenv("EUDICO_PATH") + "/share.toml"); errors.Is(err, os.ErrNotExist) { // path/to/whatever does not exist fmt.Println("No share file saved") } else { + synced = true content, err := os.ReadFile(os.Getenv("EUDICO_PATH") + "/share.toml") if err != nil { return nil, err @@ -119,13 +131,8 @@ func NewCheckpointSub( verificationShares := make(map[party.ID]*curve.Secp256k1Point) - fmt.Println(configTOML.VerificationShares) - for key, vshare := range configTOML.VerificationShares { - fmt.Println(key) - fmt.Println(vshare) - var p curve.Secp256k1Point pByte, err := hex.DecodeString(vshare.Share) if err != nil { @@ -147,18 +154,29 @@ func NewCheckpointSub( } } + // Initialize minio client object. + minioClient, err := minio.New(cpconfig.MinioHost, &minio.Options{ + Creds: credentials.NewStaticV4(cpconfig.MinioAccessKeyID, cpconfig.MinioSecretAccessKey, ""), + Secure: false, + }) + if err != nil { + return nil, err + } + return &CheckpointingSub{ - pubsub: pubsub, - topic: nil, - sub: nil, - host: host, - api: &api, - events: e, - init: false, - ptxid: "", - config: config, - newconfig: nil, - cpconfig: &cpconfig, + pubsub: pubsub, + topic: nil, + sub: nil, + host: host, + api: &api, + events: e, + init: false, + ptxid: "", + config: config, + newconfig: nil, + cpconfig: &cpconfig, + minioClient: minioClient, + synced: synced, }, nil } @@ -185,13 +203,11 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { handler, err := protocol.NewMultiHandler(f, []byte{1, 2, 3}) if err != nil { - fmt.Println(err) panic(err) } c.LoopHandler(ctx, handler, n) r, err := handler.Result() if err != nil { - fmt.Println(err) panic(err) } fmt.Println("Result :", r) @@ -206,6 +222,32 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { } match := func(oldTs, newTs *types.TipSet) (bool, events.StateChange, error) { + // verify we are synced + st, err := c.api.SyncState(ctx) + if err != nil { + panic(err) + } + //fmt.Println(st.ActiveSyncs) + + if !c.synced { + // Are we synced ? + if len(st.ActiveSyncs) > 0 && + st.ActiveSyncs[len(st.ActiveSyncs)-1].Height == newTs.Height() { + + fmt.Println("We are synced") + // Yes then verify our checkpoint + ts, err := c.api.ChainGetTipSet(ctx, c.latestConfigCheckpoint) + if err != nil { + panic(err) + } + fmt.Println("We have a checkpoint up to height : ", ts.Height()) + c.synced = true + c.height = ts.Height() + } else { + return false, nil, nil + } + } + newAct, err := c.api.StateGetActor(ctx, mpower.PowerActorAddr, newTs.Key()) if err != nil { return false, nil, err @@ -227,8 +269,9 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { return false, nil, err } - // If Power Actors list has changed start DKG - if !c.init { + // Init with the first checkpoint for the demo + // Should be done outside of it ? + if !c.init && c.config != nil { ts, err := c.api.ChainGetTipSetByHeight(ctx, 0, oldTs.Key()) if err != nil { panic(err) @@ -241,36 +284,36 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { return false, nil, nil } - // ZONDAX TODO - // Activate checkpointing every 20 blocks + // Activate checkpointing every 30 blocks fmt.Println("Height:", newTs.Height()) - if newTs.Height()%20 == 0 { + if newTs.Height()%30 == 0 && c.config != nil { fmt.Println("Check point time") // Initiation and config should be happening at start - if c.init && c.config != nil { - - data := oldTs.Cids()[0] + if c.init { + data := oldTs.Key().Bytes() - var partyList string = "" + var config string = hex.EncodeToString(data) + "\n" for _, partyId := range c.orderParticipantsList() { - partyList += partyId + "\n" + config += partyId + "\n" } - hash, err := CreateConfig([]byte(partyList)) + + hash, err := CreateConfig([]byte(config)) if err != nil { panic(err) } // Push config to S3 - err = StoreConfig(ctx, c.cpconfig.MinioHost, c.cpconfig.MinioAccessKeyID, c.cpconfig.MinioSecretAccessKey, c.cpconfig.MinioBucketName ,hex.EncodeToString(hash)) + err = StoreConfig(ctx, c.minioClient, c.cpconfig.MinioBucketName, hex.EncodeToString(hash)) if err != nil { panic(err) } - c.CreateCheckpoint(ctx, data.Bytes(), hash) + go c.CreateCheckpoint(ctx, data, hash) } } + // If Power Actors list has changed start DKG // Changes detected so generate new key if oldSt.MinerCount != newSt.MinerCount { fmt.Println("Generate new config") @@ -340,7 +383,7 @@ func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, cp, data []byte if c.ptxid == "" { fmt.Println("Missing precedent txid") taprootScript := GetTaprootScript(c.pubkey) - success := AddTaprootScriptToWallet(taprootScript) + success := AddTaprootToWallet(taprootScript) if !success { panic("failed to add taproot address to wallet") } @@ -514,6 +557,37 @@ func BuildCheckpointingSub(mctx helpers.MetricsCtx, lc fx.Lifecycle, c *Checkpoi fmt.Println("Successfully pinged bitcoind") + LoadWallet() + + // Get first checkpoint from block 0 + ts, err := c.api.ChainGetGenesis(ctx) + if err != nil { + panic(err) + } + cidBytes := ts.Key().Bytes() + publickey, err := hex.DecodeString(c.cpconfig.PublicKey) + if err != nil { + panic(err) + } + + btccp := GetLatestCheckpoint(publickey, cidBytes) + + fmt.Println(btccp) + + cp, err := GetConfig(ctx, c.minioClient, c.cpconfig.MinioBucketName, btccp.cid) + + fmt.Println(cp) + if cp != "" { + cpBytes, err := hex.DecodeString(cp) + if err != nil { + panic(err) + } + c.latestConfigCheckpoint, err = types.TipSetKeyFromBytes(cpBytes) + if err != nil { + panic(err) + } + } + c.Start(ctx) lc.Append(fx.Hook{ diff --git a/chain/checkpointing/util.go b/chain/checkpointing/util.go index 9b1017da8..fc840e5ac 100644 --- a/chain/checkpointing/util.go +++ b/chain/checkpointing/util.go @@ -50,9 +50,6 @@ func TaprootSignatureHash(tx []byte, utxo []byte, hash_type byte) ([]byte, error return nil, errors.New("only support SIGHASH_DEFAULT (0x00)") } - fmt.Println(hex.EncodeToString(tx)) - fmt.Println(hex.EncodeToString(utxo)) - var ss []byte ext_flag := 0x00 @@ -167,7 +164,7 @@ func GenCheckpointPublicKeyTaproot(internal_pubkey []byte, checkpoint []byte) [] return tweaked_pubkey } -func AddTaprootScriptToWallet(taprootScript string) bool { +func AddTaprootToWallet(taprootScript string) bool { payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"importaddress\", \"params\": [\"" + taprootScript + "\", \"\", true]}" result := jsonRPC(payload) @@ -189,15 +186,17 @@ func GetTaprootScript(pubkey []byte) string { return "5120" + hex.EncodeToString(pubkey) } -// Temporary -func BitcoindGetWalletAddress() string { +func LoadWallet() { // Create wallet payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"createwallet\", \"params\": [\"wow\"]}" _ = jsonRPC(payload) - // We don't cehck error here + // We don't check error here +} +// Temporary +func BitcoindGetWalletAddress() string { //Get new address - payload = "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"getnewaddress\", \"params\": []}" + payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"getnewaddress\", \"params\": []}" result := jsonRPC(payload) address := fmt.Sprintf("%v", result["result"]) @@ -226,7 +225,6 @@ func BitcoindPing() bool { func PrepareWitnessRawTransaction(rawtx string, sig []byte) string { wtx := rawtx[:4*2] + "00" + "01" + rawtx[4*2:len(rawtx)-4*2] + "01" + "40" + hex.EncodeToString(sig) + rawtx[len(rawtx)-4*2:] - fmt.Println("Raw transaction signed :", wtx) return wtx } @@ -238,7 +236,6 @@ func ParseUnspentTxOut(utxo []byte) (amount, script []byte) { func GetTxOut(txid string, index int) (float64, []byte) { payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"gettxout\", \"params\": [\"" + txid + "\", " + strconv.Itoa(index) + "]}" result := jsonRPC(payload) - fmt.Println(result) if result == nil { panic("cant retrieve previous transaction") } diff --git a/chain/checkpointing/verification.go b/chain/checkpointing/verification.go new file mode 100644 index 000000000..effe1939e --- /dev/null +++ b/chain/checkpointing/verification.go @@ -0,0 +1,86 @@ +package checkpointing + +import ( + "errors" +) + +type BitcoinTx struct { + txid string + value string +} + +type Checkpoint struct { + txid string + address string + cid string +} + +func GetFirstCheckpointAddress(taprootAddress string) (Checkpoint, error) { + payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"listtransactions\", \"params\": [\"*\", 500000000, 0, true]}" + result := jsonRPC(payload) + list := result["result"].([]interface{}) + for _, item := range list { + item_map := item.(map[string]interface{}) + if item_map["address"] == taprootAddress { + tx_id := item_map["txid"].(string) + payload = "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"getrawtransaction\", \"params\": [\"" + tx_id + "\", true]}" + result = jsonRPC(payload) + reader := result["result"].(map[string]interface{}) + + vout := reader["vout"].([]interface{}) + taprootOut := vout[0].(map[string]interface{})["scriptPubKey"].(map[string]interface{}) + new_address := taprootOut["hex"].(string) + + cidOut := vout[1].(map[string]interface{})["scriptPubKey"].(map[string]interface{}) + cid := cidOut["hex"].(string) + return Checkpoint{txid: tx_id, address: new_address, cid: cid[4:]}, nil + } + } + return Checkpoint{}, errors.New("Did not find checkpoint") +} + +func GetNextCheckpointFixed(txid string) (Checkpoint, error) { + payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"listtransactions\", \"params\": [\"*\", 500000000, 0, true]}" + result := jsonRPC(payload) + list := result["result"].([]interface{}) + for _, item := range list { + item_map := item.(map[string]interface{}) + tx_id := item_map["txid"].(string) + payload = "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"getrawtransaction\", \"params\": [\"" + tx_id + "\", true]}" + result = jsonRPC(payload) + reader := result["result"].(map[string]interface{}) + new_txid := reader["txid"].(string) + vin := reader["vin"].([]interface{})[0].(map[string]interface{})["txid"] + if vin == nil { + continue + } + if vin.(string) == txid { + vout := reader["vout"].([]interface{}) + taprootOut := vout[0].(map[string]interface{})["scriptPubKey"].(map[string]interface{}) + new_address := taprootOut["hex"].(string) + cidOut := vout[1].(map[string]interface{})["scriptPubKey"].(map[string]interface{}) + cid := cidOut["hex"].(string) + return Checkpoint{txid: new_txid, address: new_address, cid: cid[4:]}, nil + } + } + return Checkpoint{}, errors.New("Did not find checkpoint") +} + +func GetLatestCheckpoint(first_pk []byte, first_cp []byte) Checkpoint { + first_pubkeyTaproot := GenCheckpointPublicKeyTaproot(first_pk, first_cp) + firstscript := GetTaprootScript(first_pubkeyTaproot) + taprootAddress := PubkeyToTapprootAddress(first_pubkeyTaproot) + AddTaprootToWallet(firstscript) + checkpoint, done := GetFirstCheckpointAddress(taprootAddress) + AddTaprootToWallet(checkpoint.address) + var new_checkpoint Checkpoint + for { + new_checkpoint, done = GetNextCheckpointFixed(checkpoint.txid) + if done == nil { + checkpoint = new_checkpoint + AddTaprootToWallet(checkpoint.address) + } else { + return checkpoint + } + } +} diff --git a/data/alice/config.toml b/data/alice/config.toml index f780f7bb7..e5e02ee55 100644 --- a/data/alice/config.toml +++ b/data/alice/config.toml @@ -186,6 +186,7 @@ [Checkpoint] Fee = 0.01 + PublicKey="66a554b8af6719851a936b0afc29dc59c3678f0e3f0b7bb081c57c5b77ad48ff" MinioHost = "127.0.0.1:9000" MinioAccessKeyID = "JLVSCVFWEPJGTFL67Z4C" MinioSecretAccessKey = "4MjUvWBrtzYdJESCBQF+CYWKzhagvUZn2WRqkHnz" diff --git a/data/bob/config.toml b/data/bob/config.toml index 11b5d0cb9..d6c0a5291 100644 --- a/data/bob/config.toml +++ b/data/bob/config.toml @@ -186,6 +186,7 @@ [Checkpoint] Fee = 0.01 + PublicKey="66a554b8af6719851a936b0afc29dc59c3678f0e3f0b7bb081c57c5b77ad48ff" MinioHost = "127.0.0.1:9000" MinioAccessKeyID = "JLVSCVFWEPJGTFL67Z4C" MinioSecretAccessKey = "4MjUvWBrtzYdJESCBQF+CYWKzhagvUZn2WRqkHnz" diff --git a/data/charlie/config.toml b/data/charlie/config.toml index ba06ea354..4c9a27331 100644 --- a/data/charlie/config.toml +++ b/data/charlie/config.toml @@ -186,6 +186,7 @@ [Checkpoint] Fee = 0.01 + PublicKey="66a554b8af6719851a936b0afc29dc59c3678f0e3f0b7bb081c57c5b77ad48ff" MinioHost = "127.0.0.1:9000" MinioAccessKeyID = "JLVSCVFWEPJGTFL67Z4C" MinioSecretAccessKey = "4MjUvWBrtzYdJESCBQF+CYWKzhagvUZn2WRqkHnz" diff --git a/data/dom/config.toml b/data/dom/config.toml new file mode 100644 index 000000000..ee92969d3 --- /dev/null +++ b/data/dom/config.toml @@ -0,0 +1,195 @@ +[API] + # Binding address for the Lotus API + # + # type: string + # env var: LOTUS_API_LISTENADDRESS + ListenAddress = "/ip4/127.0.0.1/tcp/1237/http" + + # type: string + # env var: LOTUS_API_REMOTELISTENADDRESS + #RemoteListenAddress = "" + + # type: Duration + # env var: LOTUS_API_TIMEOUT + #Timeout = "30s" + + +[Backup] + # Note that in case of metadata corruption it might be much harder to recover + # your node if metadata log is disabled + # + # type: bool + # env var: LOTUS_BACKUP_DISABLEMETADATALOG + #DisableMetadataLog = false + + +[Libp2p] + # Binding address for the libp2p host - 0 means random port. + # Format: multiaddress; see https://multiformats.io/multiaddr/ + # + # type: []string + # env var: LOTUS_LIBP2P_LISTENADDRESSES + ListenAddresses = ["/ip4/0.0.0.0/tcp/0", "/ip6/::/tcp/0"] + + # Addresses to explicitally announce to other peers. If not specified, + # all interface addresses are announced + # Format: multiaddress + # + # type: []string + # env var: LOTUS_LIBP2P_ANNOUNCEADDRESSES + #AnnounceAddresses = [] + + # Addresses to not announce + # Format: multiaddress + # + # type: []string + # env var: LOTUS_LIBP2P_NOANNOUNCEADDRESSES + #NoAnnounceAddresses = [] + + # When not disabled (default), lotus asks NAT devices (e.g., routers), to + # open up an external port and forward it to the port lotus is running on. + # When this works (i.e., when your router supports NAT port forwarding), + # it makes the local lotus node accessible from the public internet + # + # type: bool + # env var: LOTUS_LIBP2P_DISABLENATPORTMAP + #DisableNatPortMap = false + + # ConnMgrLow is the number of connections that the basic connection manager + # will trim down to. + # + # type: uint + # env var: LOTUS_LIBP2P_CONNMGRLOW + #ConnMgrLow = 150 + + # ConnMgrHigh is the number of connections that, when exceeded, will trigger + # a connection GC operation. Note: protected/recently formed connections don't + # count towards this limit. + # + # type: uint + # env var: LOTUS_LIBP2P_CONNMGRHIGH + #ConnMgrHigh = 180 + + # ConnMgrGrace is a time duration that new connections are immune from being + # closed by the connection manager. + # + # type: Duration + # env var: LOTUS_LIBP2P_CONNMGRGRACE + #ConnMgrGrace = "20s" + + +[Pubsub] + # Run the node in bootstrap-node mode + # + # type: bool + # env var: LOTUS_PUBSUB_BOOTSTRAPPER + #Bootstrapper = false + + # type: string + # env var: LOTUS_PUBSUB_REMOTETRACER + #RemoteTracer = "" + + +[Client] + # type: bool + # env var: LOTUS_CLIENT_USEIPFS + #UseIpfs = false + + # type: bool + # env var: LOTUS_CLIENT_IPFSONLINEMODE + #IpfsOnlineMode = false + + # type: string + # env var: LOTUS_CLIENT_IPFSMADDR + #IpfsMAddr = "" + + # type: bool + # env var: LOTUS_CLIENT_IPFSUSEFORRETRIEVAL + #IpfsUseForRetrieval = false + + # The maximum number of simultaneous data transfers between the client + # and storage providers for storage deals + # + # type: uint64 + # env var: LOTUS_CLIENT_SIMULTANEOUSTRANSFERSFORSTORAGE + #SimultaneousTransfersForStorage = 20 + + # The maximum number of simultaneous data transfers between the client + # and storage providers for retrieval deals + # + # type: uint64 + # env var: LOTUS_CLIENT_SIMULTANEOUSTRANSFERSFORRETRIEVAL + #SimultaneousTransfersForRetrieval = 20 + + +[Wallet] + # type: string + # env var: LOTUS_WALLET_REMOTEBACKEND + #RemoteBackend = "" + + # type: bool + # env var: LOTUS_WALLET_ENABLELEDGER + #EnableLedger = false + + # type: bool + # env var: LOTUS_WALLET_DISABLELOCAL + #DisableLocal = false + + +[Fees] + # type: types.FIL + # env var: LOTUS_FEES_DEFAULTMAXFEE + #DefaultMaxFee = "0.07 FIL" + + +[Chainstore] + # type: bool + # env var: LOTUS_CHAINSTORE_ENABLESPLITSTORE + #EnableSplitstore = false + + [Chainstore.Splitstore] + # ColdStoreType specifies the type of the coldstore. + # It can be "universal" (default) or "discard" for discarding cold blocks. + # + # type: string + # env var: LOTUS_CHAINSTORE_SPLITSTORE_COLDSTORETYPE + #ColdStoreType = "universal" + + # HotStoreType specifies the type of the hotstore. + # Only currently supported value is "badger". + # + # type: string + # env var: LOTUS_CHAINSTORE_SPLITSTORE_HOTSTORETYPE + #HotStoreType = "badger" + + # MarkSetType specifies the type of the markset. + # It can be "map" (default) for in memory marking or "badger" for on-disk marking. + # + # type: string + # env var: LOTUS_CHAINSTORE_SPLITSTORE_MARKSETTYPE + #MarkSetType = "map" + + # HotStoreMessageRetention specifies the retention policy for messages, in finalities beyond + # the compaction boundary; default is 0. + # + # type: uint64 + # env var: LOTUS_CHAINSTORE_SPLITSTORE_HOTSTOREMESSAGERETENTION + #HotStoreMessageRetention = 0 + + # HotStoreFullGCFrequency specifies how often to perform a full (moving) GC on the hotstore. + # A value of 0 disables, while a value 1 will do full GC in every compaction. + # Default is 20 (about once a week). + # + # type: uint64 + # env var: LOTUS_CHAINSTORE_SPLITSTORE_HOTSTOREFULLGCFREQUENCY + #HotStoreFullGCFrequency = 20 + + +[Checkpoint] + Fee = 0.01 + PublicKey="66a554b8af6719851a936b0afc29dc59c3678f0e3f0b7bb081c57c5b77ad48ff" + MinioHost = "127.0.0.1:9000" + MinioAccessKeyID = "JLVSCVFWEPJGTFL67Z4C" + MinioSecretAccessKey = "4MjUvWBrtzYdJESCBQF+CYWKzhagvUZn2WRqkHnz" + MinioBucketName = "eudico" + diff --git a/data/dom/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU b/data/dom/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU new file mode 100644 index 000000000..a48b91486 --- /dev/null +++ b/data/dom/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU @@ -0,0 +1 @@ +{"Type":"jwt-hmac-secret","PrivateKey":"2dLb0u762Yl4grYXYJNwLyf+Iy1uuRwZ1t36151wOb8="} \ No newline at end of file diff --git a/data/dom/keystore/NRUWE4BSOAWWQ33TOQ b/data/dom/keystore/NRUWE4BSOAWWQ33TOQ new file mode 100644 index 000000000..84b4b07e5 --- /dev/null +++ b/data/dom/keystore/NRUWE4BSOAWWQ33TOQ @@ -0,0 +1 @@ +{"Type":"libp2p-host","PrivateKey":"CAESQG9g5EcVv0mltdtjatOpGUnBpb/0pYysTSjcsZYbbNE0/L75FuQoOE/areMjh83oo5aaFWALMIA3+ZrczqHnQ3Y="} \ No newline at end of file diff --git a/data/dom/token b/data/dom/token new file mode 100644 index 000000000..a5186b816 --- /dev/null +++ b/data/dom/token @@ -0,0 +1 @@ +eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJBbGxvdyI6WyJyZWFkIiwid3JpdGUiLCJzaWduIiwiYWRtaW4iXX0.97sLtihGv3qKbl3X9iCbc8FHk_lrF2JseXC2ad2nIME \ No newline at end of file diff --git a/node/config/types.go b/node/config/types.go index c40fab2e2..339cd93e4 100644 --- a/node/config/types.go +++ b/node/config/types.go @@ -385,9 +385,10 @@ type FeeConfig struct { } type Checkpoint struct { - Fee float64 - MinioHost string - MinioAccessKeyID string + Fee float64 + PublicKey string + MinioHost string + MinioAccessKeyID string MinioSecretAccessKey string - MinioBucketName string -} \ No newline at end of file + MinioBucketName string +} diff --git a/scripts/data-clean.sh b/scripts/data-clean.sh new file mode 100755 index 000000000..6d3985821 --- /dev/null +++ b/scripts/data-clean.sh @@ -0,0 +1,31 @@ +rm -rf data/dom/data-transfer +rm -rf data/dom/datastore +rm -rf data/dom/heapprof +rm -rf data/dom/imports +rm -rf data/dom/journal +rm -rf data/dom/kvlog +rm -rf data/dom/retrievals + +rm -rf data/alice/data-transfer +rm -rf data/alice/datastore +rm -rf data/alice/heapprof +rm -rf data/alice/imports +rm -rf data/alice/journal +rm -rf data/alice/kvlog +rm -rf data/alice/retrievals + +rm -rf data/bob/data-transfer +rm -rf data/bob/datastore +rm -rf data/bob/heapprof +rm -rf data/bob/imports +rm -rf data/bob/journal +rm -rf data/bob/kvlog +rm -rf data/bob/retrievals + +rm -rf data/charlie/data-transfer +rm -rf data/charlie/datastore +rm -rf data/charlie/heapprof +rm -rf data/charlie/imports +rm -rf data/charlie/journal +rm -rf data/charlie/kvlog +rm -rf data/charlie/retrievals \ No newline at end of file diff --git a/scripts/data-permissions.sh b/scripts/data-permissions.sh index 14e9c0198..47b416906 100755 --- a/scripts/data-permissions.sh +++ b/scripts/data-permissions.sh @@ -1,3 +1,4 @@ chmod 600 data/alice/keystore/* chmod 600 data/bob/keystore/* -chmod 600 data/charlie/keystore/* \ No newline at end of file +chmod 600 data/charlie/keystore/* +chmod 600 data/dom/keystore/* \ No newline at end of file diff --git a/scripts/verification.sh b/scripts/verification.sh new file mode 100755 index 000000000..c048f3cca --- /dev/null +++ b/scripts/verification.sh @@ -0,0 +1,5 @@ +#! /bin/bash + +tmux \ + new-session 'EUDICO_PATH=$PWD/data/dom ./eudico delegated daemon --genesis=gen.gen; sleep infinity' \; \ + split-window 'EUDICO_PATH=$PWD/data/dom ./eudico wait-api; EUDICO_PATH=$PWD/data/dom ./eudico net connect /ip4/127.0.0.1/tcp/3000/p2p/12D3KooWMBbLLKTM9Voo89TXLd98w4MjkJUych6QvECptousGtR4; sleep 3' \; \ From 3968398603e86483c69e828e22c542203be224c1 Mon Sep 17 00:00:00 2001 From: sleepy ramen Date: Tue, 14 Dec 2021 22:13:11 +0100 Subject: [PATCH 11/23] use minio predefined user/password (#11) --- data/alice/config.toml | 4 ++-- data/bob/config.toml | 4 ++-- data/charlie/config.toml | 4 ++-- data/dom/config.toml | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/data/alice/config.toml b/data/alice/config.toml index e5e02ee55..77d2b3b47 100644 --- a/data/alice/config.toml +++ b/data/alice/config.toml @@ -188,6 +188,6 @@ Fee = 0.01 PublicKey="66a554b8af6719851a936b0afc29dc59c3678f0e3f0b7bb081c57c5b77ad48ff" MinioHost = "127.0.0.1:9000" - MinioAccessKeyID = "JLVSCVFWEPJGTFL67Z4C" - MinioSecretAccessKey = "4MjUvWBrtzYdJESCBQF+CYWKzhagvUZn2WRqkHnz" + MinioAccessKeyID = "lola" + MinioSecretAccessKey = "123secure" MinioBucketName = "eudico" \ No newline at end of file diff --git a/data/bob/config.toml b/data/bob/config.toml index d6c0a5291..494e3597d 100644 --- a/data/bob/config.toml +++ b/data/bob/config.toml @@ -188,6 +188,6 @@ Fee = 0.01 PublicKey="66a554b8af6719851a936b0afc29dc59c3678f0e3f0b7bb081c57c5b77ad48ff" MinioHost = "127.0.0.1:9000" - MinioAccessKeyID = "JLVSCVFWEPJGTFL67Z4C" - MinioSecretAccessKey = "4MjUvWBrtzYdJESCBQF+CYWKzhagvUZn2WRqkHnz" + MinioAccessKeyID = "lola" + MinioSecretAccessKey = "123secure" MinioBucketName = "eudico" \ No newline at end of file diff --git a/data/charlie/config.toml b/data/charlie/config.toml index 4c9a27331..cfb26a3d0 100644 --- a/data/charlie/config.toml +++ b/data/charlie/config.toml @@ -188,6 +188,6 @@ Fee = 0.01 PublicKey="66a554b8af6719851a936b0afc29dc59c3678f0e3f0b7bb081c57c5b77ad48ff" MinioHost = "127.0.0.1:9000" - MinioAccessKeyID = "JLVSCVFWEPJGTFL67Z4C" - MinioSecretAccessKey = "4MjUvWBrtzYdJESCBQF+CYWKzhagvUZn2WRqkHnz" + MinioAccessKeyID = "lola" + MinioSecretAccessKey = "123secure" MinioBucketName = "eudico" \ No newline at end of file diff --git a/data/dom/config.toml b/data/dom/config.toml index ee92969d3..6714688ff 100644 --- a/data/dom/config.toml +++ b/data/dom/config.toml @@ -189,7 +189,7 @@ Fee = 0.01 PublicKey="66a554b8af6719851a936b0afc29dc59c3678f0e3f0b7bb081c57c5b77ad48ff" MinioHost = "127.0.0.1:9000" - MinioAccessKeyID = "JLVSCVFWEPJGTFL67Z4C" - MinioSecretAccessKey = "4MjUvWBrtzYdJESCBQF+CYWKzhagvUZn2WRqkHnz" + MinioAccessKeyID = "lola" + MinioSecretAccessKey = "123secure" MinioBucketName = "eudico" From 1de9d0f773e49b61cd405add93c3c28c9f74cb38 Mon Sep 17 00:00:00 2001 From: sleepy ramen Date: Wed, 22 Dec 2021 20:09:53 +0100 Subject: [PATCH 12/23] Several improvements for demo (#12) --- chain/checkpointing/network.go | 57 ++++- chain/checkpointing/storage.go | 2 +- chain/checkpointing/sub.go | 248 +++++++++++-------- chain/checkpointing/util.go | 42 ++-- chain/checkpointing/verification.go | 32 +-- chain/consensus/actors/mpower/power_actor.go | 2 + data/alice/config.toml | 7 +- data/bob/config.toml | 7 +- data/charlie/config.toml | 7 +- data/dom/config.toml | 3 +- node/config/types.go | 1 + scripts/verification.sh | 2 +- 12 files changed, 262 insertions(+), 148 deletions(-) diff --git a/chain/checkpointing/network.go b/chain/checkpointing/network.go index fbc203d50..67a051eb2 100644 --- a/chain/checkpointing/network.go +++ b/chain/checkpointing/network.go @@ -26,6 +26,11 @@ func NewNetwork(parties party.IDSlice, sub *pubsub.Subscription, topic *pubsub.T func (n *Network) Next(ctx context.Context) *protocol.Message { msg, err := n.sub.Next(ctx) + if err == context.Canceled { + // We are actually done and don't want to wait for messages anymore + return nil + } + if err != nil { panic(err) } @@ -47,7 +52,10 @@ func (n *Network) Send(ctx context.Context, msg *protocol.Message) { if err != nil { panic(err) } - n.topic.Publish(ctx, data) + err = n.topic.Publish(ctx, data) + if err != nil { + panic(err) + } } func (n *Network) Done() { @@ -59,3 +67,50 @@ func (n *Network) Done() { func (n *Network) Parties() party.IDSlice { return n.parties } + +/* + Handling incoming and outgoing messages +*/ + +func broadcastingMessage(ctx context.Context, h protocol.Handler, network *Network, over chan bool) { + for { + msg, ok := <-h.Listen() + fmt.Println("Outgoing message:", msg) + if !ok { + network.Done() + // the channel was closed, indicating that the protocol is done executing. + close(over) + return + } + network.Send(ctx, msg) + } +} + +func waitingMessages(ctx context.Context, h protocol.Handler, network *Network, over chan bool) { + for { + select { + case <-over: + return + default: + msg := network.Next(ctx) + if h.CanAccept(msg) { + // This message is ours + fmt.Println("Incoming message:", msg) + } + h.Accept(msg) + } + + } +} + +func LoopHandler(ctx context.Context, h protocol.Handler, network *Network) { + over := make(chan bool) + + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + go broadcastingMessage(ctx, h, network, over) + go waitingMessages(ctx, h, network, over) + + <-over +} diff --git a/chain/checkpointing/storage.go b/chain/checkpointing/storage.go index 4f353da44..6af5bce98 100644 --- a/chain/checkpointing/storage.go +++ b/chain/checkpointing/storage.go @@ -38,7 +38,7 @@ func CreateConfig(data []byte) ([]byte, error) { func GetConfig(ctx context.Context, minioClient *minio.Client, bucketName, hash string) (string, error) { filename := hash + ".txt" - filePath := "/tmp/dom/" + filename + filePath := "/tmp/verification/" + filename err := minioClient.FGetObject(context.Background(), bucketName, filename, filePath, minio.GetObjectOptions{}) if err != nil { diff --git a/chain/checkpointing/sub.go b/chain/checkpointing/sub.go index 8cd5a859f..4c326ceef 100644 --- a/chain/checkpointing/sub.go +++ b/chain/checkpointing/sub.go @@ -9,6 +9,7 @@ import ( "os" "sort" "strconv" + "sync" "github.com/BurntSushi/toml" "github.com/Zondax/multi-party-sig/pkg/math/curve" @@ -28,6 +29,7 @@ import ( cbor "github.com/ipfs/go-ipld-cbor" logging "github.com/ipfs/go-log/v2" "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/peer" pubsub "github.com/libp2p/go-libp2p-pubsub" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" @@ -47,10 +49,15 @@ type CheckpointingSub struct { api *impl.FullNodeAPI // Listener for events of the root chain. events *events.Events + // lock + lk sync.Mutex + // Generated public key pubkey []byte // taproot config config *keygen.TaprootConfig + // miners + minerSigners []peer.ID // new config generated newconfig *keygen.TaprootConfig // Initiated @@ -86,6 +93,8 @@ func NewCheckpointSub( return nil, err } + fmt.Println("EUDICO PATH :", os.Getenv("EUDICO_PATH")) + var ccfg config.FullNode result, err := config.FromFile(os.Getenv("EUDICO_PATH")+"/config.toml", &ccfg) if err != nil { @@ -94,6 +103,9 @@ func NewCheckpointSub( cpconfig := result.(*config.FullNode).Checkpoint + // initiate miners signers array + var minerSigners []peer.ID + synced := false var config *keygen.TaprootConfig // Load configTaproot @@ -152,6 +164,12 @@ func NewCheckpointSub( PublicKey: publickey, VerificationShares: verificationShares, } + + for id := range config.VerificationShares { + minerSigners = append(minerSigners, peer.ID(id)) + } + + fmt.Println(minerSigners) } // Initialize minio client object. @@ -164,19 +182,20 @@ func NewCheckpointSub( } return &CheckpointingSub{ - pubsub: pubsub, - topic: nil, - sub: nil, - host: host, - api: &api, - events: e, - init: false, - ptxid: "", - config: config, - newconfig: nil, - cpconfig: &cpconfig, - minioClient: minioClient, - synced: synced, + pubsub: pubsub, + topic: nil, + sub: nil, + host: host, + api: &api, + events: e, + init: false, + ptxid: "", + config: config, + minerSigners: minerSigners, + newconfig: nil, + cpconfig: &cpconfig, + minioClient: minioClient, + synced: synced, }, nil } @@ -189,31 +208,6 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { changeHandler := func(oldTs, newTs *types.TipSet, states events.StateChange, curH abi.ChainEpoch) (more bool, err error) { log.Infow("State change detected for power actor") - idsStrings := c.orderParticipantsList() - - fmt.Println("Participants list :", idsStrings) - - ids := c.formIDSlice(idsStrings) - - id := party.ID(c.host.ID().String()) - - threshold := 2 - n := NewNetwork(ids, c.sub, c.topic) - f := frost.KeygenTaproot(id, ids, threshold) - - handler, err := protocol.NewMultiHandler(f, []byte{1, 2, 3}) - if err != nil { - panic(err) - } - c.LoopHandler(ctx, handler, n) - r, err := handler.Result() - if err != nil { - panic(err) - } - fmt.Println("Result :", r) - - c.newconfig = r.(*keygen.TaprootConfig) - return true, nil } @@ -222,6 +216,9 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { } match := func(oldTs, newTs *types.TipSet) (bool, events.StateChange, error) { + c.lk.Lock() + defer c.lk.Unlock() + // verify we are synced st, err := c.api.SyncState(ctx) if err != nil { @@ -286,30 +283,48 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { // Activate checkpointing every 30 blocks fmt.Println("Height:", newTs.Height()) - if newTs.Height()%30 == 0 && c.config != nil { + // NOTES: this will only work in delegated consensus + // Wait for more tipset to valid the height and be sure it is valid + if newTs.Height()%25 == 0 && (c.config != nil || c.newconfig != nil) { fmt.Println("Check point time") // Initiation and config should be happening at start if c.init { - data := oldTs.Key().Bytes() - - var config string = hex.EncodeToString(data) + "\n" - for _, partyId := range c.orderParticipantsList() { - config += partyId + "\n" + cp := oldTs.Key().Bytes() + + // If we don't have a config we don't sign but update our config with key + if c.config == nil { + fmt.Println("We dont have a config") + pubkey := c.newconfig.PublicKey + + pubkeyShort := GenCheckpointPublicKeyTaproot(pubkey, cp) + + c.config = c.newconfig + merkleRoot := HashMerkleRoot(pubkey, cp) + c.tweakedValue = HashTweakedValue(pubkey, merkleRoot) + c.pubkey = pubkeyShort + c.newconfig = nil + + } else { + var config string = hex.EncodeToString(cp) + "\n" + for _, partyId := range c.orderParticipantsList() { + config += partyId + "\n" + } + + hash, err := CreateConfig([]byte(config)) + if err != nil { + panic(err) + } + + // Push config to S3 + err = StoreConfig(ctx, c.minioClient, c.cpconfig.MinioBucketName, hex.EncodeToString(hash)) + if err != nil { + panic(err) + } + + c.CreateCheckpoint(ctx, cp, hash) } - hash, err := CreateConfig([]byte(config)) - if err != nil { - panic(err) - } - - // Push config to S3 - err = StoreConfig(ctx, c.minioClient, c.cpconfig.MinioBucketName, hex.EncodeToString(hash)) - if err != nil { - panic(err) - } - - go c.CreateCheckpoint(ctx, data, hash) } } @@ -318,6 +333,8 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { if oldSt.MinerCount != newSt.MinerCount { fmt.Println("Generate new config") + c.GenerateNewKeys(ctx) + return true, nil, nil } @@ -347,30 +364,40 @@ func (c *CheckpointingSub) Start(ctx context.Context) { c.listenCheckpointEvents(ctx) } -func (c *CheckpointingSub) LoopHandler(ctx context.Context, h protocol.Handler, network *Network) { - for { - msg, ok := <-h.Listen() - if !ok { - network.Done() - // the channel was closed, indicating that the protocol is done executing. - fmt.Println("Should be good") - return - } - network.Send(ctx, msg) +func (c *CheckpointingSub) GenerateNewKeys(ctx context.Context) { - for _, _ = range network.Parties() { - msg = network.Next(ctx) - h.Accept(msg) - } + idsStrings := c.newOrderParticipantsList() + + fmt.Println("Participants list :", idsStrings) + + ids := c.formIDSlice(idsStrings) + + id := party.ID(c.host.ID().String()) + + threshold := (len(idsStrings) / 2) + 1 + n := NewNetwork(ids, c.sub, c.topic) + f := frost.KeygenTaproot(id, ids, threshold) + + handler, err := protocol.NewMultiHandler(f, []byte{1, 2, 3}) + if err != nil { + panic(err) + } + LoopHandler(ctx, handler, n) + r, err := handler.Result() + if err != nil { + panic(err) } + fmt.Println("Result :", r) + + c.newconfig = r.(*keygen.TaprootConfig) } func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, cp, data []byte) { - idsStrings := c.orderParticipantsList() - fmt.Println("Participants list :", idsStrings) - fmt.Println("Precedent tx", c.ptxid) - ids := c.formIDSlice(idsStrings) - taprootAddress := PubkeyToTapprootAddress(c.pubkey) + + taprootAddress, err := PubkeyToTapprootAddress(c.pubkey) + if err != nil { + panic(err) + } pubkey := c.config.PublicKey if c.newconfig != nil { @@ -378,18 +405,25 @@ func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, cp, data []byte } pubkeyShort := GenCheckpointPublicKeyTaproot(pubkey, cp) - newTaprootAddress := PubkeyToTapprootAddress(pubkeyShort) + newTaprootAddress, err := PubkeyToTapprootAddress(pubkeyShort) + if err != nil { + panic(err) + } + + idsStrings := c.orderParticipantsList() + fmt.Println("Participants list :", idsStrings) + fmt.Println("Precedent tx", c.ptxid) + ids := c.formIDSlice(idsStrings) if c.ptxid == "" { fmt.Println("Missing precedent txid") taprootScript := GetTaprootScript(c.pubkey) - success := AddTaprootToWallet(taprootScript) + success := AddTaprootToWallet(c.cpconfig.BitcoinHost, taprootScript) if !success { panic("failed to add taproot address to wallet") } - ptxid, err := WalletGetTxidFromAddress(taprootAddress) - fmt.Println(taprootAddress) + ptxid, err := WalletGetTxidFromAddress(c.cpconfig.BitcoinHost, taprootAddress) if err != nil { panic(err) } @@ -398,18 +432,17 @@ func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, cp, data []byte } index := 0 - value, scriptPubkeyBytes := GetTxOut(c.ptxid, index) + value, scriptPubkeyBytes := GetTxOut(c.cpconfig.BitcoinHost, c.ptxid, index) if scriptPubkeyBytes[0] != 0x51 { fmt.Println("Wrong txout") index = 1 - value, scriptPubkeyBytes = GetTxOut(c.ptxid, index) + value, scriptPubkeyBytes = GetTxOut(c.cpconfig.BitcoinHost, c.ptxid, index) } newValue := value - c.cpconfig.Fee payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"createrawtransaction\", \"params\": [[{\"txid\":\"" + c.ptxid + "\",\"vout\": " + strconv.Itoa(index) + ", \"sequence\": 4294967295}], [{\"" + newTaprootAddress + "\": \"" + fmt.Sprintf("%.2f", newValue) + "\"}, {\"data\": \"" + hex.EncodeToString(data) + "\"}]]}" - result := jsonRPC(payload) - fmt.Println(result) + result := jsonRPC(c.cpconfig.BitcoinHost, payload) if result == nil { panic("cant create new transaction") } @@ -435,13 +468,14 @@ func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, cp, data []byte * Orchestrate the signing message */ + fmt.Println("Starting signing") f := frost.SignTaprootWithTweak(c.config, ids, hashedTx[:], c.tweakedValue[:]) n := NewNetwork(ids, c.sub, c.topic) - handler, err := protocol.NewMultiHandler(f, []byte{1, 2, 3}) + handler, err := protocol.NewMultiHandler(f, hashedTx[:]) if err != nil { panic(err) } - c.LoopHandler(ctx, handler, n) + LoopHandler(ctx, handler, n) r, err := handler.Result() if err != nil { fmt.Println(err) @@ -467,14 +501,12 @@ func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, cp, data []byte rawtx := PrepareWitnessRawTransaction(rawTransaction, r.(taproot.Signature)) payload = "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"sendrawtransaction\", \"params\": [\"" + rawtx + "\"]}" - result = jsonRPC(payload) + result = jsonRPC(c.cpconfig.BitcoinHost, payload) if result["error"] != nil { fmt.Println(result) panic("failed to broadcast transaction") } - fmt.Println(result) - /* Need to keep this to build next one */ newtxid := result["result"].(string) fmt.Println("New Txid:", newtxid) @@ -482,14 +514,25 @@ func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, cp, data []byte } } -func (c *CheckpointingSub) orderParticipantsList() []string { +func (c *CheckpointingSub) newOrderParticipantsList() []string { id := c.host.ID().String() var ids []string ids = append(ids, id) - for _, p := range c.topic.ListPeers() { - ids = append(ids, p.String()) + for _, peerID := range c.topic.ListPeers() { + ids = append(ids, peerID.String()) + } + + sort.Strings(ids) + + return ids +} + +func (c *CheckpointingSub) orderParticipantsList() []string { + var ids []string + for id := range c.config.VerificationShares { + ids = append(ids, string(id)) } sort.Strings(ids) @@ -508,12 +551,15 @@ func (c *CheckpointingSub) formIDSlice(ids []string) party.IDSlice { return idsSlice } +// Temporary func (c *CheckpointingSub) prefundTaproot() error { - taprootAddress := PubkeyToTapprootAddress(c.pubkey) + taprootAddress, err := PubkeyToTapprootAddress(c.pubkey) + if err != nil { + return err + } payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"sendtoaddress\", \"params\": [\"" + taprootAddress + "\", 50]}" - result := jsonRPC(payload) - fmt.Println(result) + result := jsonRPC(c.cpconfig.BitcoinHost, payload) if result == nil { // Should probably not panic here return errors.New("couldn't create first transaction") @@ -549,7 +595,7 @@ func BuildCheckpointingSub(mctx helpers.MetricsCtx, lc fx.Lifecycle, c *Checkpoi ctx := helpers.LifecycleCtx(mctx, lc) // Ping to see if bitcoind is available - success := BitcoindPing() + success := BitcoindPing(c.cpconfig.BitcoinHost) if !success { // Should probably not panic here panic("Bitcoin node not available") @@ -557,7 +603,7 @@ func BuildCheckpointingSub(mctx helpers.MetricsCtx, lc fx.Lifecycle, c *Checkpoi fmt.Println("Successfully pinged bitcoind") - LoadWallet() + LoadWallet(c.cpconfig.BitcoinHost) // Get first checkpoint from block 0 ts, err := c.api.ChainGetGenesis(ctx) @@ -570,9 +616,10 @@ func BuildCheckpointingSub(mctx helpers.MetricsCtx, lc fx.Lifecycle, c *Checkpoi panic(err) } - btccp := GetLatestCheckpoint(publickey, cidBytes) - - fmt.Println(btccp) + btccp, err := GetLatestCheckpoint(c.cpconfig.BitcoinHost, publickey, cidBytes) + if err != nil { + panic(err) + } cp, err := GetConfig(ctx, c.minioClient, c.cpconfig.MinioBucketName, btccp.cid) @@ -586,6 +633,9 @@ func BuildCheckpointingSub(mctx helpers.MetricsCtx, lc fx.Lifecycle, c *Checkpoi if err != nil { panic(err) } + + // The first tx is in Bitcoin + c.init = true } c.Start(ctx) diff --git a/chain/checkpointing/util.go b/chain/checkpointing/util.go index fc840e5ac..9194305f0 100644 --- a/chain/checkpointing/util.go +++ b/chain/checkpointing/util.go @@ -90,11 +90,10 @@ func TaprootSignatureHash(tx []byte, utxo []byte, hash_type byte) ([]byte, error return TaggedHash("TapSighash", ss), nil } -func PubkeyToTapprootAddress(pubkey []byte) string { +func PubkeyToTapprootAddress(pubkey []byte) (string, error) { conv, err := bech32.ConvertBits(pubkey, 8, 5, true) if err != nil { - fmt.Println("Error:", err) - log.Fatal("I dunno.") + return "", err } // Add segwit version byte 1 @@ -104,13 +103,12 @@ func PubkeyToTapprootAddress(pubkey []byte) string { // Using EncodeM becasue we want bech32m... which has a new checksum taprootAddress, err := bech32.EncodeM("bcrt", conv) if err != nil { - fmt.Println(err) - log.Fatal("Couldn't produce our tapproot address.") + return "", err } - return taprootAddress + return taprootAddress, nil } -func PubkeyToTapprootAddressLegacy(pubkey []byte) string { +/*func PubkeyToTapprootAddressLegacy(pubkey []byte) string { conv, err := bech32.ConvertBits(pubkey, 8, 5, true) if err != nil { fmt.Println("Error:", err) @@ -125,7 +123,7 @@ func PubkeyToTapprootAddressLegacy(pubkey []byte) string { log.Fatal("Couldn't produce our tapproot address.") } return taprootAddressLegacy -} +}*/ func ApplyTweakToPublicKeyTaproot(public []byte, tweak []byte) []byte { group := curve.Secp256k1{} @@ -164,9 +162,9 @@ func GenCheckpointPublicKeyTaproot(internal_pubkey []byte, checkpoint []byte) [] return tweaked_pubkey } -func AddTaprootToWallet(taprootScript string) bool { +func AddTaprootToWallet(url, taprootScript string) bool { payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"importaddress\", \"params\": [\"" + taprootScript + "\", \"\", true]}" - result := jsonRPC(payload) + result := jsonRPC(url, payload) if result["error"] == nil { return true @@ -183,29 +181,30 @@ func AddTaprootToWallet(taprootScript string) bool { } func GetTaprootScript(pubkey []byte) string { + // 1 <20-size> pukey return "5120" + hex.EncodeToString(pubkey) } -func LoadWallet() { +func LoadWallet(url string) { // Create wallet payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"createwallet\", \"params\": [\"wow\"]}" - _ = jsonRPC(payload) + _ = jsonRPC(url, payload) // We don't check error here } // Temporary -func BitcoindGetWalletAddress() string { +func BitcoindGetWalletAddress(url string) string { //Get new address payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"getnewaddress\", \"params\": []}" - result := jsonRPC(payload) + result := jsonRPC(url, payload) address := fmt.Sprintf("%v", result["result"]) return address } -func WalletGetTxidFromAddress(taprootAddress string) (string, error) { +func WalletGetTxidFromAddress(url, taprootAddress string) (string, error) { payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"listtransactions\", \"params\": [\"*\", 500000000, 0, true]}" - result := jsonRPC(payload) + result := jsonRPC(url, payload) list := result["result"].([]interface{}) for _, item := range list { item_map := item.(map[string]interface{}) @@ -217,9 +216,9 @@ func WalletGetTxidFromAddress(taprootAddress string) (string, error) { return "", errors.New("did not find checkpoint") } -func BitcoindPing() bool { +func BitcoindPing(url string) bool { payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"ping\", \"params\": []}" - result := jsonRPC(payload) + result := jsonRPC(url, payload) return result != nil } @@ -233,9 +232,9 @@ func ParseUnspentTxOut(utxo []byte) (amount, script []byte) { return utxo[0:8], utxo[9:] } -func GetTxOut(txid string, index int) (float64, []byte) { +func GetTxOut(url, txid string, index int) (float64, []byte) { payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"gettxout\", \"params\": [\"" + txid + "\", " + strconv.Itoa(index) + "]}" - result := jsonRPC(payload) + result := jsonRPC(url, payload) if result == nil { panic("cant retrieve previous transaction") } @@ -246,10 +245,9 @@ func GetTxOut(txid string, index int) (float64, []byte) { return taprootTxOut["value"].(float64), scriptPubkeyBytes } -func jsonRPC(payload string) map[string]interface{} { +func jsonRPC(url, payload string) map[string]interface{} { // ZONDAX TODO // This needs to be in a config file - url := "http://127.0.0.1:18443" method := "POST" user := "satoshi" diff --git a/chain/checkpointing/verification.go b/chain/checkpointing/verification.go index effe1939e..a90ae4958 100644 --- a/chain/checkpointing/verification.go +++ b/chain/checkpointing/verification.go @@ -15,16 +15,16 @@ type Checkpoint struct { cid string } -func GetFirstCheckpointAddress(taprootAddress string) (Checkpoint, error) { +func GetFirstCheckpointAddress(url, taprootAddress string) (Checkpoint, error) { payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"listtransactions\", \"params\": [\"*\", 500000000, 0, true]}" - result := jsonRPC(payload) + result := jsonRPC(url, payload) list := result["result"].([]interface{}) for _, item := range list { item_map := item.(map[string]interface{}) if item_map["address"] == taprootAddress { tx_id := item_map["txid"].(string) payload = "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"getrawtransaction\", \"params\": [\"" + tx_id + "\", true]}" - result = jsonRPC(payload) + result = jsonRPC(url, payload) reader := result["result"].(map[string]interface{}) vout := reader["vout"].([]interface{}) @@ -39,15 +39,15 @@ func GetFirstCheckpointAddress(taprootAddress string) (Checkpoint, error) { return Checkpoint{}, errors.New("Did not find checkpoint") } -func GetNextCheckpointFixed(txid string) (Checkpoint, error) { +func GetNextCheckpointFixed(url, txid string) (Checkpoint, error) { payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"listtransactions\", \"params\": [\"*\", 500000000, 0, true]}" - result := jsonRPC(payload) + result := jsonRPC(url, payload) list := result["result"].([]interface{}) for _, item := range list { item_map := item.(map[string]interface{}) tx_id := item_map["txid"].(string) payload = "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"getrawtransaction\", \"params\": [\"" + tx_id + "\", true]}" - result = jsonRPC(payload) + result = jsonRPC(url, payload) reader := result["result"].(map[string]interface{}) new_txid := reader["txid"].(string) vin := reader["vin"].([]interface{})[0].(map[string]interface{})["txid"] @@ -66,21 +66,25 @@ func GetNextCheckpointFixed(txid string) (Checkpoint, error) { return Checkpoint{}, errors.New("Did not find checkpoint") } -func GetLatestCheckpoint(first_pk []byte, first_cp []byte) Checkpoint { +func GetLatestCheckpoint(url string, first_pk []byte, first_cp []byte) (*Checkpoint, error) { first_pubkeyTaproot := GenCheckpointPublicKeyTaproot(first_pk, first_cp) firstscript := GetTaprootScript(first_pubkeyTaproot) - taprootAddress := PubkeyToTapprootAddress(first_pubkeyTaproot) - AddTaprootToWallet(firstscript) - checkpoint, done := GetFirstCheckpointAddress(taprootAddress) - AddTaprootToWallet(checkpoint.address) + taprootAddress, err := PubkeyToTapprootAddress(first_pubkeyTaproot) + if err != nil { + return nil, err + } + + AddTaprootToWallet(url, firstscript) + checkpoint, done := GetFirstCheckpointAddress(url, taprootAddress) + AddTaprootToWallet(url, checkpoint.address) var new_checkpoint Checkpoint for { - new_checkpoint, done = GetNextCheckpointFixed(checkpoint.txid) + new_checkpoint, done = GetNextCheckpointFixed(url, checkpoint.txid) if done == nil { checkpoint = new_checkpoint - AddTaprootToWallet(checkpoint.address) + AddTaprootToWallet(url, checkpoint.address) } else { - return checkpoint + return &checkpoint, nil } } } diff --git a/chain/consensus/actors/mpower/power_actor.go b/chain/consensus/actors/mpower/power_actor.go index 8caa0e5c8..7186a7289 100644 --- a/chain/consensus/actors/mpower/power_actor.go +++ b/chain/consensus/actors/mpower/power_actor.go @@ -179,6 +179,8 @@ func (a Actor) UpdateClaimedPower(rt Runtime, params *UpdateClaimedPowerParams) claims, err := adt.AsMap(adt.AsStore(rt), st.Claims, builtin.DefaultHamtBitwidth) builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load claims") + st.MinerCount += 1 + err = st.addToClaim(claims, minerAddr, params.RawByteDelta, params.QualityAdjustedDelta) builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to update power raw %s, qa %s", params.RawByteDelta, params.QualityAdjustedDelta) diff --git a/data/alice/config.toml b/data/alice/config.toml index 77d2b3b47..32ff945a4 100644 --- a/data/alice/config.toml +++ b/data/alice/config.toml @@ -3,7 +3,7 @@ # # type: string # env var: LOTUS_API_LISTENADDRESS - ListenAddress = "/ip4/127.0.0.1/tcp/1234/http" + ListenAddress = "/ip4/0.0.0.0/tcp/1234/http" # type: string # env var: LOTUS_API_REMOTELISTENADDRESS @@ -29,7 +29,7 @@ # # type: []string # env var: LOTUS_LIBP2P_LISTENADDRESSES - ListenAddresses = ["/ip4/0.0.0.0/tcp/3000", "/ip6/::/tcp/3000"] + ListenAddresses = ["/ip4/0.0.0.0/tcp/3000"] # Addresses to explicitally announce to other peers. If not specified, # all interface addresses are announced @@ -186,8 +186,9 @@ [Checkpoint] Fee = 0.01 + BitcoinHost="http://btc-rpc:8332" PublicKey="66a554b8af6719851a936b0afc29dc59c3678f0e3f0b7bb081c57c5b77ad48ff" - MinioHost = "127.0.0.1:9000" + MinioHost = "minio:9000" MinioAccessKeyID = "lola" MinioSecretAccessKey = "123secure" MinioBucketName = "eudico" \ No newline at end of file diff --git a/data/bob/config.toml b/data/bob/config.toml index 494e3597d..a662bbe81 100644 --- a/data/bob/config.toml +++ b/data/bob/config.toml @@ -3,7 +3,7 @@ # # type: string # env var: LOTUS_API_LISTENADDRESS - ListenAddress = "/ip4/127.0.0.1/tcp/1235/http" + ListenAddress = "/ip4/0.0.0.0/tcp/1235/http" # type: string # env var: LOTUS_API_REMOTELISTENADDRESS @@ -29,7 +29,7 @@ # # type: []string # env var: LOTUS_LIBP2P_LISTENADDRESSES - ListenAddresses = ["/ip4/0.0.0.0/tcp/3001", "/ip6/::/tcp/3001"] + ListenAddresses = ["/ip4/0.0.0.0/tcp/3001"] # Addresses to explicitally announce to other peers. If not specified, # all interface addresses are announced @@ -186,8 +186,9 @@ [Checkpoint] Fee = 0.01 + BitcoinHost="http://btc-rpc:8332" PublicKey="66a554b8af6719851a936b0afc29dc59c3678f0e3f0b7bb081c57c5b77ad48ff" - MinioHost = "127.0.0.1:9000" + MinioHost = "minio:9000" MinioAccessKeyID = "lola" MinioSecretAccessKey = "123secure" MinioBucketName = "eudico" \ No newline at end of file diff --git a/data/charlie/config.toml b/data/charlie/config.toml index cfb26a3d0..9db03b0dc 100644 --- a/data/charlie/config.toml +++ b/data/charlie/config.toml @@ -3,7 +3,7 @@ # # type: string # env var: LOTUS_API_LISTENADDRESS - ListenAddress = "/ip4/127.0.0.1/tcp/1236/http" + ListenAddress = "/ip4/0.0.0.0/tcp/1236/http" # type: string # env var: LOTUS_API_REMOTELISTENADDRESS @@ -29,7 +29,7 @@ # # type: []string # env var: LOTUS_LIBP2P_LISTENADDRESSES - ListenAddresses = ["/ip4/0.0.0.0/tcp/3002", "/ip6/::/tcp/3002"] + ListenAddresses = ["/ip4/0.0.0.0/tcp/3002"] # Addresses to explicitally announce to other peers. If not specified, # all interface addresses are announced @@ -186,8 +186,9 @@ [Checkpoint] Fee = 0.01 + BitcoinHost="http://btc-rpc:8332" PublicKey="66a554b8af6719851a936b0afc29dc59c3678f0e3f0b7bb081c57c5b77ad48ff" - MinioHost = "127.0.0.1:9000" + MinioHost = "minio:9000" MinioAccessKeyID = "lola" MinioSecretAccessKey = "123secure" MinioBucketName = "eudico" \ No newline at end of file diff --git a/data/dom/config.toml b/data/dom/config.toml index 6714688ff..972f0b5a0 100644 --- a/data/dom/config.toml +++ b/data/dom/config.toml @@ -187,8 +187,9 @@ [Checkpoint] Fee = 0.01 + BitcoinHost="http://btc-rpc:8332" PublicKey="66a554b8af6719851a936b0afc29dc59c3678f0e3f0b7bb081c57c5b77ad48ff" - MinioHost = "127.0.0.1:9000" + MinioHost = "minio:9000" MinioAccessKeyID = "lola" MinioSecretAccessKey = "123secure" MinioBucketName = "eudico" diff --git a/node/config/types.go b/node/config/types.go index 339cd93e4..5013d4274 100644 --- a/node/config/types.go +++ b/node/config/types.go @@ -386,6 +386,7 @@ type FeeConfig struct { type Checkpoint struct { Fee float64 + BitcoinHost string PublicKey string MinioHost string MinioAccessKeyID string diff --git a/scripts/verification.sh b/scripts/verification.sh index c048f3cca..1911b91b3 100755 --- a/scripts/verification.sh +++ b/scripts/verification.sh @@ -2,4 +2,4 @@ tmux \ new-session 'EUDICO_PATH=$PWD/data/dom ./eudico delegated daemon --genesis=gen.gen; sleep infinity' \; \ - split-window 'EUDICO_PATH=$PWD/data/dom ./eudico wait-api; EUDICO_PATH=$PWD/data/dom ./eudico net connect /ip4/127.0.0.1/tcp/3000/p2p/12D3KooWMBbLLKTM9Voo89TXLd98w4MjkJUych6QvECptousGtR4; sleep 3' \; \ + split-window 'EUDICO_PATH=$PWD/data/dom ./eudico wait-api; EUDICO_PATH=$PWD/data/dom ./eudico net connect /ip4/127.0.0.1/tcp/3000/p2p/12D3KooWMBbLLKTM9Voo89TXLd98w4MjkJUych6QvECptousGtR4 /ip4/127.0.0.1/tcp/3001/p2p/12D3KooWNTyoBdMB9bpSkf7PVWR863ejGVPq9ssaaAipNvhPeQ4t /ip4/127.0.0.1/tcp/3002/p2p/12D3KooWF1aFCGUtsGEaqNks3QADLUDZxW7ot7jZPSoDiAFKJuM6; sleep 3' \; \ From cb62edd9813c83fdf84c0affdaf91acca0d8bca5 Mon Sep 17 00:00:00 2001 From: sleepy ramen Date: Tue, 18 Jan 2022 09:37:59 +0100 Subject: [PATCH 13/23] Refactoring (#13) * increasing the message size for libp2p * added comments and logs * removing deprecated functions * improve logics by removing some init steps outside of eudico --- chain/checkpointing/network.go | 33 +- chain/checkpointing/sub.go | 425 ++++---- chain/checkpointing/util.go | 91 +- chain/checkpointing/verification.go | 23 +- chain/consensus/actors/mpower/cbor_gen.go | 979 ++----------------- chain/consensus/actors/mpower/policy.go | 12 - chain/consensus/actors/mpower/power_actor.go | 506 +--------- chain/consensus/actors/mpower/power_state.go | 299 +----- data/dom/config.toml | 2 +- data/script.py | 21 + scripts/taproot.sh | 6 + 11 files changed, 370 insertions(+), 2027 deletions(-) delete mode 100644 chain/consensus/actors/mpower/policy.go create mode 100644 data/script.py diff --git a/chain/checkpointing/network.go b/chain/checkpointing/network.go index 67a051eb2..909303ddf 100644 --- a/chain/checkpointing/network.go +++ b/chain/checkpointing/network.go @@ -4,22 +4,19 @@ import ( "context" "fmt" - "github.com/Zondax/multi-party-sig/pkg/party" "github.com/Zondax/multi-party-sig/pkg/protocol" pubsub "github.com/libp2p/go-libp2p-pubsub" ) type Network struct { - sub *pubsub.Subscription - topic *pubsub.Topic - parties party.IDSlice + sub *pubsub.Subscription + topic *pubsub.Topic } -func NewNetwork(parties party.IDSlice, sub *pubsub.Subscription, topic *pubsub.Topic) *Network { +func NewNetwork(sub *pubsub.Subscription, topic *pubsub.Topic) *Network { c := &Network{ - sub: sub, - topic: topic, - parties: parties, + sub: sub, + topic: topic, } return c } @@ -35,7 +32,7 @@ func (n *Network) Next(ctx context.Context) *protocol.Message { panic(err) } - // Converting a pubsub.Message into a protocol.Message + // Unwrapping protocol message from PubSub message // see https://pkg.go.dev/github.com/libp2p/go-libp2p-pubsub@v0.5.3/pb#Message // https://pkg.go.dev/github.com/taurusgroup/multi-party-sig@v0.6.0-alpha-2021-09-21/pkg/protocol?utm_source=gopls#Message var pmessage protocol.Message @@ -58,16 +55,6 @@ func (n *Network) Send(ctx context.Context, msg *protocol.Message) { } } -func (n *Network) Done() { - fmt.Println("Done") - - /* Might need to do something here ? */ -} - -func (n *Network) Parties() party.IDSlice { - return n.parties -} - /* Handling incoming and outgoing messages */ @@ -77,7 +64,6 @@ func broadcastingMessage(ctx context.Context, h protocol.Handler, network *Netwo msg, ok := <-h.Listen() fmt.Println("Outgoing message:", msg) if !ok { - network.Done() // the channel was closed, indicating that the protocol is done executing. close(over) return @@ -93,10 +79,11 @@ func waitingMessages(ctx context.Context, h protocol.Handler, network *Network, return default: msg := network.Next(ctx) - if h.CanAccept(msg) { + fmt.Println("Incoming message:", msg, h.CanAccept(msg)) + /*if h.CanAccept(msg) { // This message is ours fmt.Println("Incoming message:", msg) - } + }*/ h.Accept(msg) } @@ -113,4 +100,6 @@ func LoopHandler(ctx context.Context, h protocol.Handler, network *Network) { go waitingMessages(ctx, h, network, over) <-over + + fmt.Println("We are done") } diff --git a/chain/checkpointing/sub.go b/chain/checkpointing/sub.go index 4c326ceef..d340bce43 100644 --- a/chain/checkpointing/sub.go +++ b/chain/checkpointing/sub.go @@ -4,12 +4,12 @@ import ( "context" "encoding/binary" "encoding/hex" - "errors" "fmt" "os" "sort" "strconv" "sync" + "time" "github.com/BurntSushi/toml" "github.com/Zondax/multi-party-sig/pkg/math/curve" @@ -29,17 +29,28 @@ import ( cbor "github.com/ipfs/go-ipld-cbor" logging "github.com/ipfs/go-log/v2" "github.com/libp2p/go-libp2p-core/host" - "github.com/libp2p/go-libp2p-core/peer" pubsub "github.com/libp2p/go-libp2p-pubsub" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" "go.uber.org/fx" + "golang.org/x/xerrors" ) var log = logging.Logger("checkpointing") +/* + Main file for the checkpointing module. Handle all the core logic. +*/ + type CheckpointingSub struct { - host host.Host + + /* + Eudico passed value (network, eudico api for state, events) + */ + + // libp2p host value + host host.Host + // libp2p pubsub instance pubsub *pubsub.PubSub // Topic for keygen topic *pubsub.Topic @@ -52,32 +63,37 @@ type CheckpointingSub struct { // lock lk sync.Mutex + /* + Checkpointing module state + */ // Generated public key pubkey []byte + // Participants list identified with their libp2p cid + participants []string // taproot config config *keygen.TaprootConfig - // miners - minerSigners []peer.ID // new config generated newconfig *keygen.TaprootConfig - // Initiated - init bool // Previous tx ptxid string // Tweaked value tweakedValue []byte - // minio config + // Checkpoint section in config.toml cpconfig *config.Checkpoint // minio client minioClient *minio.Client - // Bitcoin latest checkpoint + // Bitcoin latest checkpoint used when syncing latestConfigCheckpoint types.TipSetKey - // Is synced + // Is Eudico synced (do we have all the blocks) synced bool - // height verified! + // height verified! (the height of the latest checkpoint) height abi.ChainEpoch } +/* + Initiate checkpoint module + It will load config and inititate CheckpointingSub struct +*/ func NewCheckpointSub( mctx helpers.MetricsCtx, lc fx.Lifecycle, @@ -87,14 +103,13 @@ func NewCheckpointSub( ) (*CheckpointingSub, error) { ctx := helpers.LifecycleCtx(mctx, lc) - // Starting shardSub to listen to events in the root chain. + // Starting checkpoint listener e, err := events.NewEvents(ctx, &api) if err != nil { return nil, err } - fmt.Println("EUDICO PATH :", os.Getenv("EUDICO_PATH")) - + // Load config from EUDICO_PATH environnement var ccfg config.FullNode result, err := config.FromFile(os.Getenv("EUDICO_PATH")+"/config.toml", &ccfg) if err != nil { @@ -104,15 +119,15 @@ func NewCheckpointSub( cpconfig := result.(*config.FullNode).Checkpoint // initiate miners signers array - var minerSigners []peer.ID + var minerSigners []string synced := false + + // Load taproot verification shares from EUDICO_PATH environnement if file exist var config *keygen.TaprootConfig - // Load configTaproot - if _, err := os.Stat(os.Getenv("EUDICO_PATH") + "/share.toml"); errors.Is(err, os.ErrNotExist) { - // path/to/whatever does not exist - fmt.Println("No share file saved") - } else { + _, err = os.Stat(os.Getenv("EUDICO_PATH") + "/share.toml") + if err == nil { + // If we have a share.toml containing the distributed key we load them synced = true content, err := os.ReadFile(os.Getenv("EUDICO_PATH") + "/share.toml") if err != nil { @@ -125,16 +140,19 @@ func NewCheckpointSub( return nil, err } + // Decode the hex value to byte privateSharePath, err := hex.DecodeString(configTOML.PrivateShare) if err != nil { return nil, err } + // Decode the hex value to byte publickey, err := hex.DecodeString(configTOML.PublicKey) if err != nil { return nil, err } + // Unmarshall to Secp256k1Scalar var privateShare curve.Secp256k1Scalar err = privateShare.UnmarshalBinary(privateSharePath) if err != nil { @@ -144,6 +162,7 @@ func NewCheckpointSub( verificationShares := make(map[party.ID]*curve.Secp256k1Point) for key, vshare := range configTOML.VerificationShares { + // Decode each verification share to byte for each participants var p curve.Secp256k1Point pByte, err := hex.DecodeString(vshare.Share) @@ -166,13 +185,11 @@ func NewCheckpointSub( } for id := range config.VerificationShares { - minerSigners = append(minerSigners, peer.ID(id)) + minerSigners = append(minerSigners, string(id)) } - - fmt.Println(minerSigners) } - // Initialize minio client object. + // Initialize minio client object minioClient, err := minio.New(cpconfig.MinioHost, &minio.Options{ Creds: credentials.NewStaticV4(cpconfig.MinioAccessKeyID, cpconfig.MinioSecretAccessKey, ""), Secure: false, @@ -188,10 +205,9 @@ func NewCheckpointSub( host: host, api: &api, events: e, - init: false, ptxid: "", config: config, - minerSigners: minerSigners, + participants: minerSigners, newconfig: nil, cpconfig: &cpconfig, minioClient: minioClient, @@ -222,22 +238,24 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { // verify we are synced st, err := c.api.SyncState(ctx) if err != nil { - panic(err) + log.Errorf("unable to sync: %v", err) + return false, nil, err } - //fmt.Println(st.ActiveSyncs) if !c.synced { // Are we synced ? if len(st.ActiveSyncs) > 0 && st.ActiveSyncs[len(st.ActiveSyncs)-1].Height == newTs.Height() { - fmt.Println("We are synced") + log.Infow("we are synced") // Yes then verify our checkpoint ts, err := c.api.ChainGetTipSet(ctx, c.latestConfigCheckpoint) if err != nil { - panic(err) + log.Errorf("couldnt get tipset: %v", err) + return false, nil, err + } - fmt.Println("We have a checkpoint up to height : ", ts.Height()) + log.Infow("We have a checkpoint up to height : ", ts.Height()) c.synced = true c.height = ts.Height() } else { @@ -266,74 +284,65 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { return false, nil, err } - // Init with the first checkpoint for the demo - // Should be done outside of it ? - if !c.init && c.config != nil { - ts, err := c.api.ChainGetTipSetByHeight(ctx, 0, oldTs.Key()) - if err != nil { - panic(err) - } - data := ts.Cids()[0] - err = c.initiate(data.Bytes()) - if err != nil { - panic(err) - } - return false, nil, nil - } - // Activate checkpointing every 30 blocks - fmt.Println("Height:", newTs.Height()) + log.Infow("Height:", newTs.Height()) // NOTES: this will only work in delegated consensus // Wait for more tipset to valid the height and be sure it is valid if newTs.Height()%25 == 0 && (c.config != nil || c.newconfig != nil) { - fmt.Println("Check point time") + log.Infow("Check point time") // Initiation and config should be happening at start - if c.init { - cp := oldTs.Key().Bytes() - - // If we don't have a config we don't sign but update our config with key - if c.config == nil { - fmt.Println("We dont have a config") - pubkey := c.newconfig.PublicKey - - pubkeyShort := GenCheckpointPublicKeyTaproot(pubkey, cp) - - c.config = c.newconfig - merkleRoot := HashMerkleRoot(pubkey, cp) - c.tweakedValue = HashTweakedValue(pubkey, merkleRoot) - c.pubkey = pubkeyShort - c.newconfig = nil - - } else { - var config string = hex.EncodeToString(cp) + "\n" - for _, partyId := range c.orderParticipantsList() { - config += partyId + "\n" - } - - hash, err := CreateConfig([]byte(config)) - if err != nil { - panic(err) - } - - // Push config to S3 - err = StoreConfig(ctx, c.minioClient, c.cpconfig.MinioBucketName, hex.EncodeToString(hash)) - if err != nil { - panic(err) - } - - c.CreateCheckpoint(ctx, cp, hash) + cp := oldTs.Key().Bytes() + + // If we don't have a config we don't sign but update our config with key + if c.config == nil { + log.Infow("We dont have a config") + pubkey := c.newconfig.PublicKey + + pubkeyShort := genCheckpointPublicKeyTaproot(pubkey, cp) + + c.config = c.newconfig + merkleRoot := hashMerkleRoot(pubkey, cp) + c.tweakedValue = hashTweakedValue(pubkey, merkleRoot) + c.pubkey = pubkeyShort + c.newconfig = nil + + } else { + var config string = hex.EncodeToString(cp) + "\n" + for _, partyId := range c.orderParticipantsList() { + config += partyId + "\n" + } + + hash, err := CreateConfig([]byte(config)) + if err != nil { + log.Errorf("couldnt create config: %v", err) + return false, nil, err } + // Push config to S3 + err = StoreConfig(ctx, c.minioClient, c.cpconfig.MinioBucketName, hex.EncodeToString(hash)) + if err != nil { + log.Errorf("couldnt push config: %v", err) + return false, nil, err + } + + err = c.CreateCheckpoint(ctx, cp, hash) + if err != nil { + log.Errorf("couldnt create checkpoint: %v", err) + return false, nil, err + } } } // If Power Actors list has changed start DKG // Changes detected so generate new key if oldSt.MinerCount != newSt.MinerCount { - fmt.Println("Generate new config") - - c.GenerateNewKeys(ctx) + log.Infow("generate new config") + err := c.GenerateNewKeys(ctx, newSt.Miners) + if err != nil { + log.Errorf("error while generating new key: %v", err) + // If generating new key failed, checkpointing should not be possible + } return true, nil, nil } @@ -347,56 +356,75 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { } } -func (c *CheckpointingSub) Start(ctx context.Context) { +func (c *CheckpointingSub) Start(ctx context.Context) error { + + /* + Join libp2p pubsub topic dedicated to key generation or checkpoint generation + */ + topic, err := c.pubsub.Join("keygen") if err != nil { - panic(err) + return err } c.topic = topic // and subscribe to it - sub, err := topic.Subscribe() + // INCREASE THE BUFFER SIZE BECAUSE IT IS ONLY 32 ! AND IT IS DROPPING MESSAGES WHEN FULL + // https://github.com/libp2p/go-libp2p-pubsub/blob/v0.5.4/pubsub.go#L1222 + // NOTES: 1000 has been choosen arbitraly there is no reason for this number beside it just work + sub, err := topic.Subscribe(pubsub.WithBufferSize(1000)) if err != nil { - panic(err) + return err } c.sub = sub c.listenCheckpointEvents(ctx) + + return nil } -func (c *CheckpointingSub) GenerateNewKeys(ctx context.Context) { +func (c *CheckpointingSub) GenerateNewKeys(ctx context.Context, participants []string) error { - idsStrings := c.newOrderParticipantsList() + //idsStrings := c.newOrderParticipantsList() + idsStrings := participants + sort.Strings(idsStrings) - fmt.Println("Participants list :", idsStrings) + log.Infow("participants list :", idsStrings) ids := c.formIDSlice(idsStrings) id := party.ID(c.host.ID().String()) threshold := (len(idsStrings) / 2) + 1 - n := NewNetwork(ids, c.sub, c.topic) + n := NewNetwork(c.sub, c.topic) f := frost.KeygenTaproot(id, ids, threshold) handler, err := protocol.NewMultiHandler(f, []byte{1, 2, 3}) if err != nil { - panic(err) + return err } LoopHandler(ctx, handler, n) r, err := handler.Result() if err != nil { - panic(err) + return err } - fmt.Println("Result :", r) + log.Infow("result :", r) - c.newconfig = r.(*keygen.TaprootConfig) -} + var ok bool + c.newconfig, ok = r.(*keygen.TaprootConfig) + if !ok { + return xerrors.Errorf("state change propagated is the wrong type") + } + + c.participants = participants -func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, cp, data []byte) { + return nil +} - taprootAddress, err := PubkeyToTapprootAddress(c.pubkey) +func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, cp, data []byte) error { + taprootAddress, err := pubkeyToTapprootAddress(c.pubkey) if err != nil { - panic(err) + return err } pubkey := c.config.PublicKey @@ -404,54 +432,57 @@ func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, cp, data []byte pubkey = c.newconfig.PublicKey } - pubkeyShort := GenCheckpointPublicKeyTaproot(pubkey, cp) - newTaprootAddress, err := PubkeyToTapprootAddress(pubkeyShort) + pubkeyShort := genCheckpointPublicKeyTaproot(pubkey, cp) + newTaprootAddress, err := pubkeyToTapprootAddress(pubkeyShort) if err != nil { - panic(err) + return err } idsStrings := c.orderParticipantsList() - fmt.Println("Participants list :", idsStrings) - fmt.Println("Precedent tx", c.ptxid) + log.Infow("participants list :", idsStrings) + log.Infow("precedent tx", c.ptxid) ids := c.formIDSlice(idsStrings) if c.ptxid == "" { - fmt.Println("Missing precedent txid") - taprootScript := GetTaprootScript(c.pubkey) - success := AddTaprootToWallet(c.cpconfig.BitcoinHost, taprootScript) + log.Infow("missing precedent txid") + taprootScript := getTaprootScript(c.pubkey) + success := addTaprootToWallet(c.cpconfig.BitcoinHost, taprootScript) if !success { - panic("failed to add taproot address to wallet") + return xerrors.Errorf("failed to add taproot address to wallet") } - ptxid, err := WalletGetTxidFromAddress(c.cpconfig.BitcoinHost, taprootAddress) + // sleep an arbitrary long time to be sure it has been scanned + time.Sleep(6 * time.Second) + + ptxid, err := walletGetTxidFromAddress(c.cpconfig.BitcoinHost, taprootAddress) if err != nil { - panic(err) + return err } c.ptxid = ptxid - fmt.Println("Found precedent txid:", c.ptxid) + log.Infow("found precedent txid:", c.ptxid) } index := 0 - value, scriptPubkeyBytes := GetTxOut(c.cpconfig.BitcoinHost, c.ptxid, index) + value, scriptPubkeyBytes := getTxOut(c.cpconfig.BitcoinHost, c.ptxid, index) if scriptPubkeyBytes[0] != 0x51 { - fmt.Println("Wrong txout") + log.Infow("wrong txout") index = 1 - value, scriptPubkeyBytes = GetTxOut(c.cpconfig.BitcoinHost, c.ptxid, index) + value, scriptPubkeyBytes = getTxOut(c.cpconfig.BitcoinHost, c.ptxid, index) } newValue := value - c.cpconfig.Fee payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"createrawtransaction\", \"params\": [[{\"txid\":\"" + c.ptxid + "\",\"vout\": " + strconv.Itoa(index) + ", \"sequence\": 4294967295}], [{\"" + newTaprootAddress + "\": \"" + fmt.Sprintf("%.2f", newValue) + "\"}, {\"data\": \"" + hex.EncodeToString(data) + "\"}]]}" result := jsonRPC(c.cpconfig.BitcoinHost, payload) if result == nil { - panic("cant create new transaction") + return xerrors.Errorf("cant create new transaction") } rawTransaction := result["result"].(string) tx, err := hex.DecodeString(rawTransaction) if err != nil { - panic(err) + return err } var buf [8]byte @@ -461,31 +492,30 @@ func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, cp, data []byte hashedTx, err := TaprootSignatureHash(tx, utxo, 0x00) if err != nil { - panic(err) + return err } /* * Orchestrate the signing message */ - fmt.Println("Starting signing") + log.Infow("starting signing") f := frost.SignTaprootWithTweak(c.config, ids, hashedTx[:], c.tweakedValue[:]) - n := NewNetwork(ids, c.sub, c.topic) + n := NewNetwork(c.sub, c.topic) handler, err := protocol.NewMultiHandler(f, hashedTx[:]) if err != nil { - panic(err) + return err } LoopHandler(ctx, handler, n) r, err := handler.Result() if err != nil { - fmt.Println(err) - panic(err) + return err } - fmt.Println("Result :", r) + log.Infow("result :", r) // if signing is a success we register the new value - merkleRoot := HashMerkleRoot(pubkey, cp) - c.tweakedValue = HashTweakedValue(pubkey, merkleRoot) + merkleRoot := hashMerkleRoot(pubkey, cp) + c.tweakedValue = hashTweakedValue(pubkey, merkleRoot) c.pubkey = pubkeyShort // If new config used if c.newconfig != nil { @@ -495,38 +525,22 @@ func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, cp, data []byte c.ptxid = "" - if idsStrings[0] == c.host.ID().String() { - // Only first one broadcast the transaction ? - // Actually all participants can broadcast the transcation. It will be the same everywhere. - rawtx := PrepareWitnessRawTransaction(rawTransaction, r.(taproot.Signature)) + // Only first one broadcast the transaction ? + // Actually all participants can broadcast the transcation. It will be the same everywhere. + rawtx := prepareWitnessRawTransaction(rawTransaction, r.(taproot.Signature)) - payload = "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"sendrawtransaction\", \"params\": [\"" + rawtx + "\"]}" - result = jsonRPC(c.cpconfig.BitcoinHost, payload) - if result["error"] != nil { - fmt.Println(result) - panic("failed to broadcast transaction") - } - - /* Need to keep this to build next one */ - newtxid := result["result"].(string) - fmt.Println("New Txid:", newtxid) - c.ptxid = newtxid + payload = "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"sendrawtransaction\", \"params\": [\"" + rawtx + "\"]}" + result = jsonRPC(c.cpconfig.BitcoinHost, payload) + if result["error"] != nil { + return xerrors.Errorf("failed to broadcast transaction") } -} -func (c *CheckpointingSub) newOrderParticipantsList() []string { - id := c.host.ID().String() - var ids []string + /* Need to keep this to build next one */ + newtxid := result["result"].(string) + log.Infow("new Txid:", newtxid) + c.ptxid = newtxid - ids = append(ids, id) - - for _, peerID := range c.topic.ListPeers() { - ids = append(ids, peerID.String()) - } - - sort.Strings(ids) - - return ids + return nil } func (c *CheckpointingSub) orderParticipantsList() []string { @@ -551,98 +565,89 @@ func (c *CheckpointingSub) formIDSlice(ids []string) party.IDSlice { return idsSlice } -// Temporary -func (c *CheckpointingSub) prefundTaproot() error { - taprootAddress, err := PubkeyToTapprootAddress(c.pubkey) - if err != nil { - return err - } - - payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"sendtoaddress\", \"params\": [\"" + taprootAddress + "\", 50]}" - result := jsonRPC(c.cpconfig.BitcoinHost, payload) - if result == nil { - // Should probably not panic here - return errors.New("couldn't create first transaction") - } - c.ptxid = result["result"].(string) - - return nil -} - -func (c *CheckpointingSub) initiate(cp []byte) error { - pubkeyShort := GenCheckpointPublicKeyTaproot(c.config.PublicKey, cp) - c.pubkey = pubkeyShort - - idsStrings := c.orderParticipantsList() - - if idsStrings[0] == c.host.ID().String() { - err := c.prefundTaproot() - if err != nil { - return err - } - } - - // Save tweaked value - merkleRoot := HashMerkleRoot(c.config.PublicKey, cp) - c.tweakedValue = HashTweakedValue(c.config.PublicKey, merkleRoot) - - c.init = true - - return nil -} - +/* + BuildCheckpointingSub is called after creating the checkpointing instance + It verify connectivity with the Bitcoin node and look for the first checkpoint + and if the node is a **participant** will pre-compute some values used in signing +*/ func BuildCheckpointingSub(mctx helpers.MetricsCtx, lc fx.Lifecycle, c *CheckpointingSub) { ctx := helpers.LifecycleCtx(mctx, lc) // Ping to see if bitcoind is available - success := BitcoindPing(c.cpconfig.BitcoinHost) + success := bitcoindPing(c.cpconfig.BitcoinHost) if !success { - // Should probably not panic here - panic("Bitcoin node not available") + log.Errorf("bitcoin node not available") + return } - fmt.Println("Successfully pinged bitcoind") - - LoadWallet(c.cpconfig.BitcoinHost) + log.Infow("successfully pinged bitcoind") // Get first checkpoint from block 0 ts, err := c.api.ChainGetGenesis(ctx) if err != nil { - panic(err) + log.Errorf("couldnt get genesis tipset: %v", err) + return } cidBytes := ts.Key().Bytes() publickey, err := hex.DecodeString(c.cpconfig.PublicKey) if err != nil { - panic(err) + log.Errorf("couldnt decode public key: %v", err) + return } + // Get the last checkpoint from the bitcoin node btccp, err := GetLatestCheckpoint(c.cpconfig.BitcoinHost, publickey, cidBytes) if err != nil { - panic(err) + log.Errorf("couldnt decode public key: %v", err) + return } + // Get the config in minio using the last checkpoint found through bitcoin + // NOTES: We should be able to get the config regarless of storage (minio, IPFS, KVS,....) cp, err := GetConfig(ctx, c.minioClient, c.cpconfig.MinioBucketName, btccp.cid) - fmt.Println(cp) if cp != "" { + // Decode hex checkpoint to bytes cpBytes, err := hex.DecodeString(cp) if err != nil { - panic(err) + log.Errorf("couldnt decode checkpoint: %v", err) + return } + // Cache latest checkpoint value for when we sync and compare wit Eudico key tipset values c.latestConfigCheckpoint, err = types.TipSetKeyFromBytes(cpBytes) if err != nil { - panic(err) + log.Errorf("couldnt get tipset key from checkpoint: %v", err) + return } + } - // The first tx is in Bitcoin - c.init = true + // Pre-compute values from participants in the signing process + if c.config != nil { + // save public key taproot + // NOTES: cidBytes is the tipset key value (aka checkpoint) from the genesis block. When Eudico is stopped it should remember what was the last tipset key value + // it signed and replace it with it. Config is not saved, neither when new DKG is done. + c.pubkey = genCheckpointPublicKeyTaproot(c.config.PublicKey, cidBytes) + + //address, _ := pubkeyToTapprootAddress(c.pubkey) + //fmt.Println(address) + + // Save tweaked value + merkleRoot := hashMerkleRoot(c.config.PublicKey, cidBytes) + c.tweakedValue = hashTweakedValue(c.config.PublicKey, merkleRoot) } - c.Start(ctx) + // Start the checkpoint module + err = c.Start(ctx) + if err != nil { + log.Errorf("couldn't start checkpointing module: %v", err) + } lc.Append(fx.Hook{ OnStop: func(ctx context.Context) error { // Do we need to stop something here ? + + // NOTES: new config and checkpoint should be saved in a file for when we restart the node + return nil }, }) diff --git a/chain/checkpointing/util.go b/chain/checkpointing/util.go index 9194305f0..9bdd62e19 100644 --- a/chain/checkpointing/util.go +++ b/chain/checkpointing/util.go @@ -20,6 +20,7 @@ type VerificationShare struct { Share string } +// Define what share.toml should look like type TaprootConfigTOML struct { Thershold int PrivateShare string @@ -27,7 +28,7 @@ type TaprootConfigTOML struct { VerificationShares map[string]VerificationShare } -func TaggedHash(tag string, datas ...[]byte) []byte { +func taggedHash(tag string, datas ...[]byte) []byte { tagSum := sha256.Sum256([]byte(tag)) h := sha256.New() @@ -39,7 +40,7 @@ func TaggedHash(tag string, datas ...[]byte) []byte { return h.Sum(nil) } -func Sha256(data []byte) []byte { +func sha256Util(data []byte) []byte { h := sha256.New() h.Write(data[:]) return h.Sum(nil) @@ -67,19 +68,19 @@ func TaprootSignatureHash(tx []byte, utxo []byte, hash_type byte) ([]byte, error // Please check https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message // Previous output (txid + index = 36 bytes) - ss = append(ss, Sha256(tx[5:5+36])...) + ss = append(ss, sha256Util(tx[5:5+36])...) // Amount in the previous output (8 bytes) - ss = append(ss, Sha256(utxo[0:8])...) + ss = append(ss, sha256Util(utxo[0:8])...) // PubScript in the previous output (35 bytes) - ss = append(ss, Sha256(utxo[8:8+35])...) + ss = append(ss, sha256Util(utxo[8:8+35])...) // Sequence (4 bytes) - ss = append(ss, Sha256(tx[5+36+1:5+36+1+4])...) + ss = append(ss, sha256Util(tx[5+36+1:5+36+1+4])...) // Adding new txouts - ss = append(ss, Sha256(tx[47:len(tx)-4])...) + ss = append(ss, sha256Util(tx[47:len(tx)-4])...) // spend type (here key path spending) ss = append(ss, 0x00) @@ -87,10 +88,10 @@ func TaprootSignatureHash(tx []byte, utxo []byte, hash_type byte) ([]byte, error // Input index ss = append(ss, []byte{0, 0, 0, 0}...) - return TaggedHash("TapSighash", ss), nil + return taggedHash("TapSighash", ss), nil } -func PubkeyToTapprootAddress(pubkey []byte) (string, error) { +func pubkeyToTapprootAddress(pubkey []byte) (string, error) { conv, err := bech32.ConvertBits(pubkey, 8, 5, true) if err != nil { return "", err @@ -108,24 +109,7 @@ func PubkeyToTapprootAddress(pubkey []byte) (string, error) { return taprootAddress, nil } -/*func PubkeyToTapprootAddressLegacy(pubkey []byte) string { - conv, err := bech32.ConvertBits(pubkey, 8, 5, true) - if err != nil { - fmt.Println("Error:", err) - log.Fatal("I dunno.") - } - // Add segwit version byte 1 - conv = append([]byte{0x01}, conv...) - - taprootAddressLegacy, err := bech32.Encode("bcrt", conv) - if err != nil { - fmt.Println(err) - log.Fatal("Couldn't produce our tapproot address.") - } - return taprootAddressLegacy -}*/ - -func ApplyTweakToPublicKeyTaproot(public []byte, tweak []byte) []byte { +func applyTweakToPublicKeyTaproot(public []byte, tweak []byte) []byte { group := curve.Secp256k1{} s_tweak := group.NewScalar().SetNat(new(safenum.Nat).SetBytes(tweak)) p_tweak := s_tweak.ActOnBase() @@ -144,28 +128,28 @@ func ApplyTweakToPublicKeyTaproot(public []byte, tweak []byte) []byte { return PBytes } -func HashMerkleRoot(pubkey []byte, checkpoint []byte) []byte { - merkle_root := TaggedHash("TapLeaf", []byte{0xc0}, pubkey, checkpoint) +func hashMerkleRoot(pubkey []byte, checkpoint []byte) []byte { + merkle_root := taggedHash("TapLeaf", []byte{0xc0}, pubkey, checkpoint) return merkle_root[:] } -func HashTweakedValue(pubkey []byte, merkle_root []byte) []byte { - tweaked_value := TaggedHash("TapTweak", pubkey, merkle_root) +func hashTweakedValue(pubkey []byte, merkle_root []byte) []byte { + tweaked_value := taggedHash("TapTweak", pubkey, merkle_root) return tweaked_value[:] } -func GenCheckpointPublicKeyTaproot(internal_pubkey []byte, checkpoint []byte) []byte { - merkle_root := HashMerkleRoot(internal_pubkey, checkpoint) - tweaked_value := HashTweakedValue(internal_pubkey, merkle_root) +func genCheckpointPublicKeyTaproot(internal_pubkey []byte, checkpoint []byte) []byte { + merkle_root := hashMerkleRoot(internal_pubkey, checkpoint) + tweaked_value := hashTweakedValue(internal_pubkey, merkle_root) - tweaked_pubkey := ApplyTweakToPublicKeyTaproot(internal_pubkey, tweaked_value) + tweaked_pubkey := applyTweakToPublicKeyTaproot(internal_pubkey, tweaked_value) return tweaked_pubkey } -func AddTaprootToWallet(url, taprootScript string) bool { +func addTaprootToWallet(url, taprootScript string) bool { payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"importaddress\", \"params\": [\"" + taprootScript + "\", \"\", true]}" result := jsonRPC(url, payload) - + fmt.Println(result) if result["error"] == nil { return true } @@ -180,31 +164,16 @@ func AddTaprootToWallet(url, taprootScript string) bool { return false } -func GetTaprootScript(pubkey []byte) string { - // 1 <20-size> pukey +func getTaprootScript(pubkey []byte) string { + // 1 <20-size> pubkey return "5120" + hex.EncodeToString(pubkey) } -func LoadWallet(url string) { - // Create wallet - payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"createwallet\", \"params\": [\"wow\"]}" - _ = jsonRPC(url, payload) - // We don't check error here -} - -// Temporary -func BitcoindGetWalletAddress(url string) string { - //Get new address - payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"getnewaddress\", \"params\": []}" - - result := jsonRPC(url, payload) - address := fmt.Sprintf("%v", result["result"]) - return address -} - -func WalletGetTxidFromAddress(url, taprootAddress string) (string, error) { +func walletGetTxidFromAddress(url, taprootAddress string) (string, error) { payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"listtransactions\", \"params\": [\"*\", 500000000, 0, true]}" result := jsonRPC(url, payload) + fmt.Println(result) + list := result["result"].([]interface{}) for _, item := range list { item_map := item.(map[string]interface{}) @@ -216,23 +185,23 @@ func WalletGetTxidFromAddress(url, taprootAddress string) (string, error) { return "", errors.New("did not find checkpoint") } -func BitcoindPing(url string) bool { +func bitcoindPing(url string) bool { payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"ping\", \"params\": []}" result := jsonRPC(url, payload) return result != nil } -func PrepareWitnessRawTransaction(rawtx string, sig []byte) string { +func prepareWitnessRawTransaction(rawtx string, sig []byte) string { wtx := rawtx[:4*2] + "00" + "01" + rawtx[4*2:len(rawtx)-4*2] + "01" + "40" + hex.EncodeToString(sig) + rawtx[len(rawtx)-4*2:] return wtx } -func ParseUnspentTxOut(utxo []byte) (amount, script []byte) { +func parseUnspentTxOut(utxo []byte) (amount, script []byte) { return utxo[0:8], utxo[9:] } -func GetTxOut(url, txid string, index int) (float64, []byte) { +func getTxOut(url, txid string, index int) (float64, []byte) { payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"gettxout\", \"params\": [\"" + txid + "\", " + strconv.Itoa(index) + "]}" result := jsonRPC(url, payload) if result == nil { diff --git a/chain/checkpointing/verification.go b/chain/checkpointing/verification.go index a90ae4958..62218ffb4 100644 --- a/chain/checkpointing/verification.go +++ b/chain/checkpointing/verification.go @@ -16,11 +16,15 @@ type Checkpoint struct { } func GetFirstCheckpointAddress(url, taprootAddress string) (Checkpoint, error) { + // List all the transactions and look for one that match the taproot address payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"listtransactions\", \"params\": [\"*\", 500000000, 0, true]}" + // url is the url of the bitcoin node with the RPC port result := jsonRPC(url, payload) list := result["result"].([]interface{}) for _, item := range list { item_map := item.(map[string]interface{}) + + // Check if address match taproot adress given if yes return it if item_map["address"] == taprootAddress { tx_id := item_map["txid"].(string) payload = "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"getrawtransaction\", \"params\": [\"" + tx_id + "\", true]}" @@ -67,23 +71,30 @@ func GetNextCheckpointFixed(url, txid string) (Checkpoint, error) { } func GetLatestCheckpoint(url string, first_pk []byte, first_cp []byte) (*Checkpoint, error) { - first_pubkeyTaproot := GenCheckpointPublicKeyTaproot(first_pk, first_cp) - firstscript := GetTaprootScript(first_pubkeyTaproot) - taprootAddress, err := PubkeyToTapprootAddress(first_pubkeyTaproot) + first_pubkeyTaproot := genCheckpointPublicKeyTaproot(first_pk, first_cp) + firstscript := getTaprootScript(first_pubkeyTaproot) + taprootAddress, err := pubkeyToTapprootAddress(first_pubkeyTaproot) if err != nil { return nil, err } - AddTaprootToWallet(url, firstscript) + /* + Bitcoin node only allow to collect transaction from addresses that are registered in the wallet + In this step we import taproot script (and not the address) in the wallet node to then be able to ask + for transaction linked to it. + */ + addTaprootToWallet(url, firstscript) checkpoint, done := GetFirstCheckpointAddress(url, taprootAddress) - AddTaprootToWallet(url, checkpoint.address) + // Aging we add taproot "address" (actually the script) to the wallet in the Bitcoin node + addTaprootToWallet(url, checkpoint.address) var new_checkpoint Checkpoint for { new_checkpoint, done = GetNextCheckpointFixed(url, checkpoint.txid) if done == nil { checkpoint = new_checkpoint - AddTaprootToWallet(url, checkpoint.address) + addTaprootToWallet(url, checkpoint.address) } else { + // Return once we have found the last one in bitcoin return &checkpoint, nil } } diff --git a/chain/consensus/actors/mpower/cbor_gen.go b/chain/consensus/actors/mpower/cbor_gen.go index 26c65811a..4d223b5e7 100644 --- a/chain/consensus/actors/mpower/cbor_gen.go +++ b/chain/consensus/actors/mpower/cbor_gen.go @@ -1,617 +1,70 @@ -// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. - package mpower -import ( - "fmt" - "io" - - address "github.com/filecoin-project/go-address" - abi "github.com/filecoin-project/go-state-types/abi" - cbg "github.com/whyrusleeping/cbor-gen" - xerrors "golang.org/x/xerrors" -) - -var _ = xerrors.Errorf - -var lengthBufState = []byte{143} - -func (t *State) MarshalCBOR(w io.Writer) error { - if t == nil { - _, err := w.Write(cbg.CborNull) - return err - } - if _, err := w.Write(lengthBufState); err != nil { - return err - } - - scratch := make([]byte, 9) - - // t.TotalRawBytePower (big.Int) (struct) - if err := t.TotalRawBytePower.MarshalCBOR(w); err != nil { - return err - } - - // t.TotalBytesCommitted (big.Int) (struct) - if err := t.TotalBytesCommitted.MarshalCBOR(w); err != nil { - return err - } - - // t.TotalQualityAdjPower (big.Int) (struct) - if err := t.TotalQualityAdjPower.MarshalCBOR(w); err != nil { - return err - } - - // t.TotalQABytesCommitted (big.Int) (struct) - if err := t.TotalQABytesCommitted.MarshalCBOR(w); err != nil { - return err - } - - // t.TotalPledgeCollateral (big.Int) (struct) - if err := t.TotalPledgeCollateral.MarshalCBOR(w); err != nil { - return err - } - - // t.ThisEpochRawBytePower (big.Int) (struct) - if err := t.ThisEpochRawBytePower.MarshalCBOR(w); err != nil { - return err - } - - // t.ThisEpochQualityAdjPower (big.Int) (struct) - if err := t.ThisEpochQualityAdjPower.MarshalCBOR(w); err != nil { - return err - } - - // t.ThisEpochPledgeCollateral (big.Int) (struct) - if err := t.ThisEpochPledgeCollateral.MarshalCBOR(w); err != nil { - return err - } - - // t.ThisEpochQAPowerSmoothed (smoothing.FilterEstimate) (struct) - if err := t.ThisEpochQAPowerSmoothed.MarshalCBOR(w); err != nil { - return err - } - - // t.MinerCount (int64) (int64) - if t.MinerCount >= 0 { - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.MinerCount)); err != nil { - return err - } - } else { - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.MinerCount-1)); err != nil { - return err - } - } - - // t.MinerAboveMinPowerCount (int64) (int64) - if t.MinerAboveMinPowerCount >= 0 { - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.MinerAboveMinPowerCount)); err != nil { - return err - } - } else { - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.MinerAboveMinPowerCount-1)); err != nil { - return err - } - } - - // t.CronEventQueue (cid.Cid) (struct) - - if err := cbg.WriteCidBuf(scratch, w, t.CronEventQueue); err != nil { - return xerrors.Errorf("failed to write cid field t.CronEventQueue: %w", err) - } - - // t.FirstCronEpoch (abi.ChainEpoch) (int64) - if t.FirstCronEpoch >= 0 { - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.FirstCronEpoch)); err != nil { - return err - } - } else { - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.FirstCronEpoch-1)); err != nil { - return err - } - } - - // t.Claims (cid.Cid) (struct) - - if err := cbg.WriteCidBuf(scratch, w, t.Claims); err != nil { - return xerrors.Errorf("failed to write cid field t.Claims: %w", err) - } - - // t.ProofValidationBatch (cid.Cid) (struct) - - if t.ProofValidationBatch == nil { - if _, err := w.Write(cbg.CborNull); err != nil { - return err - } - } else { - if err := cbg.WriteCidBuf(scratch, w, *t.ProofValidationBatch); err != nil { - return xerrors.Errorf("failed to write cid field t.ProofValidationBatch: %w", err) - } - } - - return nil -} - -func (t *State) UnmarshalCBOR(r io.Reader) error { - *t = State{} - - br := cbg.GetPeeker(r) - scratch := make([]byte, 8) - - maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) - if err != nil { - return err - } - if maj != cbg.MajArray { - return fmt.Errorf("cbor input should be of type array") - } - - if extra != 15 { - return fmt.Errorf("cbor input had wrong number of fields") - } - - // t.TotalRawBytePower (big.Int) (struct) - - { - - if err := t.TotalRawBytePower.UnmarshalCBOR(br); err != nil { - return xerrors.Errorf("unmarshaling t.TotalRawBytePower: %w", err) - } - - } - // t.TotalBytesCommitted (big.Int) (struct) - - { - - if err := t.TotalBytesCommitted.UnmarshalCBOR(br); err != nil { - return xerrors.Errorf("unmarshaling t.TotalBytesCommitted: %w", err) - } - - } - // t.TotalQualityAdjPower (big.Int) (struct) - - { - - if err := t.TotalQualityAdjPower.UnmarshalCBOR(br); err != nil { - return xerrors.Errorf("unmarshaling t.TotalQualityAdjPower: %w", err) - } - - } - // t.TotalQABytesCommitted (big.Int) (struct) - - { - - if err := t.TotalQABytesCommitted.UnmarshalCBOR(br); err != nil { - return xerrors.Errorf("unmarshaling t.TotalQABytesCommitted: %w", err) - } - - } - // t.TotalPledgeCollateral (big.Int) (struct) - - { - - if err := t.TotalPledgeCollateral.UnmarshalCBOR(br); err != nil { - return xerrors.Errorf("unmarshaling t.TotalPledgeCollateral: %w", err) - } - - } - // t.ThisEpochRawBytePower (big.Int) (struct) - - { - - if err := t.ThisEpochRawBytePower.UnmarshalCBOR(br); err != nil { - return xerrors.Errorf("unmarshaling t.ThisEpochRawBytePower: %w", err) - } - - } - // t.ThisEpochQualityAdjPower (big.Int) (struct) - - { - - if err := t.ThisEpochQualityAdjPower.UnmarshalCBOR(br); err != nil { - return xerrors.Errorf("unmarshaling t.ThisEpochQualityAdjPower: %w", err) - } - - } - // t.ThisEpochPledgeCollateral (big.Int) (struct) - - { - - if err := t.ThisEpochPledgeCollateral.UnmarshalCBOR(br); err != nil { - return xerrors.Errorf("unmarshaling t.ThisEpochPledgeCollateral: %w", err) - } - - } - // t.ThisEpochQAPowerSmoothed (smoothing.FilterEstimate) (struct) - - { - - if err := t.ThisEpochQAPowerSmoothed.UnmarshalCBOR(br); err != nil { - return xerrors.Errorf("unmarshaling t.ThisEpochQAPowerSmoothed: %w", err) - } - - } - // t.MinerCount (int64) (int64) - { - maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) - var extraI int64 - if err != nil { - return err - } - switch maj { - case cbg.MajUnsignedInt: - extraI = int64(extra) - if extraI < 0 { - return fmt.Errorf("int64 positive overflow") - } - case cbg.MajNegativeInt: - extraI = int64(extra) - if extraI < 0 { - return fmt.Errorf("int64 negative oveflow") - } - extraI = -1 - extraI - default: - return fmt.Errorf("wrong type for int64 field: %d", maj) - } - - t.MinerCount = int64(extraI) - } - // t.MinerAboveMinPowerCount (int64) (int64) - { - maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) - var extraI int64 - if err != nil { - return err - } - switch maj { - case cbg.MajUnsignedInt: - extraI = int64(extra) - if extraI < 0 { - return fmt.Errorf("int64 positive overflow") - } - case cbg.MajNegativeInt: - extraI = int64(extra) - if extraI < 0 { - return fmt.Errorf("int64 negative oveflow") - } - extraI = -1 - extraI - default: - return fmt.Errorf("wrong type for int64 field: %d", maj) - } - - t.MinerAboveMinPowerCount = int64(extraI) - } - // t.CronEventQueue (cid.Cid) (struct) - - { - - c, err := cbg.ReadCid(br) - if err != nil { - return xerrors.Errorf("failed to read cid field t.CronEventQueue: %w", err) - } - - t.CronEventQueue = c - - } - // t.FirstCronEpoch (abi.ChainEpoch) (int64) - { - maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) - var extraI int64 - if err != nil { - return err - } - switch maj { - case cbg.MajUnsignedInt: - extraI = int64(extra) - if extraI < 0 { - return fmt.Errorf("int64 positive overflow") - } - case cbg.MajNegativeInt: - extraI = int64(extra) - if extraI < 0 { - return fmt.Errorf("int64 negative oveflow") - } - extraI = -1 - extraI - default: - return fmt.Errorf("wrong type for int64 field: %d", maj) - } - - t.FirstCronEpoch = abi.ChainEpoch(extraI) - } - // t.Claims (cid.Cid) (struct) - - { - - c, err := cbg.ReadCid(br) - if err != nil { - return xerrors.Errorf("failed to read cid field t.Claims: %w", err) - } - - t.Claims = c - - } - // t.ProofValidationBatch (cid.Cid) (struct) - - { - - b, err := br.ReadByte() - if err != nil { - return err - } - if b != cbg.CborNull[0] { - if err := br.UnreadByte(); err != nil { - return err - } - - c, err := cbg.ReadCid(br) - if err != nil { - return xerrors.Errorf("failed to read cid field t.ProofValidationBatch: %w", err) - } - - t.ProofValidationBatch = &c - } - - } - return nil -} - -var lengthBufClaim = []byte{131} - -func (t *Claim) MarshalCBOR(w io.Writer) error { - if t == nil { - _, err := w.Write(cbg.CborNull) - return err - } - if _, err := w.Write(lengthBufClaim); err != nil { - return err - } - - scratch := make([]byte, 9) - - // t.WindowPoStProofType (abi.RegisteredPoStProof) (int64) - if t.WindowPoStProofType >= 0 { - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.WindowPoStProofType)); err != nil { - return err - } - } else { - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.WindowPoStProofType-1)); err != nil { - return err - } - } - - // t.RawBytePower (big.Int) (struct) - if err := t.RawBytePower.MarshalCBOR(w); err != nil { - return err - } - - // t.QualityAdjPower (big.Int) (struct) - if err := t.QualityAdjPower.MarshalCBOR(w); err != nil { - return err - } - return nil -} - -func (t *Claim) UnmarshalCBOR(r io.Reader) error { - *t = Claim{} - - br := cbg.GetPeeker(r) - scratch := make([]byte, 8) - - maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) - if err != nil { - return err - } - if maj != cbg.MajArray { - return fmt.Errorf("cbor input should be of type array") - } - - if extra != 3 { - return fmt.Errorf("cbor input had wrong number of fields") - } - - // t.WindowPoStProofType (abi.RegisteredPoStProof) (int64) - { - maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) - var extraI int64 - if err != nil { - return err - } - switch maj { - case cbg.MajUnsignedInt: - extraI = int64(extra) - if extraI < 0 { - return fmt.Errorf("int64 positive overflow") - } - case cbg.MajNegativeInt: - extraI = int64(extra) - if extraI < 0 { - return fmt.Errorf("int64 negative oveflow") - } - extraI = -1 - extraI - default: - return fmt.Errorf("wrong type for int64 field: %d", maj) - } - - t.WindowPoStProofType = abi.RegisteredPoStProof(extraI) - } - // t.RawBytePower (big.Int) (struct) - - { - - if err := t.RawBytePower.UnmarshalCBOR(br); err != nil { - return xerrors.Errorf("unmarshaling t.RawBytePower: %w", err) - } - - } - // t.QualityAdjPower (big.Int) (struct) - - { - - if err := t.QualityAdjPower.UnmarshalCBOR(br); err != nil { - return xerrors.Errorf("unmarshaling t.QualityAdjPower: %w", err) - } - - } - return nil -} - -var lengthBufCronEvent = []byte{130} - -func (t *CronEvent) MarshalCBOR(w io.Writer) error { - if t == nil { - _, err := w.Write(cbg.CborNull) - return err - } - if _, err := w.Write(lengthBufCronEvent); err != nil { - return err - } - - scratch := make([]byte, 9) - - // t.MinerAddr (address.Address) (struct) - if err := t.MinerAddr.MarshalCBOR(w); err != nil { - return err - } - - // t.CallbackPayload ([]uint8) (slice) - if len(t.CallbackPayload) > cbg.ByteArrayMaxLen { - return xerrors.Errorf("Byte array in field t.CallbackPayload was too long") - } - - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajByteString, uint64(len(t.CallbackPayload))); err != nil { - return err - } - - if _, err := w.Write(t.CallbackPayload[:]); err != nil { - return err - } - return nil -} - -func (t *CronEvent) UnmarshalCBOR(r io.Reader) error { - *t = CronEvent{} - - br := cbg.GetPeeker(r) - scratch := make([]byte, 8) - - maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) - if err != nil { - return err - } - if maj != cbg.MajArray { - return fmt.Errorf("cbor input should be of type array") - } - - if extra != 2 { - return fmt.Errorf("cbor input had wrong number of fields") - } - - // t.MinerAddr (address.Address) (struct) - - { - - if err := t.MinerAddr.UnmarshalCBOR(br); err != nil { - return xerrors.Errorf("unmarshaling t.MinerAddr: %w", err) - } - - } - // t.CallbackPayload ([]uint8) (slice) - - maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) - if err != nil { - return err - } - - if extra > cbg.ByteArrayMaxLen { - return fmt.Errorf("t.CallbackPayload: byte array too large (%d)", extra) - } - if maj != cbg.MajByteString { - return fmt.Errorf("expected byte array") - } - - if extra > 0 { - t.CallbackPayload = make([]uint8, extra) - } +import ( + "fmt" + "io" - if _, err := io.ReadFull(br, t.CallbackPayload[:]); err != nil { - return err - } - return nil -} + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) -var lengthBufCreateMinerParams = []byte{133} +var _ = xerrors.Errorf + +var lengthBufState = []byte{130} -func (t *CreateMinerParams) MarshalCBOR(w io.Writer) error { +func (t *State) MarshalCBOR(w io.Writer) error { if t == nil { _, err := w.Write(cbg.CborNull) return err } - if _, err := w.Write(lengthBufCreateMinerParams); err != nil { + if _, err := w.Write(lengthBufState); err != nil { return err } scratch := make([]byte, 9) - // t.Owner (address.Address) (struct) - if err := t.Owner.MarshalCBOR(w); err != nil { - return err - } - - // t.Worker (address.Address) (struct) - if err := t.Worker.MarshalCBOR(w); err != nil { - return err - } - - // t.WindowPoStProofType (abi.RegisteredPoStProof) (int64) - if t.WindowPoStProofType >= 0 { - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.WindowPoStProofType)); err != nil { + // t.MinerCount (int64) (int64) + if t.MinerCount >= 0 { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.MinerCount)); err != nil { return err } } else { - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.WindowPoStProofType-1)); err != nil { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.MinerCount-1)); err != nil { return err } } - // t.Peer ([]uint8) (slice) - if len(t.Peer) > cbg.ByteArrayMaxLen { - return xerrors.Errorf("Byte array in field t.Peer was too long") + // t.Miners ([]string) (slice) + if len(t.Miners) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Miners was too long") } - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajByteString, uint64(len(t.Peer))); err != nil { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.Miners))); err != nil { return err } - - if _, err := w.Write(t.Peer[:]); err != nil { - return err + for _, v := range t.Miners { + if err := marshalCBORString(w, v); err != nil { + return err + } } - // t.Multiaddrs ([][]uint8) (slice) - if len(t.Multiaddrs) > cbg.MaxLength { - return xerrors.Errorf("Slice value in field t.Multiaddrs was too long") - } + return nil +} - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.Multiaddrs))); err != nil { +func marshalCBORString(w io.Writer, s string) error { + if err := cbg.WriteMajorTypeHeader(w, cbg.MajTextString, uint64(len(s))); err != nil { return err } - for _, v := range t.Multiaddrs { - if len(v) > cbg.ByteArrayMaxLen { - return xerrors.Errorf("Byte array in field v was too long") - } - - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajByteString, uint64(len(v))); err != nil { - return err - } - if _, err := w.Write(v[:]); err != nil { - return err - } + if _, err := io.WriteString(w, s); err != nil { + return err } + return nil } -func (t *CreateMinerParams) UnmarshalCBOR(r io.Reader) error { - *t = CreateMinerParams{} +func (t *State) UnmarshalCBOR(r io.Reader) error { + *t = State{} br := cbg.GetPeeker(r) scratch := make([]byte, 8) @@ -624,29 +77,11 @@ func (t *CreateMinerParams) UnmarshalCBOR(r io.Reader) error { return fmt.Errorf("cbor input should be of type array") } - if extra != 5 { + if extra != 2 { return fmt.Errorf("cbor input had wrong number of fields") } - // t.Owner (address.Address) (struct) - - { - - if err := t.Owner.UnmarshalCBOR(br); err != nil { - return xerrors.Errorf("unmarshaling t.Owner: %w", err) - } - - } - // t.Worker (address.Address) (struct) - - { - - if err := t.Worker.UnmarshalCBOR(br); err != nil { - return xerrors.Errorf("unmarshaling t.Worker: %w", err) - } - - } - // t.WindowPoStProofType (abi.RegisteredPoStProof) (int64) + // t.MinerCount (int64) (int64) { maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) var extraI int64 @@ -669,38 +104,17 @@ func (t *CreateMinerParams) UnmarshalCBOR(r io.Reader) error { return fmt.Errorf("wrong type for int64 field: %d", maj) } - t.WindowPoStProofType = abi.RegisteredPoStProof(extraI) - } - // t.Peer ([]uint8) (slice) - - maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) - if err != nil { - return err - } - - if extra > cbg.ByteArrayMaxLen { - return fmt.Errorf("t.Peer: byte array too large (%d)", extra) - } - if maj != cbg.MajByteString { - return fmt.Errorf("expected byte array") - } - - if extra > 0 { - t.Peer = make([]uint8, extra) - } - - if _, err := io.ReadFull(br, t.Peer[:]); err != nil { - return err + t.MinerCount = int64(extraI) } - // t.Multiaddrs ([][]uint8) (slice) + // t.Miners ([]string) (slice) maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) if err != nil { return err } if extra > cbg.MaxLength { - return fmt.Errorf("t.Multiaddrs: array too large (%d)", extra) + return fmt.Errorf("t.Miners: array too large (%d)", extra) } if maj != cbg.MajArray { @@ -708,217 +122,54 @@ func (t *CreateMinerParams) UnmarshalCBOR(r io.Reader) error { } if extra > 0 { - t.Multiaddrs = make([][]uint8, extra) + t.Miners = make([]string, extra) } for i := 0; i < int(extra); i++ { - { - var maj byte - var extra uint64 - var err error - - maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) - if err != nil { - return err - } - - if extra > cbg.ByteArrayMaxLen { - return fmt.Errorf("t.Multiaddrs[i]: byte array too large (%d)", extra) - } - if maj != cbg.MajByteString { - return fmt.Errorf("expected byte array") - } - - if extra > 0 { - t.Multiaddrs[i] = make([]uint8, extra) - } - - if _, err := io.ReadFull(br, t.Multiaddrs[i][:]); err != nil { - return err - } - } - } - - return nil -} - -var lengthBufCurrentTotalPowerReturn = []byte{132} - -func (t *CurrentTotalPowerReturn) MarshalCBOR(w io.Writer) error { - if t == nil { - _, err := w.Write(cbg.CborNull) - return err - } - if _, err := w.Write(lengthBufCurrentTotalPowerReturn); err != nil { - return err - } - - // t.RawBytePower (big.Int) (struct) - if err := t.RawBytePower.MarshalCBOR(w); err != nil { - return err - } - - // t.QualityAdjPower (big.Int) (struct) - if err := t.QualityAdjPower.MarshalCBOR(w); err != nil { - return err - } - - // t.PledgeCollateral (big.Int) (struct) - if err := t.PledgeCollateral.MarshalCBOR(w); err != nil { - return err - } - - // t.QualityAdjPowerSmoothed (smoothing.FilterEstimate) (struct) - if err := t.QualityAdjPowerSmoothed.MarshalCBOR(w); err != nil { - return err - } - return nil -} - -func (t *CurrentTotalPowerReturn) UnmarshalCBOR(r io.Reader) error { - *t = CurrentTotalPowerReturn{} - - br := cbg.GetPeeker(r) - scratch := make([]byte, 8) - - maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) - if err != nil { - return err - } - if maj != cbg.MajArray { - return fmt.Errorf("cbor input should be of type array") - } - - if extra != 4 { - return fmt.Errorf("cbor input had wrong number of fields") - } - - // t.RawBytePower (big.Int) (struct) - - { - - if err := t.RawBytePower.UnmarshalCBOR(br); err != nil { - return xerrors.Errorf("unmarshaling t.RawBytePower: %w", err) - } - } - // t.QualityAdjPower (big.Int) (struct) - - { - - if err := t.QualityAdjPower.UnmarshalCBOR(br); err != nil { - return xerrors.Errorf("unmarshaling t.QualityAdjPower: %w", err) - } - - } - // t.PledgeCollateral (big.Int) (struct) - - { - - if err := t.PledgeCollateral.UnmarshalCBOR(br); err != nil { - return xerrors.Errorf("unmarshaling t.PledgeCollateral: %w", err) + m, err := cbg.ReadString(br) + if err != nil { + return err } + t.Miners[i] = m } - // t.QualityAdjPowerSmoothed (smoothing.FilterEstimate) (struct) - - { - - if err := t.QualityAdjPowerSmoothed.UnmarshalCBOR(br); err != nil { - return xerrors.Errorf("unmarshaling t.QualityAdjPowerSmoothed: %w", err) - } - } return nil } -var lengthBufMinerConstructorParams = []byte{134} +var lengthBufAddMinerParams = []byte{129} -func (t *MinerConstructorParams) MarshalCBOR(w io.Writer) error { +func (t *AddMinerParams) MarshalCBOR(w io.Writer) error { if t == nil { _, err := w.Write(cbg.CborNull) return err } - if _, err := w.Write(lengthBufMinerConstructorParams); err != nil { + if _, err := w.Write(lengthBufAddMinerParams); err != nil { return err } scratch := make([]byte, 9) - // t.OwnerAddr (address.Address) (struct) - if err := t.OwnerAddr.MarshalCBOR(w); err != nil { - return err - } - - // t.WorkerAddr (address.Address) (struct) - if err := t.WorkerAddr.MarshalCBOR(w); err != nil { - return err - } - - // t.ControlAddrs ([]address.Address) (slice) - if len(t.ControlAddrs) > cbg.MaxLength { - return xerrors.Errorf("Slice value in field t.ControlAddrs was too long") + // t.Miners ([]string) (slice) + if len(t.Miners) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Miners was too long") } - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.ControlAddrs))); err != nil { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.Miners))); err != nil { return err } - for _, v := range t.ControlAddrs { - if err := v.MarshalCBOR(w); err != nil { - return err - } - } - - // t.WindowPoStProofType (abi.RegisteredPoStProof) (int64) - if t.WindowPoStProofType >= 0 { - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.WindowPoStProofType)); err != nil { - return err - } - } else { - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.WindowPoStProofType-1)); err != nil { + for _, v := range t.Miners { + if err := marshalCBORString(w, v); err != nil { return err } } - // t.PeerId ([]uint8) (slice) - if len(t.PeerId) > cbg.ByteArrayMaxLen { - return xerrors.Errorf("Byte array in field t.PeerId was too long") - } - - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajByteString, uint64(len(t.PeerId))); err != nil { - return err - } - - if _, err := w.Write(t.PeerId[:]); err != nil { - return err - } - - // t.Multiaddrs ([][]uint8) (slice) - if len(t.Multiaddrs) > cbg.MaxLength { - return xerrors.Errorf("Slice value in field t.Multiaddrs was too long") - } - - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.Multiaddrs))); err != nil { - return err - } - for _, v := range t.Multiaddrs { - if len(v) > cbg.ByteArrayMaxLen { - return xerrors.Errorf("Byte array in field v was too long") - } - - if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajByteString, uint64(len(v))); err != nil { - return err - } - - if _, err := w.Write(v[:]); err != nil { - return err - } - } return nil } -func (t *MinerConstructorParams) UnmarshalCBOR(r io.Reader) error { - *t = MinerConstructorParams{} +func (t *AddMinerParams) UnmarshalCBOR(r io.Reader) error { + *t = AddMinerParams{} br := cbg.GetPeeker(r) scratch := make([]byte, 8) @@ -931,37 +182,18 @@ func (t *MinerConstructorParams) UnmarshalCBOR(r io.Reader) error { return fmt.Errorf("cbor input should be of type array") } - if extra != 6 { + if extra != 1 { return fmt.Errorf("cbor input had wrong number of fields") } - // t.OwnerAddr (address.Address) (struct) - - { - - if err := t.OwnerAddr.UnmarshalCBOR(br); err != nil { - return xerrors.Errorf("unmarshaling t.OwnerAddr: %w", err) - } - - } - // t.WorkerAddr (address.Address) (struct) - - { - - if err := t.WorkerAddr.UnmarshalCBOR(br); err != nil { - return xerrors.Errorf("unmarshaling t.WorkerAddr: %w", err) - } - - } - // t.ControlAddrs ([]address.Address) (slice) - + // t.Miners ([]string) (slice) maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) if err != nil { return err } if extra > cbg.MaxLength { - return fmt.Errorf("t.ControlAddrs: array too large (%d)", extra) + return fmt.Errorf("t.Miners: array too large (%d)", extra) } if maj != cbg.MajArray { @@ -969,110 +201,17 @@ func (t *MinerConstructorParams) UnmarshalCBOR(r io.Reader) error { } if extra > 0 { - t.ControlAddrs = make([]address.Address, extra) + t.Miners = make([]string, extra) } for i := 0; i < int(extra); i++ { - var v address.Address - if err := v.UnmarshalCBOR(br); err != nil { - return err - } - - t.ControlAddrs[i] = v - } - - // t.WindowPoStProofType (abi.RegisteredPoStProof) (int64) - { - maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) - var extraI int64 + m, err := cbg.ReadString(br) if err != nil { return err } - switch maj { - case cbg.MajUnsignedInt: - extraI = int64(extra) - if extraI < 0 { - return fmt.Errorf("int64 positive overflow") - } - case cbg.MajNegativeInt: - extraI = int64(extra) - if extraI < 0 { - return fmt.Errorf("int64 negative oveflow") - } - extraI = -1 - extraI - default: - return fmt.Errorf("wrong type for int64 field: %d", maj) - } - - t.WindowPoStProofType = abi.RegisteredPoStProof(extraI) - } - // t.PeerId ([]uint8) (slice) - - maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) - if err != nil { - return err - } - - if extra > cbg.ByteArrayMaxLen { - return fmt.Errorf("t.PeerId: byte array too large (%d)", extra) - } - if maj != cbg.MajByteString { - return fmt.Errorf("expected byte array") - } - if extra > 0 { - t.PeerId = make([]uint8, extra) - } - - if _, err := io.ReadFull(br, t.PeerId[:]); err != nil { - return err - } - // t.Multiaddrs ([][]uint8) (slice) - - maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) - if err != nil { - return err - } - - if extra > cbg.MaxLength { - return fmt.Errorf("t.Multiaddrs: array too large (%d)", extra) - } - - if maj != cbg.MajArray { - return fmt.Errorf("expected cbor array") - } - - if extra > 0 { - t.Multiaddrs = make([][]uint8, extra) - } - - for i := 0; i < int(extra); i++ { - { - var maj byte - var extra uint64 - var err error - - maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) - if err != nil { - return err - } - - if extra > cbg.ByteArrayMaxLen { - return fmt.Errorf("t.Multiaddrs[i]: byte array too large (%d)", extra) - } - if maj != cbg.MajByteString { - return fmt.Errorf("expected byte array") - } - - if extra > 0 { - t.Multiaddrs[i] = make([]uint8, extra) - } - - if _, err := io.ReadFull(br, t.Multiaddrs[i][:]); err != nil { - return err - } - } + t.Miners[i] = m } return nil diff --git a/chain/consensus/actors/mpower/policy.go b/chain/consensus/actors/mpower/policy.go deleted file mode 100644 index 909da4e4b..000000000 --- a/chain/consensus/actors/mpower/policy.go +++ /dev/null @@ -1,12 +0,0 @@ -package mpower - -// The number of miners that must meet the consensus minimum miner power before that minimum power is enforced -// as a condition of leader election. -// This ensures a network still functions before any miners reach that threshold. -const ConsensusMinerMinMiners = 4 // PARAM_SPEC - -// Maximum number of prove-commits each miner can submit in one epoch. -// -// This limits the number of proof partitions we may need to load in the cron call path. -// Onboarding 1EiB/year requires at least 32 prove-commits per epoch. -const MaxMinerProveCommitsPerEpoch = 200 // PARAM_SPEC diff --git a/chain/consensus/actors/mpower/power_actor.go b/chain/consensus/actors/mpower/power_actor.go index 7186a7289..6961a8bef 100644 --- a/chain/consensus/actors/mpower/power_actor.go +++ b/chain/consensus/actors/mpower/power_actor.go @@ -1,38 +1,21 @@ package mpower import ( - "bytes" - - addr "github.com/filecoin-project/go-address" address "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/cbor" "github.com/filecoin-project/go-state-types/exitcode" - rtt "github.com/filecoin-project/go-state-types/rt" actor "github.com/filecoin-project/lotus/chain/consensus/actors" - xerrors "golang.org/x/xerrors" - power0 "github.com/filecoin-project/specs-actors/actors/builtin/power" "github.com/ipfs/go-cid" "github.com/filecoin-project/specs-actors/v6/actors/builtin" - initact "github.com/filecoin-project/specs-actors/v6/actors/builtin/init" - "github.com/filecoin-project/specs-actors/v6/actors/builtin/reward" "github.com/filecoin-project/specs-actors/v6/actors/runtime" - "github.com/filecoin-project/specs-actors/v6/actors/runtime/proof" "github.com/filecoin-project/specs-actors/v6/actors/util/adt" - "github.com/filecoin-project/specs-actors/v6/actors/util/smoothing" ) type Runtime = runtime.Runtime -type SectorTermination int64 - -const ( - ErrTooManyProveCommits = exitcode.FirstActorSpecificExitCode + iota -) - type Actor struct{} var PowerActorAddr = func() address.Address { @@ -46,14 +29,7 @@ var PowerActorAddr = func() address.Address { func (a Actor) Exports() []interface{} { return []interface{}{ builtin.MethodConstructor: a.Constructor, - 2: a.CreateMiner, - 3: a.UpdateClaimedPower, - 4: a.EnrollCronEvent, - 5: a.OnEpochTickEnd, - 6: a.UpdatePledgeTotal, - 7: nil, // deprecated - 8: a.SubmitPoRepForBulkVerify, - 9: a.CurrentTotalPower, + 2: a.AddMiner, } } @@ -71,19 +47,6 @@ func (a Actor) State() cbor.Er { var _ runtime.VMActor = Actor{} -// Storage miner actor constructor params are defined here so the power actor can send them to the init actor -// to instantiate miners. -// Changed since v2: -// - Seal proof type replaced with PoSt proof type -type MinerConstructorParams struct { - OwnerAddr addr.Address - WorkerAddr addr.Address - ControlAddrs []addr.Address - WindowPoStProofType abi.RegisteredPoStProof - PeerId abi.PeerID - Multiaddrs []abi.Multiaddrs -} - //////////////////////////////////////////////////////////////////////////////// // Actor methods //////////////////////////////////////////////////////////////////////////////// @@ -97,477 +60,18 @@ func (a Actor) Constructor(rt Runtime, _ *abi.EmptyValue) *abi.EmptyValue { return nil } -// Changed since v2: -// - Seal proof type replaced with PoSt proof types -type CreateMinerParams struct { - Owner addr.Address - Worker addr.Address - WindowPoStProofType abi.RegisteredPoStProof - Peer abi.PeerID - Multiaddrs []abi.Multiaddrs -} - -//type CreateMinerReturn struct { -// IDAddress addr.Address // The canonical ID-based address for the actor. -// RobustAddress addr.Address // A more expensive but re-org-safe address for the newly created actor. -//} -type CreateMinerReturn = power0.CreateMinerReturn - -func (a Actor) CreateMiner(rt Runtime, params *CreateMinerParams) *CreateMinerReturn { - rt.ValidateImmediateCallerAcceptAny() - - ctorParams := MinerConstructorParams{ - OwnerAddr: params.Owner, - WorkerAddr: params.Worker, - WindowPoStProofType: params.WindowPoStProofType, - PeerId: params.Peer, - Multiaddrs: params.Multiaddrs, - } - ctorParamBuf := new(bytes.Buffer) - err := ctorParams.MarshalCBOR(ctorParamBuf) - builtin.RequireNoErr(rt, err, exitcode.ErrSerialization, "failed to serialize miner constructor params %v", ctorParams) - - var addresses initact.ExecReturn - code := rt.Send( - builtin.InitActorAddr, - builtin.MethodsInit.Exec, - &initact.ExecParams{ - CodeCID: builtin.StorageMinerActorCodeID, - ConstructorParams: ctorParamBuf.Bytes(), - }, - rt.ValueReceived(), // Pass on any value to the new actor. - &addresses, - ) - builtin.RequireSuccess(rt, code, "failed to init new actor") - - var st State - rt.StateTransaction(&st, func() { - claims, err := adt.AsMap(adt.AsStore(rt), st.Claims, builtin.DefaultHamtBitwidth) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load claims") - - err = setClaim(claims, addresses.IDAddress, &Claim{params.WindowPoStProofType, abi.NewStoragePower(0), abi.NewStoragePower(0)}) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to put power in claimed table while creating miner") - - st.MinerCount += 1 - - // Ensure new claim updates all power stats - err = st.updateStatsForNewMiner(params.WindowPoStProofType) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed update power stats for new miner %v", addresses.IDAddress) - - st.Claims, err = claims.Root() - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to flush claims") - }) - return &CreateMinerReturn{ - IDAddress: addresses.IDAddress, - RobustAddress: addresses.RobustAddress, - } +type AddMinerParams struct { + Miners []string } -//type UpdateClaimedPowerParams struct { -// RawByteDelta abi.StoragePower -// QualityAdjustedDelta abi.StoragePower -//} -type UpdateClaimedPowerParams = power0.UpdateClaimedPowerParams - // Adds or removes claimed power for the calling actor. // May only be invoked by a miner actor. -func (a Actor) UpdateClaimedPower(rt Runtime, params *UpdateClaimedPowerParams) *abi.EmptyValue { +func (a Actor) AddMiner(rt Runtime, params *AddMinerParams) *abi.EmptyValue { rt.ValidateImmediateCallerAcceptAny() - minerAddr := rt.Caller() var st State rt.StateTransaction(&st, func() { - claims, err := adt.AsMap(adt.AsStore(rt), st.Claims, builtin.DefaultHamtBitwidth) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load claims") - st.MinerCount += 1 - - err = st.addToClaim(claims, minerAddr, params.RawByteDelta, params.QualityAdjustedDelta) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to update power raw %s, qa %s", params.RawByteDelta, params.QualityAdjustedDelta) - - st.Claims, err = claims.Root() - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to flush claims") - }) - return nil -} - -//type EnrollCronEventParams struct { -// EventEpoch abi.ChainEpoch -// Payload []byte -//} -type EnrollCronEventParams = power0.EnrollCronEventParams - -func (a Actor) EnrollCronEvent(rt Runtime, params *EnrollCronEventParams) *abi.EmptyValue { - rt.ValidateImmediateCallerType(builtin.StorageMinerActorCodeID) - minerAddr := rt.Caller() - minerEvent := CronEvent{ - MinerAddr: minerAddr, - CallbackPayload: params.Payload, - } - - // Ensure it is not possible to enter a large negative number which would cause problems in cron processing. - if params.EventEpoch < 0 { - rt.Abortf(exitcode.ErrIllegalArgument, "cron event epoch %d cannot be less than zero", params.EventEpoch) - } - - var st State - rt.StateTransaction(&st, func() { - events, err := adt.AsMultimap(adt.AsStore(rt), st.CronEventQueue, CronQueueHamtBitwidth, CronQueueAmtBitwidth) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load cron events") - - err = st.appendCronEvent(events, params.EventEpoch, &minerEvent) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to enroll cron event") - - st.CronEventQueue, err = events.Root() - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to flush cron events") - }) - return nil -} - -// Called by Cron. -func (a Actor) OnEpochTickEnd(rt Runtime, _ *abi.EmptyValue) *abi.EmptyValue { - rt.ValidateImmediateCallerIs(builtin.CronActorAddr) - - var rewret reward.ThisEpochRewardReturn - rewretcode := rt.Send(builtin.RewardActorAddr, builtin.MethodsReward.ThisEpochReward, nil, big.Zero(), &rewret) - builtin.RequireSuccess(rt, rewretcode, "failed to check epoch baseline power") - - if err := a.processBatchProofVerifies(rt, rewret); err != nil { - rt.Log(rtt.ERROR, "unexpected error processing batch proof verifies: %s. Skipping all verification for epoch %d", err, rt.CurrEpoch()) - } - a.processDeferredCronEvents(rt, rewret) - - var st State - rt.StateTransaction(&st, func() { - // update next epoch's power and pledge values - // this must come before the next epoch's rewards are calculated - // so that next epoch reward reflects power added this epoch - rawBytePower, qaPower := CurrentTotalPower(&st) - st.ThisEpochPledgeCollateral = st.TotalPledgeCollateral - st.ThisEpochQualityAdjPower = qaPower - st.ThisEpochRawBytePower = rawBytePower - // we can now assume delta is one since cron is invoked on every epoch. - st.updateSmoothedEstimate(abi.ChainEpoch(1)) - }) - - // update network KPI in RewardActor - code := rt.Send( - builtin.RewardActorAddr, - builtin.MethodsReward.UpdateNetworkKPI, - &st.ThisEpochRawBytePower, - abi.NewTokenAmount(0), - &builtin.Discard{}, - ) - builtin.RequireSuccess(rt, code, "failed to update network KPI with Reward Actor") - - return nil -} - -func (a Actor) UpdatePledgeTotal(rt Runtime, pledgeDelta *abi.TokenAmount) *abi.EmptyValue { - rt.ValidateImmediateCallerType(builtin.StorageMinerActorCodeID) - var st State - rt.StateTransaction(&st, func() { - validateMinerHasClaim(rt, st, rt.Caller()) - st.addPledgeTotal(*pledgeDelta) - builtin.RequireState(rt, st.TotalPledgeCollateral.GreaterThanEqual(big.Zero()), "negative total pledge collateral %v", st.TotalPledgeCollateral) - }) - return nil -} - -// GasOnSubmitVerifySeal is amount of gas charged for SubmitPoRepForBulkVerify -// This number is empirically determined -const GasOnSubmitVerifySeal = 34721049 - -func (a Actor) SubmitPoRepForBulkVerify(rt Runtime, sealInfo *proof.SealVerifyInfo) *abi.EmptyValue { - rt.ValidateImmediateCallerType(builtin.StorageMinerActorCodeID) - - minerAddr := rt.Caller() - - var st State - rt.StateTransaction(&st, func() { - validateMinerHasClaim(rt, st, minerAddr) - - store := adt.AsStore(rt) - var mmap *adt.Multimap - var err error - if st.ProofValidationBatch == nil { - mmap, err = adt.MakeEmptyMultimap(store, builtin.DefaultHamtBitwidth, ProofValidationBatchAmtBitwidth) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to create empty proof validation set") - rt.Log(rtt.DEBUG, "ProofValidationBatch created") - } else { - mmap, err = adt.AsMultimap(adt.AsStore(rt), *st.ProofValidationBatch, builtin.DefaultHamtBitwidth, ProofValidationBatchAmtBitwidth) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load proof batch set") - } - - arr, found, err := mmap.Get(abi.AddrKey(minerAddr)) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to get get seal verify infos at addr %s", minerAddr) - if found && arr.Length() >= MaxMinerProveCommitsPerEpoch { - rt.Abortf(ErrTooManyProveCommits, "miner %s attempting to prove commit over %d sectors in epoch", minerAddr, MaxMinerProveCommitsPerEpoch) - } - - err = mmap.Add(abi.AddrKey(minerAddr), sealInfo) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to insert proof into batch") - - mmrc, err := mmap.Root() - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to flush proof batch") - - rt.ChargeGas("OnSubmitVerifySeal", GasOnSubmitVerifySeal, 0) - st.ProofValidationBatch = &mmrc + st.Miners = params.Miners }) - return nil } - -// Changed since v0: -// - QualityAdjPowerSmoothed is not a pointer -type CurrentTotalPowerReturn struct { - RawBytePower abi.StoragePower - QualityAdjPower abi.StoragePower - PledgeCollateral abi.TokenAmount - QualityAdjPowerSmoothed smoothing.FilterEstimate -} - -// Returns the total power and pledge recorded by the power actor. -// The returned values are frozen during the cron tick before this epoch -// so that this method returns consistent values while processing all messages -// of an epoch. -func (a Actor) CurrentTotalPower(rt Runtime, _ *abi.EmptyValue) *CurrentTotalPowerReturn { - rt.ValidateImmediateCallerAcceptAny() - var st State - rt.StateReadonly(&st) - - return &CurrentTotalPowerReturn{ - RawBytePower: st.ThisEpochRawBytePower, - QualityAdjPower: st.ThisEpochQualityAdjPower, - PledgeCollateral: st.ThisEpochPledgeCollateral, - QualityAdjPowerSmoothed: st.ThisEpochQAPowerSmoothed, - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Method utility functions -//////////////////////////////////////////////////////////////////////////////// - -func validateMinerHasClaim(rt Runtime, st State, minerAddr addr.Address) { - claims, err := adt.AsMap(adt.AsStore(rt), st.Claims, builtin.DefaultHamtBitwidth) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load claims") - - found, err := claims.Has(abi.AddrKey(minerAddr)) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to look up claim") - if !found { - rt.Abortf(exitcode.ErrForbidden, "unknown miner %s forbidden to interact with power actor", minerAddr) - } -} - -func (a Actor) processBatchProofVerifies(rt Runtime, rewret reward.ThisEpochRewardReturn) error { - var st State - - var miners []addr.Address - verifies := make(map[addr.Address][]proof.SealVerifyInfo) - - var stErr error - rt.StateTransaction(&st, func() { - store := adt.AsStore(rt) - if st.ProofValidationBatch == nil { - rt.Log(rtt.DEBUG, "ProofValidationBatch was nil, quitting verification") - return - } - mmap, err := adt.AsMultimap(store, *st.ProofValidationBatch, builtin.DefaultHamtBitwidth, ProofValidationBatchAmtBitwidth) - if err != nil { - stErr = xerrors.Errorf("failed to load proofs validation batch: %w", err) - return - } - - claims, err := adt.AsMap(adt.AsStore(rt), st.Claims, builtin.DefaultHamtBitwidth) - if err != nil { - stErr = xerrors.Errorf("failed to load claims: %w", err) - return - } - - err = mmap.ForAll(func(k string, arr *adt.Array) error { - a, err := addr.NewFromBytes([]byte(k)) - if err != nil { - return xerrors.Errorf("failed to parse address key: %w", err) - } - - // refuse to process proofs for miner with no claim - found, err := claims.Has(abi.AddrKey(a)) - if err != nil { - return xerrors.Errorf("failed to look up claim: %w", err) - } - if !found { - rt.Log(rtt.WARN, "skipping batch verifies for unknown miner %s", a) - return nil - } - - miners = append(miners, a) - - var infos []proof.SealVerifyInfo - var svi proof.SealVerifyInfo - err = arr.ForEach(&svi, func(i int64) error { - infos = append(infos, svi) - return nil - }) - if err != nil { - return xerrors.Errorf("failed to iterate over proof verify array for miner %s: %w", a, err) - } - - verifies[a] = infos - return nil - }) - // Do not return immediately, all runs that get this far should wipe the ProofValidationBatchQueue. - // If we leave the validation batch then in the case of a repeating state error the queue - // will quickly fill up and repeated traversals will start ballooning cron execution time. - if err != nil { - stErr = xerrors.Errorf("failed to iterate proof batch: %w", err) - } - st.ProofValidationBatch = nil - }) - if stErr != nil { - return stErr - } - - res, err := rt.BatchVerifySeals(verifies) - if err != nil { - return xerrors.Errorf("failed to batch verify: %w", err) - } - - for _, m := range miners { - vres, ok := res[m] - if !ok { - return xerrors.Errorf("batch verify seals syscall implemented incorrectly, result not found for miner: %s", m) - } - - verifs := verifies[m] - - seen := map[abi.SectorNumber]struct{}{} - var successful []abi.SectorNumber - for i, r := range vres { - if r { - snum := verifs[i].SectorID.Number - - if _, exists := seen[snum]; exists { - // filter-out duplicates - rt.Log(rtt.INFO, "skipped over a duplicate proof") - continue - } - - seen[snum] = struct{}{} - successful = append(successful, snum) - } else { - rt.Log(rtt.INFO, "a proof failed from miner %s", m) - } - } - - if len(successful) > 0 { - code := rt.Send( - m, - builtin.MethodsMiner.ConfirmSectorProofsValid, - &builtin.ConfirmSectorProofsParams{ - Sectors: successful, - RewardSmoothed: rewret.ThisEpochRewardSmoothed, - RewardBaselinePower: rewret.ThisEpochBaselinePower, - QualityAdjPowerSmoothed: st.ThisEpochQAPowerSmoothed}, - abi.NewTokenAmount(0), - &builtin.Discard{}, - ) - if code.IsError() { - rt.Log(rtt.ERROR, - "failed to confirm sector proof validity to %s, error code %d", - m, code) - } - } - } - return nil -} - -func (a Actor) processDeferredCronEvents(rt Runtime, rewret reward.ThisEpochRewardReturn) { - rtEpoch := rt.CurrEpoch() - - var cronEvents []CronEvent - var st State - rt.StateTransaction(&st, func() { - events, err := adt.AsMultimap(adt.AsStore(rt), st.CronEventQueue, CronQueueHamtBitwidth, CronQueueAmtBitwidth) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load cron events") - - claims, err := adt.AsMap(adt.AsStore(rt), st.Claims, builtin.DefaultHamtBitwidth) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load claims") - - for epoch := st.FirstCronEpoch; epoch <= rtEpoch; epoch++ { - epochEvents, err := loadCronEvents(events, epoch) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load cron events at %v", epoch) - - for _, evt := range epochEvents { - // refuse to process proofs for miner with no claim - found, err := claims.Has(abi.AddrKey(evt.MinerAddr)) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to look up claim") - if !found { - rt.Log(rtt.WARN, "skipping cron event for unknown miner %v", evt.MinerAddr) - continue - } - cronEvents = append(cronEvents, evt) - } - - if len(epochEvents) > 0 { - err = events.RemoveAll(epochKey(epoch)) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to clear cron events at %v", epoch) - } else { - rt.Log(rtt.DEBUG, "no epoch events were loaded") - } - } - - st.FirstCronEpoch = rtEpoch + 1 - - st.CronEventQueue, err = events.Root() - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to flush events") - }) - failedMinerCrons := make([]addr.Address, 0) - - for _, event := range cronEvents { - - params := builtin.DeferredCronEventParams{ - EventPayload: event.CallbackPayload, - RewardSmoothed: rewret.ThisEpochRewardSmoothed, - QualityAdjPowerSmoothed: st.ThisEpochQAPowerSmoothed, - } - - code := rt.Send( - event.MinerAddr, - builtin.MethodsMiner.OnDeferredCronEvent, - ¶ms, - abi.NewTokenAmount(0), - &builtin.Discard{}, - ) - // If a callback fails, this actor continues to invoke other callbacks - // and persists state removing the failed event from the event queue. It won't be tried again. - // Failures are unexpected here but will result in removal of miner power as a defensive measure. - if code != exitcode.Ok { - rt.Log(rtt.ERROR, "OnDeferredCronEvent failed for miner %s: exitcode %d", event.MinerAddr, code) - failedMinerCrons = append(failedMinerCrons, event.MinerAddr) - } - } - - if len(failedMinerCrons) > 0 { - rt.StateTransaction(&st, func() { - claims, err := adt.AsMap(adt.AsStore(rt), st.Claims, builtin.DefaultHamtBitwidth) - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load claims") - - // Remove miner claim and leave miner frozen - for _, minerAddr := range failedMinerCrons { - found, err := st.deleteClaim(claims, minerAddr) - if err != nil { - rt.Log(rtt.ERROR, "failed to delete claim for miner %s after failing OnDeferredCronEvent: %s", minerAddr, err) - continue - } else if !found { - rt.Log(rtt.ERROR, "can't find claim for miner %s after failing OnDeferredCronEvent: %s", minerAddr, err) - continue - } - - // Decrement miner count to keep stats consistent. - st.MinerCount-- - } - - st.Claims, err = claims.Root() - builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to flush claims") - }) - } -} diff --git a/chain/consensus/actors/mpower/power_state.go b/chain/consensus/actors/mpower/power_state.go index 0bd4289ae..5f5a5030b 100644 --- a/chain/consensus/actors/mpower/power_state.go +++ b/chain/consensus/actors/mpower/power_state.go @@ -1,308 +1,19 @@ package mpower import ( - "fmt" - "reflect" - - addr "github.com/filecoin-project/go-address" - "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/go-state-types/big" - cid "github.com/ipfs/go-cid" - "golang.org/x/xerrors" - - "github.com/filecoin-project/specs-actors/v6/actors/builtin" "github.com/filecoin-project/specs-actors/v6/actors/util/adt" - "github.com/filecoin-project/specs-actors/v6/actors/util/smoothing" ) -// genesis power in bytes = 750,000 GiB -var InitialQAPowerEstimatePosition = big.Mul(big.NewInt(750_000), big.NewInt(1<<30)) - -// max chain throughput in bytes per epoch = 120 ProveCommits / epoch = 3,840 GiB -var InitialQAPowerEstimateVelocity = big.Mul(big.NewInt(3_840), big.NewInt(1<<30)) - -// Bitwidth of CronEventQueue HAMT determined empirically from mutation -// patterns and projections of mainnet data. -const CronQueueHamtBitwidth = 6 - -// Bitwidth of CronEventQueue AMT determined empirically from mutation -// patterns and projections of mainnet data. -const CronQueueAmtBitwidth = 6 - -// Bitwidth of ProofValidationBatch AMT determined empirically from mutation -// pattersn and projections of mainnet data. -const ProofValidationBatchAmtBitwidth = 4 - +// Mpower actor is only used to determine if a new miner joined or not when running the checkpointing module +// in delegated mode (easier for development) type State struct { - TotalRawBytePower abi.StoragePower - // TotalBytesCommitted includes claims from miners below min power threshold - TotalBytesCommitted abi.StoragePower - TotalQualityAdjPower abi.StoragePower - // TotalQABytesCommitted includes claims from miners below min power threshold - TotalQABytesCommitted abi.StoragePower - TotalPledgeCollateral abi.TokenAmount - - // These fields are set once per epoch in the previous cron tick and used - // for consistent values across a single epoch's state transition. - ThisEpochRawBytePower abi.StoragePower - ThisEpochQualityAdjPower abi.StoragePower - ThisEpochPledgeCollateral abi.TokenAmount - ThisEpochQAPowerSmoothed smoothing.FilterEstimate - MinerCount int64 - // Number of miners having proven the minimum consensus power. - MinerAboveMinPowerCount int64 - - // A queue of events to be triggered by cron, indexed by epoch. - CronEventQueue cid.Cid // Multimap, (HAMT[ChainEpoch]AMT[CronEvent]) - - // First epoch in which a cron task may be stored. - // Cron will iterate every epoch between this and the current epoch inclusively to find tasks to execute. - FirstCronEpoch abi.ChainEpoch - - // Claimed power for each miner. - Claims cid.Cid // Map, HAMT[address]Claim - - ProofValidationBatch *cid.Cid // Multimap, (HAMT[Address]AMT[SealVerifyInfo]) -} - -type Claim struct { - // Miner's proof type used to determine minimum miner size - WindowPoStProofType abi.RegisteredPoStProof - - // Sum of raw byte power for a miner's sectors. - RawBytePower abi.StoragePower - - // Sum of quality adjusted power for a miner's sectors. - QualityAdjPower abi.StoragePower -} - -type CronEvent struct { - MinerAddr addr.Address - CallbackPayload []byte + Miners []string } func ConstructState(store adt.Store) (*State, error) { - emptyClaimsMapCid, err := adt.StoreEmptyMap(store, builtin.DefaultHamtBitwidth) - if err != nil { - return nil, xerrors.Errorf("failed to create empty map: %w", err) - } - emptyCronQueueMMapCid, err := adt.StoreEmptyMultimap(store, CronQueueHamtBitwidth, CronQueueAmtBitwidth) - if err != nil { - return nil, xerrors.Errorf("failed to create empty multimap: %w", err) - } - return &State{ - TotalRawBytePower: abi.NewStoragePower(0), - TotalBytesCommitted: abi.NewStoragePower(0), - TotalQualityAdjPower: abi.NewStoragePower(0), - TotalQABytesCommitted: abi.NewStoragePower(0), - TotalPledgeCollateral: abi.NewTokenAmount(0), - ThisEpochRawBytePower: abi.NewStoragePower(0), - ThisEpochQualityAdjPower: abi.NewStoragePower(0), - ThisEpochPledgeCollateral: abi.NewTokenAmount(0), - ThisEpochQAPowerSmoothed: smoothing.NewEstimate(InitialQAPowerEstimatePosition, InitialQAPowerEstimateVelocity), - FirstCronEpoch: 0, - CronEventQueue: emptyCronQueueMMapCid, - Claims: emptyClaimsMapCid, - MinerCount: 0, - MinerAboveMinPowerCount: 0, + MinerCount: 0, + Miners: make([]string, 0), }, nil } - -// MinerNominalPowerMeetsConsensusMinimum is used to validate Election PoSt -// winners outside the chain state. If the miner has over a threshold of power -// the miner meets the minimum. If the network is a below a threshold of -// miners and has power > zero the miner meets the minimum. -func (st *State) MinerNominalPowerMeetsConsensusMinimum(s adt.Store, miner addr.Address) (bool, error) { //nolint:deadcode,unused - claims, err := adt.AsMap(s, st.Claims, builtin.DefaultHamtBitwidth) - if err != nil { - return false, xerrors.Errorf("failed to load claims: %w", err) - } - - claim, ok, err := getClaim(claims, miner) - if err != nil { - return false, err - } - if !ok { - return false, xerrors.Errorf("no claim for actor %w", miner) - } - - minerNominalPower := claim.RawBytePower - minerMinPower, err := builtin.ConsensusMinerMinPower(claim.WindowPoStProofType) - if err != nil { - return false, xerrors.Errorf("could not get miner min power from proof type: %w", err) - } - - // if miner is larger than min power requirement, we're set - if minerNominalPower.GreaterThanEqual(minerMinPower) { - return true, nil - } - - // otherwise, if ConsensusMinerMinMiners miners meet min power requirement, return false - if st.MinerAboveMinPowerCount >= ConsensusMinerMinMiners { - return false, nil - } - - // If fewer than ConsensusMinerMinMiners over threshold miner can win a block with non-zero power - return minerNominalPower.GreaterThan(abi.NewStoragePower(0)), nil -} - -// Parameters may be negative to subtract. -func (st *State) AddToClaim(s adt.Store, miner addr.Address, power abi.StoragePower, qapower abi.StoragePower) error { - claims, err := adt.AsMap(s, st.Claims, builtin.DefaultHamtBitwidth) - if err != nil { - return xerrors.Errorf("failed to load claims: %w", err) - } - - if err := st.addToClaim(claims, miner, power, qapower); err != nil { - return xerrors.Errorf("failed to add claim: %w", err) - } - - st.Claims, err = claims.Root() - if err != nil { - return xerrors.Errorf("failed to flush claims: %w", err) - } - - return nil -} - -func (st *State) GetClaim(s adt.Store, a addr.Address) (*Claim, bool, error) { - claims, err := adt.AsMap(s, st.Claims, builtin.DefaultHamtBitwidth) - if err != nil { - return nil, false, xerrors.Errorf("failed to load claims: %w", err) - } - return getClaim(claims, a) -} - -func (st *State) addToClaim(claims *adt.Map, miner addr.Address, power abi.StoragePower, qapower abi.StoragePower) error { - // TotalBytes always update directly - st.TotalQABytesCommitted = big.Add(st.TotalQABytesCommitted, qapower) - st.TotalBytesCommitted = big.Add(st.TotalBytesCommitted, power) - - oldClaim := Claim{ - WindowPoStProofType: 0, - RawBytePower: big.NewInt(0), - QualityAdjPower: big.NewInt(0), - } - - newClaim := Claim{ - WindowPoStProofType: oldClaim.WindowPoStProofType, - RawBytePower: big.Add(oldClaim.RawBytePower, power), - QualityAdjPower: big.Add(oldClaim.QualityAdjPower, qapower), - } - - return setClaim(claims, miner, &newClaim) -} - -func (st *State) updateStatsForNewMiner(windowPoStProof abi.RegisteredPoStProof) error { - minPower, err := builtin.ConsensusMinerMinPower(windowPoStProof) - if err != nil { - return fmt.Errorf("could not get consensus miner min power: %w", err) - } - - if minPower.LessThanEqual(big.Zero()) { - st.MinerAboveMinPowerCount++ - } - return nil -} - -func (st *State) deleteClaim(claims *adt.Map, miner addr.Address) (bool, error) { - // Note: this flow loads the claim multiple times, unnecessarily. - // We should refactor to use claims.Pop(). - oldClaim, ok, err := getClaim(claims, miner) - if err != nil { - return false, fmt.Errorf("failed to get claim: %w", err) - } - if !ok { - return false, nil // no record, we're done - } - - // subtract from stats as if we were simply removing power - err = st.addToClaim(claims, miner, oldClaim.RawBytePower.Neg(), oldClaim.QualityAdjPower.Neg()) - if err != nil { - return false, fmt.Errorf("failed to subtract miner power before deleting claim: %w", err) - } - - // delete claim from state to invalidate miner - return true, claims.Delete(abi.AddrKey(miner)) -} - -func getClaim(claims *adt.Map, a addr.Address) (*Claim, bool, error) { - var out Claim - found, err := claims.Get(abi.AddrKey(a), &out) - if err != nil { - return nil, false, xerrors.Errorf("failed to get claim for address %v: %w", a, err) - } - if !found { - return nil, false, nil - } - return &out, true, nil -} - -func (st *State) addPledgeTotal(amount abi.TokenAmount) { - st.TotalPledgeCollateral = big.Add(st.TotalPledgeCollateral, amount) -} - -func (st *State) appendCronEvent(events *adt.Multimap, epoch abi.ChainEpoch, event *CronEvent) error { - // if event is in past, alter FirstCronEpoch so it will be found. - if epoch < st.FirstCronEpoch { - st.FirstCronEpoch = epoch - } - - if err := events.Add(epochKey(epoch), event); err != nil { - return xerrors.Errorf("failed to store cron event at epoch %v for miner %v: %w", epoch, event, err) - } - - return nil -} - -func (st *State) updateSmoothedEstimate(delta abi.ChainEpoch) { - filterQAPower := smoothing.LoadFilter(st.ThisEpochQAPowerSmoothed, smoothing.DefaultAlpha, smoothing.DefaultBeta) - st.ThisEpochQAPowerSmoothed = filterQAPower.NextEstimate(st.ThisEpochQualityAdjPower, delta) -} - -func loadCronEvents(mmap *adt.Multimap, epoch abi.ChainEpoch) ([]CronEvent, error) { - var events []CronEvent - var ev CronEvent - err := mmap.ForEach(epochKey(epoch), &ev, func(i int64) error { - events = append(events, ev) - return nil - }) - return events, err -} - -func setClaim(claims *adt.Map, a addr.Address, claim *Claim) error { - if claim.RawBytePower.LessThan(big.Zero()) { - return xerrors.Errorf("negative claim raw power %v", claim.RawBytePower) - } - if claim.QualityAdjPower.LessThan(big.Zero()) { - return xerrors.Errorf("negative claim quality-adjusted power %v", claim.QualityAdjPower) - } - if err := claims.Put(abi.AddrKey(a), claim); err != nil { - return xerrors.Errorf("failed to put claim with address %s power %v: %w", a, claim, err) - } - return nil -} - -// CurrentTotalPower returns current power values accounting for minimum miner -// and minimum power -func CurrentTotalPower(st *State) (abi.StoragePower, abi.StoragePower) { - if st.MinerAboveMinPowerCount < ConsensusMinerMinMiners { - return st.TotalBytesCommitted, st.TotalQABytesCommitted - } - return st.TotalRawBytePower, st.TotalQualityAdjPower -} - -func epochKey(e abi.ChainEpoch) abi.Keyer { - return abi.IntKey(int64(e)) -} - -func init() { - // Check that ChainEpoch is indeed a signed integer to confirm that epochKey is making the right interpretation. - var e abi.ChainEpoch - if reflect.TypeOf(e).Kind() != reflect.Int64 { - panic("incorrect chain epoch encoding") - } - -} diff --git a/data/dom/config.toml b/data/dom/config.toml index 972f0b5a0..5b78021ab 100644 --- a/data/dom/config.toml +++ b/data/dom/config.toml @@ -29,7 +29,7 @@ # # type: []string # env var: LOTUS_LIBP2P_LISTENADDRESSES - ListenAddresses = ["/ip4/0.0.0.0/tcp/0", "/ip6/::/tcp/0"] + ListenAddresses = ["/ip4/0.0.0.0/tcp/0"] # Addresses to explicitally announce to other peers. If not specified, # all interface addresses are announced diff --git a/data/script.py b/data/script.py new file mode 100644 index 000000000..d21e07bad --- /dev/null +++ b/data/script.py @@ -0,0 +1,21 @@ +import sys + +print(sys.argv[1]) + +f = open(sys.argv[1],"r") +lines = f.readlines() + +participants = [] +count = 0 +command = 'eudico send --from t1d2xrzcslx7xlbbylc5c3d5lvandqw4iwl6epxba --method 2 --params-json "{\"Miners\":[' +for line in lines: + count += 1 + participant = line.split('/')[-1].rstrip() + participants.append(participant) + command = command + '\\"' + participant + '\\"' + if count < len(lines): + command = command + ',' + +command = command + ']}" t065 0' + +print(command) diff --git a/scripts/taproot.sh b/scripts/taproot.sh index b98af788d..b9fb89f08 100755 --- a/scripts/taproot.sh +++ b/scripts/taproot.sh @@ -17,6 +17,12 @@ curl -u satoshi:amiens -X POST \ -d "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"generatetoaddress\", \"params\": [150, \"$ADDRESS\"]}" \ -H 'Content-Type:application/json' +curl -u satoshi:amiens -X POST \ + 127.0.0.1:18443 \ + -d "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"sendtoaddress\", \"params\": [\"bcrt1p4ffl08gtqmc00j3cdc8x9tnqy8u4c0lr8vryny8um605qd78w7vs90n7mx\", 50]}" \ + -H 'Content-Type:application/json' + + tmux \ new-session 'EUDICO_PATH=$PWD/data/alice ./eudico delegated daemon --genesis=gen.gen; sleep infinity' \; \ split-window -h 'EUDICO_PATH=$PWD/data/bob ./eudico delegated daemon --genesis=gen.gen; sleep infinity' \; \ From a797c8c60a97565808e6db3cab5c112f2e6c6fd3 Mon Sep 17 00:00:00 2001 From: rllola Date: Tue, 18 Jan 2022 16:56:05 +0100 Subject: [PATCH 14/23] more comments --- chain/checkpointing/storage.go | 6 +-- chain/checkpointing/sub.go | 47 +++++++++++++------ chain/consensus/actors/mpower/power_actor.go | 8 +++- chain/consensus/actors/mpower/power_state.go | 3 +- .../hierarchical/actors/subnet/genesis.go | 2 + 5 files changed, 46 insertions(+), 20 deletions(-) diff --git a/chain/checkpointing/storage.go b/chain/checkpointing/storage.go index 6af5bce98..36884fe29 100644 --- a/chain/checkpointing/storage.go +++ b/chain/checkpointing/storage.go @@ -12,7 +12,7 @@ import ( "github.com/minio/minio-go/v7" ) -func StoreConfig(ctx context.Context, minioClient *minio.Client, bucketName, hash string) error { +func StoreMinersConfig(ctx context.Context, minioClient *minio.Client, bucketName, hash string) error { filename := hash + ".txt" filePath := "/tmp/" + filename contentType := "text/plain" @@ -25,7 +25,7 @@ func StoreConfig(ctx context.Context, minioClient *minio.Client, bucketName, has return nil } -func CreateConfig(data []byte) ([]byte, error) { +func CreateMinersConfig(data []byte) ([]byte, error) { hash := sha256.Sum256(data) err := os.WriteFile("/tmp/"+hex.EncodeToString(hash[:])+".txt", data, 0644) @@ -36,7 +36,7 @@ func CreateConfig(data []byte) ([]byte, error) { return hash[:], nil } -func GetConfig(ctx context.Context, minioClient *minio.Client, bucketName, hash string) (string, error) { +func GetMinersConfig(ctx context.Context, minioClient *minio.Client, bucketName, hash string) (string, error) { filename := hash + ".txt" filePath := "/tmp/verification/" + filename diff --git a/chain/checkpointing/sub.go b/chain/checkpointing/sub.go index d340bce43..758471d34 100644 --- a/chain/checkpointing/sub.go +++ b/chain/checkpointing/sub.go @@ -218,6 +218,10 @@ func NewCheckpointSub( func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { checkFunc := func(ctx context.Context, ts *types.TipSet) (done bool, more bool, err error) { + + // Verify if we are sync here (maybe ?) + // if not sync return done = true and more = false + return false, true, nil } @@ -236,6 +240,7 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { defer c.lk.Unlock() // verify we are synced + // Maybe move it to checkFunc st, err := c.api.SyncState(ctx) if err != nil { log.Errorf("unable to sync: %v", err) @@ -244,11 +249,13 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { if !c.synced { // Are we synced ? + // Replace this WaitForSync logic with this function + // https://github.com/Zondax/eudico/blob/1de9d0f773e49b61cd405add93c3c28c9f74cb38/node/modules/services.go#L104 if len(st.ActiveSyncs) > 0 && st.ActiveSyncs[len(st.ActiveSyncs)-1].Height == newTs.Height() { log.Infow("we are synced") - // Yes then verify our checkpoint + // Yes then verify our checkpoint from Bitcoin and verify if we find in it in our Eudico chain ts, err := c.api.ChainGetTipSet(ctx, c.latestConfigCheckpoint) if err != nil { log.Errorf("couldnt get tipset: %v", err) @@ -263,6 +270,11 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { } } + /* + Now we compared old Power Actor State and new Power Actor State + */ + + // Get actors at specified tipset newAct, err := c.api.StateGetActor(ctx, mpower.PowerActorAddr, newTs.Key()) if err != nil { return false, nil, err @@ -273,8 +285,8 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { return false, nil, err } + // Get state from specified actors var oldSt, newSt mpower.State - bs := blockstore.NewAPIBlockstore(c.api) cst := cbor.NewCborStore(bs) if err := cst.Get(ctx, oldAct.Head, &oldSt); err != nil { @@ -284,17 +296,19 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { return false, nil, err } - // Activate checkpointing every 30 blocks + // Activate checkpointing every 25 blocks log.Infow("Height:", newTs.Height()) // NOTES: this will only work in delegated consensus // Wait for more tipset to valid the height and be sure it is valid + // NOTES: should retrieve list of signing miners using Power actor state (see Miners) and not through config instanciation if newTs.Height()%25 == 0 && (c.config != nil || c.newconfig != nil) { - log.Infow("Check point time") + log.Infow("check point time") // Initiation and config should be happening at start cp := oldTs.Key().Bytes() // If we don't have a config we don't sign but update our config with key + // NOTES: `config` refers to config taproot as mentioned in the multi-party-sig lib if c.config == nil { log.Infow("We dont have a config") pubkey := c.newconfig.PublicKey @@ -308,21 +322,23 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { c.newconfig = nil } else { - var config string = hex.EncodeToString(cp) + "\n" + // Change name to MinerConfig (checkpoint in hex and miners list)? + var minersConfig string = hex.EncodeToString(cp) + "\n" for _, partyId := range c.orderParticipantsList() { - config += partyId + "\n" + minersConfig += partyId + "\n" } - hash, err := CreateConfig([]byte(config)) + // This create the file that will be stored in minio (or any storage) + hash, err := CreateMinersConfig([]byte(minersConfig)) if err != nil { - log.Errorf("couldnt create config: %v", err) + log.Errorf("couldnt create miners config: %v", err) return false, nil, err } - // Push config to S3 - err = StoreConfig(ctx, c.minioClient, c.cpconfig.MinioBucketName, hex.EncodeToString(hash)) + // Push config to minio + err = StoreMinersConfig(ctx, c.minioClient, c.cpconfig.MinioBucketName, hex.EncodeToString(hash)) if err != nil { - log.Errorf("couldnt push config: %v", err) + log.Errorf("couldnt push miners config: %v", err) return false, nil, err } @@ -350,6 +366,9 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { return false, nil, nil } + // Listen to changes in Eudico + // `76587687658765876` <- This is the confidence threshold used to determine if the StateChangeHandler should be triggered. + // It is an absurdly high number so the metric used to determine if to trigger it or not is the number of tipsets that have passed in the heaviest chain (the 5 you see there) err := c.events.StateChanged(checkFunc, changeHandler, revertHandler, 5, 76587687658765876, match) if err != nil { return @@ -385,7 +404,6 @@ func (c *CheckpointingSub) Start(ctx context.Context) error { func (c *CheckpointingSub) GenerateNewKeys(ctx context.Context, participants []string) error { - //idsStrings := c.newOrderParticipantsList() idsStrings := participants sort.Strings(idsStrings) @@ -406,6 +424,7 @@ func (c *CheckpointingSub) GenerateNewKeys(ctx context.Context, participants []s LoopHandler(ctx, handler, n) r, err := handler.Result() if err != nil { + // if a participant is mibehaving the DKG entirely fail (no fallback) return err } log.Infow("result :", r) @@ -604,7 +623,7 @@ func BuildCheckpointingSub(mctx helpers.MetricsCtx, lc fx.Lifecycle, c *Checkpoi // Get the config in minio using the last checkpoint found through bitcoin // NOTES: We should be able to get the config regarless of storage (minio, IPFS, KVS,....) - cp, err := GetConfig(ctx, c.minioClient, c.cpconfig.MinioBucketName, btccp.cid) + cp, err := GetMinersConfig(ctx, c.minioClient, c.cpconfig.MinioBucketName, btccp.cid) if cp != "" { // Decode hex checkpoint to bytes @@ -613,7 +632,7 @@ func BuildCheckpointingSub(mctx helpers.MetricsCtx, lc fx.Lifecycle, c *Checkpoi log.Errorf("couldnt decode checkpoint: %v", err) return } - // Cache latest checkpoint value for when we sync and compare wit Eudico key tipset values + // Cache latest checkpoint value from Bitcoin for when we sync and compare wit Eudico key tipset values c.latestConfigCheckpoint, err = types.TipSetKeyFromBytes(cpBytes) if err != nil { log.Errorf("couldnt get tipset key from checkpoint: %v", err) diff --git a/chain/consensus/actors/mpower/power_actor.go b/chain/consensus/actors/mpower/power_actor.go index 6961a8bef..d4d4bce7e 100644 --- a/chain/consensus/actors/mpower/power_actor.go +++ b/chain/consensus/actors/mpower/power_actor.go @@ -18,6 +18,7 @@ type Runtime = runtime.Runtime type Actor struct{} +// Power Actor address is t065 (arbitrarly choosen) var PowerActorAddr = func() address.Address { a, err := address.NewIDAddress(65) if err != nil { @@ -28,8 +29,8 @@ var PowerActorAddr = func() address.Address { func (a Actor) Exports() []interface{} { return []interface{}{ - builtin.MethodConstructor: a.Constructor, - 2: a.AddMiner, + builtin.MethodConstructor: a.Constructor, // Initialiazed the actor; always required + 2: a.AddMiner, // Add a miner to the list (specificaly crafted for checkpointing) } } @@ -51,6 +52,7 @@ var _ runtime.VMActor = Actor{} // Actor methods //////////////////////////////////////////////////////////////////////////////// +// see https://github.com/filecoin-project/specs-actors/blob/master/actors/builtin/power/power_actor.go#L83 func (a Actor) Constructor(rt Runtime, _ *abi.EmptyValue) *abi.EmptyValue { rt.ValidateImmediateCallerIs(builtin.SystemActorAddr) @@ -60,6 +62,7 @@ func (a Actor) Constructor(rt Runtime, _ *abi.EmptyValue) *abi.EmptyValue { return nil } +// Add miners parameters structure (not in original power actor) type AddMinerParams struct { Miners []string } @@ -70,6 +73,7 @@ func (a Actor) AddMiner(rt Runtime, params *AddMinerParams) *abi.EmptyValue { rt.ValidateImmediateCallerAcceptAny() var st State rt.StateTransaction(&st, func() { + // Miners list is replaced with the one passed as parameters st.MinerCount += 1 st.Miners = params.Miners }) diff --git a/chain/consensus/actors/mpower/power_state.go b/chain/consensus/actors/mpower/power_state.go index 5f5a5030b..2e0024497 100644 --- a/chain/consensus/actors/mpower/power_state.go +++ b/chain/consensus/actors/mpower/power_state.go @@ -14,6 +14,7 @@ type State struct { func ConstructState(store adt.Store) (*State, error) { return &State{ MinerCount: 0, - Miners: make([]string, 0), + // should have participants with pre generated key + Miners: make([]string, 0), }, nil } diff --git a/chain/consensus/hierarchical/actors/subnet/genesis.go b/chain/consensus/hierarchical/actors/subnet/genesis.go index 1c1fb1b2c..687e69cf1 100644 --- a/chain/consensus/hierarchical/actors/subnet/genesis.go +++ b/chain/consensus/hierarchical/actors/subnet/genesis.go @@ -257,6 +257,8 @@ func SetupSubnetActor(ctx context.Context, bs bstore.Blockstore, networkName str return act, nil } +// This is our mocked power actor used in checkpointing module +// This function allow initializing the state in our genesis file func SetupStoragePowerActor(ctx context.Context, bs bstore.Blockstore, av actors.Version) (*types.Actor, error) { cst := cbor.NewCborStore(bs) pst, err := mpower.ConstructState(adt.WrapStore(ctx, cbor.NewCborStore(bs))) From 6ea6fdf2d8acf77f62f9904061a5afe970e67955 Mon Sep 17 00:00:00 2001 From: rllola Date: Wed, 19 Jan 2022 15:01:36 +0100 Subject: [PATCH 15/23] update multisig lib --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 04339ce05..5487c88d7 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee github.com/Kubuxu/imtui v0.0.0-20210401140320-41663d68d0fa github.com/StackExchange/wmi v1.2.1 // indirect - github.com/Zondax/multi-party-sig v0.6.0-alpha-2021-09-21.0.20211202131736-ca8cb1c7e1a1 + github.com/Zondax/multi-party-sig v0.6.0-alpha-2021-09-21.0.20220119135030-8f412195b286 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d github.com/alecthomas/jsonschema v0.0.0-20200530073317-71f438968921 github.com/btcsuite/btcutil v1.0.3-0.20210929233259-9cdf59f60c51 diff --git a/go.sum b/go.sum index 9561261a3..63d5700e2 100644 --- a/go.sum +++ b/go.sum @@ -86,6 +86,8 @@ github.com/Zondax/multi-party-sig v0.6.0-alpha-2021-09-21.0.20211117140501-65990 github.com/Zondax/multi-party-sig v0.6.0-alpha-2021-09-21.0.20211117140501-65990deeb804/go.mod h1:KOfSxMrl13ge7DX30LdWQyw4zrVzyZc9uykL77Q/TXc= github.com/Zondax/multi-party-sig v0.6.0-alpha-2021-09-21.0.20211202131736-ca8cb1c7e1a1 h1:txHoW8OAMuzzEJqKy/krlsq45hMtySGKxW6W5LIlveM= github.com/Zondax/multi-party-sig v0.6.0-alpha-2021-09-21.0.20211202131736-ca8cb1c7e1a1/go.mod h1:KOfSxMrl13ge7DX30LdWQyw4zrVzyZc9uykL77Q/TXc= +github.com/Zondax/multi-party-sig v0.6.0-alpha-2021-09-21.0.20220119135030-8f412195b286 h1:ZxenR9Lvj/0m86G4oo/3mFKLBXdM+UpnpxzwWQybPq0= +github.com/Zondax/multi-party-sig v0.6.0-alpha-2021-09-21.0.20220119135030-8f412195b286/go.mod h1:KOfSxMrl13ge7DX30LdWQyw4zrVzyZc9uykL77Q/TXc= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= From 1251ab34bd04381b4882e8463782b46b68d136eb Mon Sep 17 00:00:00 2001 From: rllola Date: Wed, 19 Jan 2022 15:04:37 +0100 Subject: [PATCH 16/23] using KeygenTaprootGennaro --- chain/checkpointing/sub.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/checkpointing/sub.go b/chain/checkpointing/sub.go index 758471d34..c43725950 100644 --- a/chain/checkpointing/sub.go +++ b/chain/checkpointing/sub.go @@ -415,7 +415,7 @@ func (c *CheckpointingSub) GenerateNewKeys(ctx context.Context, participants []s threshold := (len(idsStrings) / 2) + 1 n := NewNetwork(c.sub, c.topic) - f := frost.KeygenTaproot(id, ids, threshold) + f := frost.KeygenTaprootGennaro(id, ids, threshold) handler, err := protocol.NewMultiHandler(f, []byte{1, 2, 3}) if err != nil { From dfbe59dfeefd772d0f00f39939a19ffc4d83b75b Mon Sep 17 00:00:00 2001 From: rllola Date: Thu, 20 Jan 2022 16:59:49 +0100 Subject: [PATCH 17/23] remove some println and one println --- chain/checkpointing/sub.go | 1 + chain/checkpointing/util.go | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/chain/checkpointing/sub.go b/chain/checkpointing/sub.go index c43725950..3ba0741ae 100644 --- a/chain/checkpointing/sub.go +++ b/chain/checkpointing/sub.go @@ -298,6 +298,7 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { // Activate checkpointing every 25 blocks log.Infow("Height:", newTs.Height()) + fmt.Println("Height:", newTs.Height()) // NOTES: this will only work in delegated consensus // Wait for more tipset to valid the height and be sure it is valid // NOTES: should retrieve list of signing miners using Power actor state (see Miners) and not through config instanciation diff --git a/chain/checkpointing/util.go b/chain/checkpointing/util.go index 9bdd62e19..c43a1d58b 100644 --- a/chain/checkpointing/util.go +++ b/chain/checkpointing/util.go @@ -149,7 +149,6 @@ func genCheckpointPublicKeyTaproot(internal_pubkey []byte, checkpoint []byte) [] func addTaprootToWallet(url, taprootScript string) bool { payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"importaddress\", \"params\": [\"" + taprootScript + "\", \"\", true]}" result := jsonRPC(url, payload) - fmt.Println(result) if result["error"] == nil { return true } @@ -172,7 +171,6 @@ func getTaprootScript(pubkey []byte) string { func walletGetTxidFromAddress(url, taprootAddress string) (string, error) { payload := "{\"jsonrpc\": \"1.0\", \"id\":\"wow\", \"method\": \"listtransactions\", \"params\": [\"*\", 500000000, 0, true]}" result := jsonRPC(url, payload) - fmt.Println(result) list := result["result"].([]interface{}) for _, item := range list { From c582162f44182c6ae333735cc32de3ae6b89266a Mon Sep 17 00:00:00 2001 From: rllola Date: Thu, 20 Jan 2022 17:16:25 +0100 Subject: [PATCH 18/23] uncomment address --- chain/checkpointing/sub.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chain/checkpointing/sub.go b/chain/checkpointing/sub.go index 3ba0741ae..2608e7a53 100644 --- a/chain/checkpointing/sub.go +++ b/chain/checkpointing/sub.go @@ -648,8 +648,8 @@ func BuildCheckpointingSub(mctx helpers.MetricsCtx, lc fx.Lifecycle, c *Checkpoi // it signed and replace it with it. Config is not saved, neither when new DKG is done. c.pubkey = genCheckpointPublicKeyTaproot(c.config.PublicKey, cidBytes) - //address, _ := pubkeyToTapprootAddress(c.pubkey) - //fmt.Println(address) + address, _ := pubkeyToTapprootAddress(c.pubkey) + fmt.Println(address) // Save tweaked value merkleRoot := hashMerkleRoot(c.config.PublicKey, cidBytes) From 1cfd09daaace868cf5ace43333b0e3c01e862ee6 Mon Sep 17 00:00:00 2001 From: rllola Date: Fri, 21 Jan 2022 10:02:00 +0100 Subject: [PATCH 19/23] revert keygen to default one --- chain/checkpointing/sub.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/chain/checkpointing/sub.go b/chain/checkpointing/sub.go index 2608e7a53..0bbe88c16 100644 --- a/chain/checkpointing/sub.go +++ b/chain/checkpointing/sub.go @@ -416,7 +416,10 @@ func (c *CheckpointingSub) GenerateNewKeys(ctx context.Context, participants []s threshold := (len(idsStrings) / 2) + 1 n := NewNetwork(c.sub, c.topic) - f := frost.KeygenTaprootGennaro(id, ids, threshold) + + // Keygen with Gennaro porotocol if failing + //f := frost.KeygenTaprootGennaro(id, ids, threshold) + f := frost.KeygenTaproot(id, ids, threshold) handler, err := protocol.NewMultiHandler(f, []byte{1, 2, 3}) if err != nil { @@ -648,6 +651,7 @@ func BuildCheckpointingSub(mctx helpers.MetricsCtx, lc fx.Lifecycle, c *Checkpoi // it signed and replace it with it. Config is not saved, neither when new DKG is done. c.pubkey = genCheckpointPublicKeyTaproot(c.config.PublicKey, cidBytes) + // Get the taproot address used in taproot.sh address, _ := pubkeyToTapprootAddress(c.pubkey) fmt.Println(address) From 6d9d3ac258ccc127c678bd3b958cec5f476005c4 Mon Sep 17 00:00:00 2001 From: rllola Date: Fri, 21 Jan 2022 10:04:21 +0100 Subject: [PATCH 20/23] fix log --- chain/checkpointing/sub.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/checkpointing/sub.go b/chain/checkpointing/sub.go index 0bbe88c16..fba7b5c25 100644 --- a/chain/checkpointing/sub.go +++ b/chain/checkpointing/sub.go @@ -297,7 +297,7 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { } // Activate checkpointing every 25 blocks - log.Infow("Height:", newTs.Height()) + log.Infow("Height:", newTs.Height().String()) fmt.Println("Height:", newTs.Height()) // NOTES: this will only work in delegated consensus // Wait for more tipset to valid the height and be sure it is valid From 3f9555fbc67f600659277e2de3a8e65fc953d90c Mon Sep 17 00:00:00 2001 From: rllola Date: Fri, 21 Jan 2022 14:12:49 +0100 Subject: [PATCH 21/23] fix zap logs error --- chain/checkpointing/sub.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/chain/checkpointing/sub.go b/chain/checkpointing/sub.go index fba7b5c25..59d34e58e 100644 --- a/chain/checkpointing/sub.go +++ b/chain/checkpointing/sub.go @@ -262,7 +262,7 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { return false, nil, err } - log.Infow("We have a checkpoint up to height : ", ts.Height()) + log.Infow("We have a checkpoint up to height : ", "height", ts.Height()) c.synced = true c.height = ts.Height() } else { @@ -297,7 +297,7 @@ func (c *CheckpointingSub) listenCheckpointEvents(ctx context.Context) { } // Activate checkpointing every 25 blocks - log.Infow("Height:", newTs.Height().String()) + log.Infow("Height:", "height", newTs.Height().String()) fmt.Println("Height:", newTs.Height()) // NOTES: this will only work in delegated consensus // Wait for more tipset to valid the height and be sure it is valid @@ -408,7 +408,7 @@ func (c *CheckpointingSub) GenerateNewKeys(ctx context.Context, participants []s idsStrings := participants sort.Strings(idsStrings) - log.Infow("participants list :", idsStrings) + log.Infow("participants list :", "participants", idsStrings) ids := c.formIDSlice(idsStrings) @@ -431,7 +431,7 @@ func (c *CheckpointingSub) GenerateNewKeys(ctx context.Context, participants []s // if a participant is mibehaving the DKG entirely fail (no fallback) return err } - log.Infow("result :", r) + log.Infow("result :", "result", r) var ok bool c.newconfig, ok = r.(*keygen.TaprootConfig) @@ -462,8 +462,8 @@ func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, cp, data []byte } idsStrings := c.orderParticipantsList() - log.Infow("participants list :", idsStrings) - log.Infow("precedent tx", c.ptxid) + log.Infow("participants list :", "participants", idsStrings) + log.Infow("precedent tx", "txid", c.ptxid) ids := c.formIDSlice(idsStrings) if c.ptxid == "" { @@ -482,7 +482,7 @@ func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, cp, data []byte return err } c.ptxid = ptxid - log.Infow("found precedent txid:", c.ptxid) + log.Infow("found precedent txid:", "txid", c.ptxid) } index := 0 @@ -534,7 +534,7 @@ func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, cp, data []byte if err != nil { return err } - log.Infow("result :", r) + log.Infow("result :", "result", r) // if signing is a success we register the new value merkleRoot := hashMerkleRoot(pubkey, cp) @@ -560,7 +560,7 @@ func (c *CheckpointingSub) CreateCheckpoint(ctx context.Context, cp, data []byte /* Need to keep this to build next one */ newtxid := result["result"].(string) - log.Infow("new Txid:", newtxid) + log.Infow("new Txid:", "newtxid", newtxid) c.ptxid = newtxid return nil From a0a39cecc12cb8218db4896934dfc89d3baca387 Mon Sep 17 00:00:00 2001 From: rllola Date: Tue, 25 Jan 2022 13:43:05 +0100 Subject: [PATCH 22/23] added unit tests --- chain/checkpointing/util_test.go | 60 ++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 chain/checkpointing/util_test.go diff --git a/chain/checkpointing/util_test.go b/chain/checkpointing/util_test.go new file mode 100644 index 000000000..5fe385b23 --- /dev/null +++ b/chain/checkpointing/util_test.go @@ -0,0 +1,60 @@ +package checkpointing + +import ( + "encoding/hex" + "fmt" + "testing" +) + +func TestTaprootSignatureHash(t *testing.T) { + tx, _ := hex.DecodeString("0200000001cbfbdd3778e1d2e2b22fc728f3b902ff6e4df7a40582367e20aec056e05fbd9d0000000000ffffffff0280da2d0900000000225120b9435744b668ab44e3074432bf1b167d4e655db03be13aa6db295055a220b26a0000000000000000056a0363696400000000") + utxo, _ := hex.DecodeString("50ed400900000000225120b9435744b668ab44e3074432bf1b167d4e655db03be13aa6db295055a220b26a") + + sig_hash, _ := TaprootSignatureHash(tx, utxo, 0x00) + + if hex.EncodeToString(sig_hash) != "6b0fe64d6f1af182fb8b0d9e1f8587fafb08162b60495dfb2a1799516bb80874" { + fmt.Println(hex.EncodeToString(sig_hash)) + t.Errorf("Invalid hash") + } +} + +func TestTaggedHash(t *testing.T) { + tag := taggedHash("TapSighash") + + if hex.EncodeToString(tag) != "dabc11914abcd8072900042a2681e52f8dba99ce82e224f97b5fdb7cd4b9c803" { + fmt.Println(hex.EncodeToString(tag)) + t.Errorf("Invalid Tag") + } +} + +func TestTaggedHashExtraData(t *testing.T) { + tag := taggedHash("TapSighash", []byte{0}) + + if hex.EncodeToString(tag) != "c2fd0de003889a09c4afcf676656a0d8a1fb706313ff7d509afb00c323c010cd" { + fmt.Println(hex.EncodeToString(tag)) + t.Errorf("Invalid Tag") + } +} + +//some testvectors from https://github.com/bitcoin/bips/blob/995f45211d1baac4ac34685cf09d804eb8edd078/bip-0341/wallet-test-vectors.json +func TestTweakPubkey(t *testing.T) { + internal_pubkey, _ := hex.DecodeString("d6889cb081036e0faefa3a35157ad71086b123b2b144b649798b494c300a961d") + tweak, _ := hex.DecodeString("b86e7be8f39bab32a6f2c0443abbc210f0edac0e2c53d501b36b64437d9c6c70") + + tweaked_pubkey := applyTweakToPublicKeyTaproot(internal_pubkey, tweak) + + if hex.EncodeToString(tweaked_pubkey) != "53a1f6e454df1aa2776a2814a721372d6258050de330b3c6d10ee8f4e0dda343" { + t.Errorf("Invalid tweaked pubkey") + } +} + +func TestMerkleHash(t *testing.T) { + pubkey, _ := hex.DecodeString("187791b6f712a8ea41c8ecdd0ee77fab3e85263b37e1ec18a3651926b3a6cf27") + merkle_root, _ := hex.DecodeString("5b75adecf53548f3ec6ad7d78383bf84cc57b55a3127c72b9a2481752dd88b21") + + test_tweak := hashTweakedValue(pubkey, merkle_root) + + if hex.EncodeToString(test_tweak) != "cbd8679ba636c1110ea247542cfbd964131a6be84f873f7f3b62a777528ed001" { + t.Errorf("Invalid tweaked pubkey") + } +} From b5a2060a57a8e7d8b9675edc511a3a038953e5b2 Mon Sep 17 00:00:00 2001 From: rllola Date: Tue, 25 Jan 2022 20:25:09 +0100 Subject: [PATCH 23/23] fix script.py --- data/script.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/script.py b/data/script.py index d21e07bad..af94dacd6 100644 --- a/data/script.py +++ b/data/script.py @@ -7,7 +7,7 @@ participants = [] count = 0 -command = 'eudico send --from t1d2xrzcslx7xlbbylc5c3d5lvandqw4iwl6epxba --method 2 --params-json "{\"Miners\":[' +command = 'eudico send --from t1d2xrzcslx7xlbbylc5c3d5lvandqw4iwl6epxba --method 2 --params-json "{\\"Miners\\":[' for line in lines: count += 1 participant = line.split('/')[-1].rstrip()