From 7be74ca7170ba78440f737e352cb6bf0ba83e7cf Mon Sep 17 00:00:00 2001 From: Chris Gorman Date: Fri, 3 Sep 2021 12:26:11 -0400 Subject: [PATCH] Merging updates from dynamics into main. The dynamics package is included to allow for controlled changes to be made to various parameters throughout the MadNet system. These changes may be desired at some point in the future. Some of the changes include allowing for fees in application objects, including transaction fees. There were also some changes to crypto/ to ensure the objects behave as expected and do not panic under certain circumstances. --- application/application.go | 14 +- application/deposit/deposit.go | 1 + application/deposit/deposit_test.go | 7 +- application/indexer/expsize.go | 26 +- application/indexer/indexer_test.go | 14 +- application/indexer/valueold.go | 169 -- application/indexer/valueold_test.go | 179 --- application/minedtx/mined_test.go | 38 +- application/minedtx/mockstorage_test.go | 145 ++ application/objs/as.go | 44 +- application/objs/as_test.go | 8 + application/objs/asowner_test.go | 1 + application/objs/aspi.go | 30 +- application/objs/aspi_test.go | 5 + application/objs/capn/application.capnp | 72 +- application/objs/capn/application.capnp.go | 909 +++++++++-- application/objs/capn/gen.go | 2 +- application/objs/constants.go | 2 + application/objs/ds.go | 89 ++ application/objs/ds_test.go | 245 ++- application/objs/dsl.go | 16 + application/objs/dsl_test.go | 16 + application/objs/dsowner_test.go | 5 +- application/objs/dspi.go | 101 +- application/objs/dspi_test.go | 12 +- application/objs/mockstorage_test.go | 145 ++ application/objs/tf.go | 176 +++ application/objs/tf_test.go | 397 +++++ application/objs/tfpi.go | 128 ++ application/objs/tfpi_test.go | 144 ++ application/objs/tfpreimage/tfpreimage.go | 52 + application/objs/tx.go | 90 +- application/objs/tx/tx.go | 7 + application/objs/tx_test.go | 1417 ++++++++++++++++- application/objs/txfee/txfee.go | 55 + application/objs/txin.go | 2 +- application/objs/txin_test.go | 22 +- application/objs/txinl.go | 2 +- application/objs/txinl_test.go | 47 +- application/objs/txvec.go | 13 +- application/objs/uint256/uint256.go | 22 + application/objs/uint256/uint256_test.go | 52 + application/objs/utxo.go | 188 ++- application/objs/utxo_test.go | 442 +++++- application/objs/vin.go | 22 + application/objs/vout.go | 90 +- application/objs/vs.go | 64 +- application/objs/vs_test.go | 171 +- application/objs/vsowner_test.go | 10 +- application/objs/vspi.go | 27 + application/objs/vspi_test.go | 3 + application/pendingtx/pending_test.go | 5 +- application/pendingtx/pendingtxhandler.go | 32 +- application/txhandler.go | 15 +- application/utxohandler/utxohandler.go | 39 +- application/utxohandler/utxohandler_test.go | 3 +- application/utxohandler/utxotrie/utxotrie.go | 11 +- application/wrapper/storage.go | 69 + cmd/testutils/inject/main.go | 51 +- cmd/testutils/many_utxos/main.go | 5 +- cmd/validator/validator.go | 27 +- consensus/admin/handlers.go | 32 +- consensus/db/db.go | 12 +- consensus/db/db_test.go | 100 +- consensus/db/rawdb.go | 4 +- consensus/dman/actors_test.go | 5 +- consensus/dman/dman.go | 3 +- consensus/dman/txcache_test.go | 2 + consensus/gossip/client.go | 5 +- consensus/gossip/handlers.go | 7 +- consensus/gossip/state_test.go | 20 +- consensus/lstate/appman.go | 7 +- consensus/lstate/engine.go | 44 +- consensus/lstate/fastsync.go | 664 ++++---- consensus/lstate/handlers.go | 14 +- consensus/lstate/rstate.go | 7 +- consensus/lstate/statecastlocal.go | 3 +- consensus/lstate/statechnglocal.go | 21 +- consensus/objs/bclaims_test.go | 122 ++ consensus/objs/bclms.go | 4 - consensus/objs/bhIndKey.go | 10 +- consensus/objs/bhdr.go | 44 +- consensus/objs/bhdr_test.go | 17 +- consensus/objs/capn/gen.go | 2 +- consensus/objs/cbkey.go | 10 +- consensus/objs/estore.go | 15 +- consensus/objs/nh.go | 9 +- consensus/objs/nh_test.go | 5 +- consensus/objs/nhl.go | 10 +- consensus/objs/nr_test.go | 5 +- consensus/objs/nrc.go | 3 +- consensus/objs/nrl.go | 6 +- consensus/objs/ostate/ostate.go | 4 +- consensus/objs/ovs.go | 19 +- consensus/objs/pc.go | 13 +- consensus/objs/pc_test.go | 5 +- consensus/objs/pcl.go | 4 +- consensus/objs/pclms.go | 3 +- consensus/objs/pclms_test.go | 5 +- consensus/objs/pcn.go | 4 +- consensus/objs/pcn_test.go | 5 +- consensus/objs/phlkey.go | 10 +- consensus/objs/plkey.go | 10 +- consensus/objs/pnkey.go | 10 +- consensus/objs/prop.go | 9 +- consensus/objs/prop_test.go | 7 +- consensus/objs/pv.go | 4 +- consensus/objs/pv_test.go | 5 +- consensus/objs/pvl.go | 4 +- consensus/objs/pvn.go | 4 +- consensus/objs/pvn_test.go | 5 +- consensus/objs/rc.go | 11 +- consensus/objs/rc_test.go | 163 +- consensus/objs/rclms.go | 7 +- consensus/objs/rclms_test.go | 44 + consensus/objs/rs.go | 13 +- consensus/objs/rs_test.go | 5 +- consensus/objs/rskeycurr.go | 5 +- consensus/objs/rskeyhist.go | 17 +- consensus/objs/safetoproceedkey.go | 9 +- consensus/objs/sbhkey.go | 8 +- consensus/objs/state_test.go | 20 +- consensus/objs/txcachekey.go | 19 +- consensus/objs/txcachekey_test.go | 4 +- consensus/objs/util.go | 45 + consensus/objs/util_test.go | 336 ++++ consensus/objs/v.go | 6 +- consensus/objs/vs.go | 9 +- consensus/objs/vskey.go | 10 +- consensus/request/client.go | 5 +- consensus/request/handlers.go | 7 +- consensus/synchronizer.go | 14 +- constants/consensus.go | 7 - constants/dbprefix/consensus.go | 8 + crypto/bn.go | 14 +- crypto/bn_test.go | 15 +- crypto/bngroup.go | 27 +- crypto/bngroup_test.go | 40 +- crypto/errors.go | 4 + crypto/secp.go | 11 +- dynamics/consensus.go | 18 + dynamics/db.go | 108 ++ dynamics/db_test.go | 166 ++ dynamics/errors.go | 41 + dynamics/linkedlist.go | 81 + dynamics/linkedlist_test.go | 120 ++ dynamics/node.go | 157 ++ dynamics/node_test.go | 584 +++++++ dynamics/nodekey.go | 37 + dynamics/nodekey_test.go | 55 + dynamics/rawdb.go | 12 + dynamics/rawstorage.go | 416 +++++ dynamics/rawstorage_test.go | 1216 +++++++++++++++ dynamics/storage.go | 769 +++++++++ dynamics/storage_test.go | 1473 ++++++++++++++++++ dynamics/update.go | 192 +++ dynamics/update_test.go | 378 +++++ go.mod | 1 - go.sum | 3 +- localrpc/translateAobjsFwd.go | 22 + localrpc/translateAobjsRev.go | 15 + proto/aobjs.pb.go | 372 ++++- proto/aobjs.proto | 23 +- 163 files changed, 13167 insertions(+), 1512 deletions(-) delete mode 100644 application/indexer/valueold.go delete mode 100644 application/indexer/valueold_test.go create mode 100644 application/minedtx/mockstorage_test.go create mode 100644 application/objs/mockstorage_test.go create mode 100644 application/objs/tf.go create mode 100644 application/objs/tf_test.go create mode 100644 application/objs/tfpi.go create mode 100644 application/objs/tfpi_test.go create mode 100644 application/objs/tfpreimage/tfpreimage.go create mode 100644 application/objs/txfee/txfee.go create mode 100644 application/wrapper/storage.go create mode 100644 consensus/objs/util_test.go create mode 100644 dynamics/consensus.go create mode 100644 dynamics/db.go create mode 100644 dynamics/db_test.go create mode 100644 dynamics/errors.go create mode 100644 dynamics/linkedlist.go create mode 100644 dynamics/linkedlist_test.go create mode 100644 dynamics/node.go create mode 100644 dynamics/node_test.go create mode 100644 dynamics/nodekey.go create mode 100644 dynamics/nodekey_test.go create mode 100644 dynamics/rawdb.go create mode 100644 dynamics/rawstorage.go create mode 100644 dynamics/rawstorage_test.go create mode 100644 dynamics/storage.go create mode 100644 dynamics/storage_test.go create mode 100644 dynamics/update.go create mode 100644 dynamics/update_test.go diff --git a/application/application.go b/application/application.go index 574e6391..a8200790 100644 --- a/application/application.go +++ b/application/application.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" + "github.com/MadBase/MadNet/dynamics" "github.com/MadBase/MadNet/errorz" "github.com/MadBase/MadNet/utils" "github.com/sirupsen/logrus" @@ -14,6 +15,7 @@ import ( "github.com/MadBase/MadNet/application/objs/uint256" "github.com/MadBase/MadNet/application/pendingtx" "github.com/MadBase/MadNet/application/utxohandler" + "github.com/MadBase/MadNet/application/wrapper" trie "github.com/MadBase/MadNet/badgerTrie" "github.com/MadBase/MadNet/consensus/appmock" consensusdb "github.com/MadBase/MadNet/consensus/db" @@ -36,8 +38,9 @@ type Application struct { } // Init initializes Application ... -func (a *Application) Init(conDB *consensusdb.Database, memDB *badger.DB, dph *deposit.Handler) error { +func (a *Application) Init(conDB *consensusdb.Database, memDB *badger.DB, dph *deposit.Handler, storageInterface dynamics.StorageGetter) error { a.logger = logging.GetLogger(constants.LoggerApp) + storage := wrapper.NewStorage(storageInterface) uHdlr := utxohandler.NewUTXOHandler(conDB.DB()) pHdlr := pendingtx.NewPendingTxHandler(memDB) pHdlr.UTXOHandler = uHdlr @@ -50,6 +53,7 @@ func (a *Application) Init(conDB *consensusdb.Database, memDB *badger.DB, dph *d dHdlr: dph, uHdlr: uHdlr, cdb: conDB, + storage: storage, } a.txHandler.dHdlr.IsSpent = a.txHandler.uHdlr.TrieContains // initialize the application with a random key. @@ -151,7 +155,7 @@ func (a *Application) IsValid(txn *badger.Txn, chainID uint32, height uint32, st utils.DebugTrace(a.logger, err) return false, err } - if err := txs.Validate(height, vout); err != nil { + if err := txs.Validate(height, vout, a.txHandler.storage); err != nil { utils.DebugTrace(a.logger, err) return false, err } @@ -221,7 +225,11 @@ func (a *Application) SetMiningKey(privKey []byte, curveSpec constants.CurveSpec switch curveSpec { case constants.CurveBN256Eth: signer := &crypto.BNSigner{} - signer.SetPrivk(privKey) + err := signer.SetPrivk(privKey) + if err != nil { + utils.DebugTrace(a.logger, err) + return err + } pubk, err := signer.Pubkey() if err != nil { utils.DebugTrace(a.logger, err) diff --git a/application/deposit/deposit.go b/application/deposit/deposit.go index 1b15d77c..ed64a230 100644 --- a/application/deposit/deposit.go +++ b/application/deposit/deposit.go @@ -86,6 +86,7 @@ func (dp *Handler) Add(txn *badger.Txn, chainID uint32, utxoID []byte, biValue * Value: value, ChainID: chainID, Owner: vso, + Fee: new(uint256.Uint256).SetZero(), }, TxHash: n2, } diff --git a/application/deposit/deposit_test.go b/application/deposit/deposit_test.go index 4ab9dec6..c17fc5cb 100644 --- a/application/deposit/deposit_test.go +++ b/application/deposit/deposit_test.go @@ -29,12 +29,15 @@ func newDepositHandler() *Handler { func testingOwner() *objs.Owner { signer := &crypto.BNSigner{} - signer.SetPrivk([]byte("secret")) + err := signer.SetPrivk([]byte("secret")) + if err != nil { + panic(err) + } pubk, _ := signer.Pubkey() acct := crypto.GetAccount(pubk) owner := &objs.Owner{} curveSpec := constants.CurveSecp256k1 - err := owner.New(acct, curveSpec) + err = owner.New(acct, curveSpec) if err != nil { panic(err) } diff --git a/application/indexer/expsize.go b/application/indexer/expsize.go index 83b58b63..9c8412a5 100644 --- a/application/indexer/expsize.go +++ b/application/indexer/expsize.go @@ -94,34 +94,38 @@ func (esi *ExpSizeIndex) Drop(txn *badger.Txn, utxoID []byte) error { return utils.DeleteValue(txn, key) } -func (esi *ExpSizeIndex) GetExpiredObjects(txn *badger.Txn, epoch uint32, maxBytes uint32) ([][]byte, uint32) { +func (esi *ExpSizeIndex) GetExpiredObjects(txn *badger.Txn, epoch uint32, maxBytes uint32, maxObjects int) ([][]byte, uint32) { result := [][]byte{} byteCount := uint32(0) + objCount := 0 opts := badger.DefaultIteratorOptions prefix := esi.prefix() opts.Prefix = prefix iter := txn.NewIterator(opts) defer iter.Close() for iter.Seek(prefix); iter.ValidForPrefix(prefix); iter.Next() { + if objCount+1 > maxObjects { + break + } + if byteCount+constants.HashLen > maxBytes { + break + } itm := iter.Item() key := itm.KeyCopy(nil) key = key[len(prefix):] epochBytes := key[:4] // slice is 4 bytes so no error will be raised epochObj, _ := utils.UnmarshalUint32(epochBytes) - sizeInvBytes := key[4:8] - // slice is 4 bytes so no error will be raised - sizeObjInv, _ := utils.UnmarshalUint32(sizeInvBytes) - sizeObj := constants.MaxUint32 - sizeObjInv utxoID := key[8:] - if epochObj <= epoch { - if byteCount+sizeObj <= maxBytes { - byteCount += sizeObj - result = append(result, utxoID) - } + if epochObj > epoch { + break } + byteCount += constants.HashLen + result = append(result, utxoID) + objCount++ } - return result, byteCount + remainingBytes := maxBytes - byteCount + return result, remainingBytes } func (esi *ExpSizeIndex) makeKey(epoch uint32, size uint32, utxoID []byte) *ExpSizeIndexKey { diff --git a/application/indexer/indexer_test.go b/application/indexer/indexer_test.go index 266a5e05..6c6bf04c 100644 --- a/application/indexer/indexer_test.go +++ b/application/indexer/indexer_test.go @@ -623,7 +623,8 @@ func TestExpSizeIndex(t *testing.T) { if err != nil { t.Fatal(err) } - expObjs, expSize := index.GetExpiredObjects(txn, epoch1, 99) + maxBytes := uint32(99) + expObjs, remainingBytes := index.GetExpiredObjects(txn, epoch1, maxBytes, constants.MaxTxVectorLength) if len(expObjs) != 2 { t.Fatal("expObjs len wrong", len(expObjs)) } @@ -633,22 +634,23 @@ func TestExpSizeIndex(t *testing.T) { if !bytes.Equal(expObjs[1], txHash1) { t.Fatal("exp1 wrong") } - if expSize != size1+size2 { - t.Fatal("exp size wrong") + if maxBytes-remainingBytes != 2*constants.HashLen { + t.Fatal("wrong size for remainingBytes") } err = index.Drop(txn, txHash1) if err != nil { t.Fatal(err) } - expObjs, expSize = index.GetExpiredObjects(txn, epoch1, 99) + maxBytes = 99 + expObjs, remainingBytes = index.GetExpiredObjects(txn, epoch1, maxBytes, constants.MaxTxVectorLength) if len(expObjs) != 1 { t.Fatal("expObjs len wrong", len(expObjs)) } if !bytes.Equal(expObjs[0], txHash2) { t.Fatal("exp0 wrong") } - if expSize != size2 { - t.Fatal("exp size wrong") + if maxBytes-remainingBytes != constants.HashLen { + t.Fatal("wrong size for remainingBytes") } return nil }) diff --git a/application/indexer/valueold.go b/application/indexer/valueold.go deleted file mode 100644 index 7824f437..00000000 --- a/application/indexer/valueold.go +++ /dev/null @@ -1,169 +0,0 @@ -package indexer - -import ( - "github.com/MadBase/MadNet/application/objs" - "github.com/MadBase/MadNet/constants" - "github.com/MadBase/MadNet/utils" - "github.com/dgraph-io/badger/v2" -) - -/* -|| - -| - | - -*/ - -// TODO HANDLE UINT32 OVERFLOW - -func newValueIndexOld(p, pp prefixFunc) *valueIndexOld { - return &valueIndexOld{p, pp} -} - -// valueIndexOld creates an index that allows objects to be dropped -// by epoch -type valueIndexOld struct { - prefix prefixFunc - refPrefix prefixFunc -} - -type valueIndexOldKey struct { - key []byte -} - -func (vik *valueIndexOldKey) MarshalBinary() []byte { - return utils.CopySlice(vik.key) -} - -func (vik *valueIndexOldKey) UnmarshalBinary(data []byte) { - vik.key = utils.CopySlice(data) -} - -type valueIndexOldRefKey struct { - refkey []byte -} - -// MarshalBinary returns the byte slice for the key object -func (virk *valueIndexOldRefKey) MarshalBinary() []byte { - return utils.CopySlice(virk.refkey) -} - -// UnmarshalBinary takes in a byte slice to set the key object -func (virk *valueIndexOldRefKey) UnmarshalBinary(data []byte) { - virk.refkey = utils.CopySlice(data) -} - -// Add adds an item to the list -func (vi *valueIndexOld) Add(txn *badger.Txn, utxoID []byte, owner *objs.Owner, value uint32) error { - viKey, err := vi.makeKey(owner, value, utxoID) - if err != nil { - return err - } - key := viKey.MarshalBinary() - viRefKey := vi.makeRefKey(utxoID) - refKey := viRefKey.MarshalBinary() - valueIndexOld, err := vi.makevalueIndexOld(owner, value, utxoID) - if err != nil { - return err - } - err = utils.SetValue(txn, refKey, valueIndexOld) - if err != nil { - return err - } - return utils.SetValue(txn, key, utils.CopySlice(utxoID)) -} - -// Drop returns a list of all txHashes that should be dropped -func (vi *valueIndexOld) Drop(txn *badger.Txn, utxoID []byte) error { - utxoIDCopy := utils.CopySlice(utxoID) - viRefKey := vi.makeRefKey(utxoIDCopy) - refKey := viRefKey.MarshalBinary() - valueIndexOld, err := utils.GetValue(txn, refKey) - if err != nil { - return err - } - key := []byte{} - key = append(key, vi.prefix()...) - key = append(key, valueIndexOld...) - err = utils.DeleteValue(txn, refKey) - if err != nil { - return err - } - return utils.DeleteValue(txn, key) -} - -func (vi *valueIndexOld) GetValueForOwner(txn *badger.Txn, owner *objs.Owner, minValue uint32, exclude [][]byte) ([][]byte, uint32, error) { - exclusionSet := make(map[[constants.HashLen]byte]bool) - var hsh [constants.HashLen]byte - for _, ID := range exclude { - copy(hsh[:], utils.CopySlice(ID)) - exclusionSet[hsh] = true - } - result := [][]byte{} - valueCount := uint32(0) - opts := badger.DefaultIteratorOptions - prefix := vi.prefix() - ownerBytes, err := owner.MarshalBinary() - if err != nil { - return nil, 0, err - } - prefix = append(prefix, ownerBytes...) - opts.Prefix = prefix - iter := txn.NewIterator(opts) - defer iter.Close() - for iter.Seek(prefix); iter.ValidForPrefix(prefix); iter.Next() { - itm := iter.Item() - key := itm.KeyCopy(nil) - valueBytes := key[len(prefix) : len(prefix)+4] - value, _ := utils.UnmarshalUint32(valueBytes) - utxoID, err := itm.ValueCopy(nil) - if err != nil { - return nil, 0, err - } - copy(hsh[:], utxoID) - if !exclusionSet[hsh] { - valueCount += value - result = append(result, utxoID) - } - if valueCount >= minValue { - break - } - } - return result, valueCount, nil -} - -func (vi *valueIndexOld) makeKey(owner *objs.Owner, value uint32, utxoID []byte) (*valueIndexOldKey, error) { - valueIndexOld, err := vi.makevalueIndexOld(owner, value, utxoID) - if err != nil { - return nil, err - } - key := []byte{} - key = append(key, vi.prefix()...) - key = append(key, valueIndexOld...) - viKey := &valueIndexOldKey{} - viKey.UnmarshalBinary(key) - return viKey, nil -} - -func (vi *valueIndexOld) makeRefKey(utxoID []byte) *valueIndexOldRefKey { - refKey := []byte{} - refKey = append(refKey, vi.refPrefix()...) - refKey = append(refKey, utils.CopySlice(utxoID)...) - viRefKey := &valueIndexOldRefKey{} - viRefKey.UnmarshalBinary(refKey) - return viRefKey -} - -func (vi *valueIndexOld) makevalueIndexOld(owner *objs.Owner, value uint32, utxoID []byte) ([]byte, error) { - valueBytes := utils.MarshalUint32(value) - ownerBytes, err := owner.MarshalBinary() - if err != nil { - return nil, err - } - valueIndexOld := []byte{} - valueIndexOld = append(valueIndexOld, ownerBytes...) - valueIndexOld = append(valueIndexOld, valueBytes...) - valueIndexOld = append(valueIndexOld, utils.CopySlice(utxoID)...) - return valueIndexOld, nil -} diff --git a/application/indexer/valueold_test.go b/application/indexer/valueold_test.go deleted file mode 100644 index d8f0987d..00000000 --- a/application/indexer/valueold_test.go +++ /dev/null @@ -1,179 +0,0 @@ -package indexer - -import ( - "bytes" - "io/ioutil" - "os" - "testing" - - "github.com/MadBase/MadNet/application/objs" - "github.com/MadBase/MadNet/crypto" - "github.com/MadBase/MadNet/utils" - "github.com/dgraph-io/badger/v2" -) - -func makeValueIndexOld() *valueIndexOld { - prefix1 := func() []byte { - return []byte("ya") - } - prefix2 := func() []byte { - return []byte("yb") - } - index := newValueIndexOld(prefix1, prefix2) - return index -} - -func TestValueOldIndexAdd(t *testing.T) { - dir, err := ioutil.TempDir("", "badger-test") - if err != nil { - t.Fatal(err) - } - defer func() { - if err := os.RemoveAll(dir); err != nil { - t.Fatal(err) - } - }() - opts := badger.DefaultOptions(dir) - db, err := badger.Open(opts) - if err != nil { - t.Fatal(err) - } - defer db.Close() - - index := makeValueIndexOld() - owner := &objs.Owner{} - utxoID := crypto.Hasher([]byte("utxoID")) - value := uint32(25519) - - db.Update(func(txn *badger.Txn) error { - err := index.Add(txn, utxoID, owner, value) - if err == nil { - // Invalid Owner - t.Fatal("Should have raised error (1)") - } - return nil - }) - owner = makeOwner() - db.Update(func(txn *badger.Txn) error { - err = index.Add(txn, utxoID, owner, value) - if err != nil { - t.Fatal(err) - } - return nil - }) -} - -func TestValueOldIndexDrop(t *testing.T) { - dir, err := ioutil.TempDir("", "badger-test") - if err != nil { - t.Fatal(err) - } - defer func() { - if err := os.RemoveAll(dir); err != nil { - t.Fatal(err) - } - }() - opts := badger.DefaultOptions(dir) - db, err := badger.Open(opts) - if err != nil { - t.Fatal(err) - } - defer db.Close() - - index := makeValueIndexOld() - owner := makeOwner() - utxoID := crypto.Hasher([]byte("utxoID")) - value := uint32(25519) - - db.Update(func(txn *badger.Txn) error { - err := index.Drop(txn, utxoID) - if err == nil { - // Not present - t.Fatal("Should have raised error") - } - err = index.Add(txn, utxoID, owner, value) - if err != nil { - t.Fatal(err) - } - err = index.Drop(txn, utxoID) - if err != nil { - t.Fatal(err) - } - return nil - }) -} - -func TestValueOldIndexMakeKey(t *testing.T) { - dir, err := ioutil.TempDir("", "badger-test") - if err != nil { - t.Fatal(err) - } - defer func() { - if err := os.RemoveAll(dir); err != nil { - t.Fatal(err) - } - }() - opts := badger.DefaultOptions(dir) - db, err := badger.Open(opts) - if err != nil { - t.Fatal(err) - } - defer db.Close() - - index := makeValueIndexOld() - owner := &objs.Owner{} - utxoID := crypto.Hasher([]byte("utxoID")) - value := uint32(25519) - _, err = index.makeKey(owner, value, utxoID) - if err == nil { - t.Fatal("Should have raised error (1)") - } - - owner = makeOwner() - ownerBytes, err := owner.MarshalBinary() - if err != nil { - t.Fatal(err) - } - trueKey := []byte{} - trueKey = append(trueKey, index.prefix()...) - trueKey = append(trueKey, ownerBytes...) - trueKey = append(trueKey, utils.MarshalUint32(value)...) - trueKey = append(trueKey, utxoID...) - viKey, err := index.makeKey(owner, value, utxoID) - if err != nil { - t.Fatal(err) - } - key := viKey.MarshalBinary() - if !bytes.Equal(key, trueKey) { - t.Fatal("keys do not agree") - } -} - -func TestValueOldIndexMakeRefKey(t *testing.T) { - dir, err := ioutil.TempDir("", "badger-test") - if err != nil { - t.Fatal(err) - } - defer func() { - if err := os.RemoveAll(dir); err != nil { - t.Fatal(err) - } - }() - opts := badger.DefaultOptions(dir) - db, err := badger.Open(opts) - if err != nil { - t.Fatal(err) - } - defer db.Close() - - index := makeValueIndex() - utxoID := crypto.Hasher([]byte("utxoID")) - trueKey := []byte{} - trueKey = append(trueKey, index.refPrefix()...) - trueKey = append(trueKey, utxoID...) - viKey := index.makeRefKey(utxoID) - key := viKey.MarshalBinary() - if !bytes.Equal(key, trueKey) { - t.Fatal("keys do not agree") - } -} diff --git a/application/minedtx/mined_test.go b/application/minedtx/mined_test.go index 58434710..4d2c093d 100644 --- a/application/minedtx/mined_test.go +++ b/application/minedtx/mined_test.go @@ -46,6 +46,7 @@ func makeVS(ownerSigner objs.Signer) *objs.TXOut { ChainID: cid, Value: val, Owner: owner, + Fee: uint256.Zero(), } vs := &objs.ValueStore{ VSPreImage: vsp, @@ -173,7 +174,13 @@ func TestMined(t *testing.T) { hndlr := NewMinedTxHandler() signer := &crypto.BNSigner{} - signer.SetPrivk([]byte("secret")) + err = signer.SetPrivk([]byte("secret")) + if err != nil { + t.Fatal(err) + } + + msg := makeMockStorageGetter() + storage := makeStorage(msg) //////////////////////////////////////// ownerSigner := testingOwner() @@ -181,11 +188,11 @@ func TestMined(t *testing.T) { tx2 := makeTxConsuming(ownerSigner, consumedUTXOs) - _, err = tx.Validate(nil, 1, consumedUTXOs) + _, err = tx.Validate(nil, 1, consumedUTXOs, storage) if err != nil { t.Fatal(err) } - _, err = tx2.Validate(nil, 1, tx.Vout) + _, err = tx2.Validate(nil, 1, tx.Vout, storage) if err != nil { t.Fatal(err) } @@ -284,7 +291,10 @@ func TestMinedDelete(t *testing.T) { ownerSigner := testingOwner() consumedUTXOs, tx := makeTxInitial(ownerSigner) - _, err = tx.Validate(nil, 1, consumedUTXOs) + msg := makeMockStorageGetter() + storage := makeStorage(msg) + + _, err = tx.Validate(nil, 1, consumedUTXOs, storage) if err != nil { t.Fatal(err) } @@ -344,7 +354,10 @@ func TestMinedGet(t *testing.T) { ownerSigner := testingOwner() consumedUTXOs, tx := makeTxInitial(ownerSigner) - _, err = tx.Validate(nil, 1, consumedUTXOs) + msg := makeMockStorageGetter() + storage := makeStorage(msg) + + _, err = tx.Validate(nil, 1, consumedUTXOs, storage) if err != nil { t.Fatal(err) } @@ -424,7 +437,10 @@ func TestMinedGetHeightForTx(t *testing.T) { ownerSigner := testingOwner() consumedUTXOs, tx := makeTxInitial(ownerSigner) - _, err = tx.Validate(nil, 1, consumedUTXOs) + msg := makeMockStorageGetter() + storage := makeStorage(msg) + + _, err = tx.Validate(nil, 1, consumedUTXOs, storage) if err != nil { t.Fatal(err) } @@ -488,7 +504,10 @@ func TestMinedGetOneInternal(t *testing.T) { ownerSigner := testingOwner() consumedUTXOs, tx := makeTxInitial(ownerSigner) - _, err = tx.Validate(nil, 1, consumedUTXOs) + msg := makeMockStorageGetter() + storage := makeStorage(msg) + + _, err = tx.Validate(nil, 1, consumedUTXOs, storage) if err != nil { t.Fatal(err) } @@ -560,7 +579,10 @@ func TestMinedAddOneInternal(t *testing.T) { ownerSigner := testingOwner() consumedUTXOs, tx := makeTxInitial(ownerSigner) - _, err = tx.Validate(nil, 1, consumedUTXOs) + msg := makeMockStorageGetter() + storage := makeStorage(msg) + + _, err = tx.Validate(nil, 1, consumedUTXOs, storage) if err != nil { t.Fatal(err) } diff --git a/application/minedtx/mockstorage_test.go b/application/minedtx/mockstorage_test.go new file mode 100644 index 00000000..35a02335 --- /dev/null +++ b/application/minedtx/mockstorage_test.go @@ -0,0 +1,145 @@ +package minedtx + +import ( + "math/big" + "time" + + "github.com/MadBase/MadNet/application/wrapper" + "github.com/MadBase/MadNet/dynamics" + "github.com/dgraph-io/badger/v2" +) + +func makeMockStorageGetter() *mockStorageGetter { + maxBytes := uint32(0) + dataStoreEpochFee := new(big.Int).SetInt64(0) + atomicSwapFee := new(big.Int).SetInt64(0) + valueStoreFee := new(big.Int).SetInt64(0) + minTxFee := new(big.Int).SetInt64(0) + + msg := &mockStorageGetter{ + maxBytes: maxBytes, + dataStoreEpochFee: dataStoreEpochFee, + valueStoreFee: valueStoreFee, + atomicSwapFee: atomicSwapFee, + minTxFee: minTxFee, + } + return msg +} + +func makeStorage(msg dynamics.StorageGetter) *wrapper.Storage { + storage := wrapper.NewStorage(msg) + return storage +} + +type mockStorageGetter struct { + maxBytes uint32 + dataStoreEpochFee *big.Int + valueStoreFee *big.Int + atomicSwapFee *big.Int + minTxFee *big.Int + maxTxVectorLength int +} + +func (msg *mockStorageGetter) GetMaxBytes() uint32 { + return msg.maxBytes +} + +func (msg *mockStorageGetter) SetMaxBytes(value uint32) { + msg.maxBytes = value +} + +func (msg *mockStorageGetter) GetMaxProposalSize() uint32 { + return msg.maxBytes +} + +func (msg *mockStorageGetter) GetProposalStepTimeout() time.Duration { + return time.Duration(0) +} +func (msg *mockStorageGetter) GetPreVoteStepTimeout() time.Duration { + return time.Duration(0) +} +func (msg *mockStorageGetter) GetPreCommitStepTimeout() time.Duration { + return time.Duration(0) +} +func (msg *mockStorageGetter) GetDeadBlockRoundNextRoundTimeout() time.Duration { + return time.Duration(0) +} +func (msg *mockStorageGetter) GetDownloadTimeout() time.Duration { + return time.Duration(0) +} +func (msg *mockStorageGetter) GetSrvrMsgTimeout() time.Duration { + return time.Duration(0) +} +func (msg *mockStorageGetter) GetMsgTimeout() time.Duration { + return time.Duration(0) +} +func (msg *mockStorageGetter) GetMaxTxVectorLength() int { + return 128 +} + +func (msg *mockStorageGetter) UpdateStorage(txn *badger.Txn, update dynamics.Updater) error { + return nil +} +func (msg *mockStorageGetter) LoadStorage(txn *badger.Txn, epoch uint32) error { + return nil +} + +func (msg *mockStorageGetter) GetDataStoreEpochFee() *big.Int { + return msg.dataStoreEpochFee +} + +func (msg *mockStorageGetter) SetDataStoreEpochFee(value *big.Int) { + if value == nil { + panic("invalid value") + } + msg.dataStoreEpochFee.Set(value) +} + +func (msg *mockStorageGetter) GetDataStoreValidVersion() uint32 { + return 0 +} + +func (msg *mockStorageGetter) GetValueStoreFee() *big.Int { + return msg.valueStoreFee +} + +func (msg *mockStorageGetter) SetValueStoreFee(value *big.Int) { + if value == nil { + panic("invalid value") + } + msg.valueStoreFee.Set(value) +} + +func (msg *mockStorageGetter) GetValueStoreValidVersion() uint32 { + return 0 +} + +func (msg *mockStorageGetter) GetAtomicSwapFee() *big.Int { + return msg.atomicSwapFee +} + +func (msg *mockStorageGetter) SetAtomicSwapFee(value *big.Int) { + if value == nil { + panic("invalid value") + } + msg.atomicSwapFee.Set(value) +} + +func (msg *mockStorageGetter) GetAtomicSwapValidStopEpoch() uint32 { + return 0 +} + +func (msg *mockStorageGetter) GetMinTxFee() *big.Int { + return msg.minTxFee +} + +func (msg *mockStorageGetter) SetMinTxFee(value *big.Int) { + if value == nil { + panic("invalid value") + } + msg.minTxFee.Set(value) +} + +func (msg *mockStorageGetter) GetTxValidVersion() uint32 { + return 0 +} diff --git a/application/objs/as.go b/application/objs/as.go index bc854688..ffad1a52 100644 --- a/application/objs/as.go +++ b/application/objs/as.go @@ -4,6 +4,7 @@ import ( "github.com/MadBase/MadNet/application/objs/atomicswap" mdefs "github.com/MadBase/MadNet/application/objs/capn" "github.com/MadBase/MadNet/application/objs/uint256" + "github.com/MadBase/MadNet/application/wrapper" "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/crypto" "github.com/MadBase/MadNet/errorz" @@ -142,12 +143,37 @@ func (b *AtomicSwap) SetTxHash(txHash []byte) error { // Value returns the Value of the object func (b *AtomicSwap) Value() (*uint256.Uint256, error) { - if b == nil || b.ASPreImage == nil || b.ASPreImage.Value == nil { + if b == nil || b.ASPreImage == nil || b.ASPreImage.Value == nil || b.ASPreImage.Value.IsZero() { return nil, errorz.ErrInvalid{}.New("not initialized") } return b.ASPreImage.Value.Clone(), nil } +// Fee returns the Fee of the object +func (b *AtomicSwap) Fee() (*uint256.Uint256, error) { + if b == nil || b.ASPreImage == nil || b.ASPreImage.Fee == nil { + return nil, errorz.ErrInvalid{}.New("not initialized") + } + return b.ASPreImage.Fee.Clone(), nil +} + +// ValuePlusFee returns the Value of the object with the associated fee +func (b *AtomicSwap) ValuePlusFee() (*uint256.Uint256, error) { + value, err := b.Value() + if err != nil { + return nil, err + } + fee, err := b.Fee() + if err != nil { + return nil, err + } + total, err := new(uint256.Uint256).Add(value, fee) + if err != nil { + return nil, err + } + return total, nil +} + // Owner returns the AtomicSwapOwner object of the AtomicSwap func (b *AtomicSwap) Owner() (*AtomicSwapOwner, error) { if b == nil || b.ASPreImage == nil { @@ -205,6 +231,22 @@ func (b *AtomicSwap) IsExpired(currentHeight uint32) (bool, error) { return b.ASPreImage.IsExpired(currentHeight) } +// ValidateFee validates the fee of the object at the time of creation +func (b *AtomicSwap) ValidateFee(storage *wrapper.Storage) error { + fee, err := b.Fee() + if err != nil { + return err + } + feeTrue, err := storage.GetAtomicSwapFee() + if err != nil { + return err + } + if fee.Cmp(feeTrue) != 0 { + return errorz.ErrInvalid{}.New("invalid fee") + } + return nil +} + // ValidateSignature validates the signature of the TXIn against the atomic swap func (b *AtomicSwap) ValidateSignature(currentHeight uint32, txIn *TXIn) error { if b == nil { diff --git a/application/objs/as_test.go b/application/objs/as_test.go index e2bdde56..f2db1edc 100644 --- a/application/objs/as_test.go +++ b/application/objs/as_test.go @@ -55,6 +55,7 @@ func TestAtomicSwapGood(t *testing.T) { Owner: owner, IssuedAt: iat, Exp: exp, + Fee: new(uint256.Uint256).SetZero(), } txHash := make([]byte, constants.HashLen) as := &AtomicSwap{ @@ -128,6 +129,7 @@ func TestAtomicSwapBad1(t *testing.T) { Owner: owner, IssuedAt: iat, Exp: exp, + Fee: new(uint256.Uint256).SetZero(), } txHash := make([]byte, constants.HashLen) as := &AtomicSwap{ @@ -191,6 +193,7 @@ func TestAtomicSwapBad2(t *testing.T) { Owner: owner, IssuedAt: iat, Exp: exp, + Fee: new(uint256.Uint256).SetZero(), } txHash := make([]byte, constants.HashLen+1) // Invalid TxHash as := &AtomicSwap{ @@ -751,3 +754,8 @@ func TestAtomicSwapMakeTxIn(t *testing.T) { t.Fatal(err) } } + +func TestAtomicSwapValidateFee(t *testing.T) { + return + panic("test not implemented") +} diff --git a/application/objs/asowner_test.go b/application/objs/asowner_test.go index 564ceed1..5cdc2579 100644 --- a/application/objs/asowner_test.go +++ b/application/objs/asowner_test.go @@ -54,6 +54,7 @@ func TestASOwnerSig(t *testing.T) { Owner: owner, IssuedAt: iat, Exp: exp, + Fee: new(uint256.Uint256).SetZero(), } asp2 := &ASPreImage{} aspBytes, err := asp.MarshalBinary() diff --git a/application/objs/aspi.go b/application/objs/aspi.go index 05cff942..0940709a 100644 --- a/application/objs/aspi.go +++ b/application/objs/aspi.go @@ -18,6 +18,7 @@ type ASPreImage struct { IssuedAt uint32 Exp uint32 Owner *AtomicSwapOwner + Fee *uint256.Uint256 // preHash []byte } @@ -54,6 +55,7 @@ func (b *ASPreImage) UnmarshalCapn(bc mdefs.ASPreImage) error { if err := owner.UnmarshalBinary(bc.Owner()); err != nil { return err } + b.Owner = owner b.ChainID = bc.ChainID() u32array := [8]uint32{} u32array[0] = bc.Value() @@ -70,10 +72,24 @@ func (b *ASPreImage) UnmarshalCapn(bc mdefs.ASPreImage) error { return err } b.Value = vObj + b.TXOutIdx = bc.TXOutIdx() - b.Owner = owner b.IssuedAt = bc.IssuedAt() b.Exp = bc.Exp() + fObj := &uint256.Uint256{} + u32array[0] = bc.Fee0() + u32array[1] = bc.Fee1() + u32array[2] = bc.Fee2() + u32array[3] = bc.Fee3() + u32array[4] = bc.Fee4() + u32array[5] = bc.Fee5() + u32array[6] = bc.Fee6() + u32array[7] = bc.Fee7() + err = fObj.FromUint32Array(u32array) + if err != nil { + return err + } + b.Fee = fObj return nil } @@ -120,6 +136,18 @@ func (b *ASPreImage) MarshalCapn(seg *capnp.Segment) (mdefs.ASPreImage, error) { bc.SetValue5(u32array[5]) bc.SetValue6(u32array[6]) bc.SetValue7(u32array[7]) + u32array, err = b.Fee.ToUint32Array() + if err != nil { + return bc, err + } + bc.SetFee0(u32array[0]) + bc.SetFee1(u32array[1]) + bc.SetFee2(u32array[2]) + bc.SetFee3(u32array[3]) + bc.SetFee4(u32array[4]) + bc.SetFee5(u32array[5]) + bc.SetFee6(u32array[6]) + bc.SetFee7(u32array[7]) bc.SetTXOutIdx(b.TXOutIdx) bc.SetIssuedAt(b.IssuedAt) bc.SetExp(b.Exp) diff --git a/application/objs/aspi_test.go b/application/objs/aspi_test.go index 5f0fa4e7..1de63145 100644 --- a/application/objs/aspi_test.go +++ b/application/objs/aspi_test.go @@ -52,6 +52,7 @@ func TestASPreImageGood(t *testing.T) { Owner: owner, IssuedAt: iat, Exp: exp, + Fee: new(uint256.Uint256).SetZero(), } asp2 := &ASPreImage{} aspBytes, err := asp.MarshalBinary() @@ -137,6 +138,7 @@ func TestASPreImageBad1(t *testing.T) { Owner: owner, IssuedAt: iat, Exp: exp, + Fee: new(uint256.Uint256).SetZero(), } asp2 := &ASPreImage{} aspBytes, err := asp.MarshalBinary() @@ -244,6 +246,7 @@ func TestASPreImageBad3(t *testing.T) { Owner: owner, IssuedAt: iat, Exp: exp, + Fee: new(uint256.Uint256).SetZero(), } asp2 := &ASPreImage{} aspBytes, err := asp.MarshalBinary() @@ -300,6 +303,7 @@ func TestASPreImageBad4(t *testing.T) { Owner: owner, IssuedAt: iat, Exp: exp, + Fee: new(uint256.Uint256).SetZero(), } asp2 := &ASPreImage{} aspBytes, err := asp.MarshalBinary() @@ -356,6 +360,7 @@ func TestASPreImageBad5(t *testing.T) { Owner: owner, IssuedAt: iat, Exp: exp, + Fee: new(uint256.Uint256).SetZero(), } asp2 := &ASPreImage{} aspBytes, err := asp.MarshalBinary() diff --git a/application/objs/capn/application.capnp b/application/objs/capn/application.capnp index 65af9219..66e6fe76 100644 --- a/application/objs/capn/application.capnp +++ b/application/objs/capn/application.capnp @@ -3,10 +3,11 @@ using Go = import "/go.capnp"; $Go.package("capn"); $Go.import("github.com/MadBase/MadNet/application/capn"); -const defaultDSPreImage :DSPreImage = (chainID = 0, index = 0x"00", issuedAt = 0, deposit = 0, rawData = 0x"00", owner = 0x"00"); +const defaultDSPreImage :DSPreImage = (chainID = 0, index = 0x"00", issuedAt = 0, deposit = 0, rawData = 0x"00", owner = 0x"00", deposit1 = 0, deposit2 = 0, deposit3 = 0, deposit4 = 0, deposit5 = 0, deposit6 = 0, deposit7 = 0, fee0 = 0, fee1 = 0, fee2 = 0, fee3 = 0, fee4 = 0, fee5 = 0, fee6 = 0, fee7 = 0); const defaultDSLinker :DSLinker = (txHash = 0x"00", dSPreImage = .defaultDSPreImage); -const defaultVSPreImage :VSPreImage = (chainID = 0, value = 0, owner = 0x"00"); -const defaultASPreImage :ASPreImage = (chainID = 0, value = 0, owner = 0x"00", issuedAt = 0, exp = 0); +const defaultVSPreImage :VSPreImage = (chainID = 0, value = 0, owner = 0x"00", value1 = 0, value2 = 0, value3 = 0, value4 = 0, value5 = 0, value6 = 0, value7 = 0, fee0 = 0, fee1 = 0, fee2 = 0, fee3 = 0, fee4 = 0, fee5 = 0, fee6 = 0, fee7 = 0); +const defaultASPreImage :ASPreImage = (chainID = 0, value = 0, owner = 0x"00", issuedAt = 0, exp = 0, value1 = 0, value2 = 0, value3 = 0, value4 = 0, value5 = 0, value6 = 0, value7 = 0, fee0 = 0, fee1 = 0, fee2 = 0, fee3 = 0, fee4 = 0, fee5 = 0, fee6 = 0, fee7 = 0); +const defaultTFPreImage :TFPreImage = (chainID = 0, fee0 = 0, fee1 = 0, fee2 = 0, fee3 = 0, fee4 = 0, fee5 = 0, fee6 = 0, fee7 = 0); const defaultTXInPreImage :TXInPreImage = (chainID = 0, consumedTxIdx = 0, consumedTxHash = 0x"00"); const defaultTXInLinker :TXInLinker = (tXInPreImage = .defaultTXInPreImage, txHash = 0x"00"); @@ -37,6 +38,17 @@ struct DSPreImage { deposit5 @11 :UInt32 = 0; deposit6 @12 :UInt32 = 0; deposit7 @13 :UInt32 = 0; + # Deposit stores the value of the DataStore + + fee0 @14 :UInt32 = 0; + fee1 @15 :UInt32 = 0; + fee2 @16 :UInt32 = 0; + fee3 @17 :UInt32 = 0; + fee4 @18 :UInt32 = 0; + fee5 @19 :UInt32 = 0; + fee6 @20 :UInt32 = 0; + fee7 @21 :UInt32 = 0; + # Fee stores the associated fee for a DataStore } struct DSLinker { @@ -75,6 +87,17 @@ struct VSPreImage { value5 @8 :UInt32 = 0; value6 @9 :UInt32 = 0; value7 @10 :UInt32 = 0; + # Value stores the value + + fee0 @11 :UInt32 = 0; + fee1 @12 :UInt32 = 0; + fee2 @13 :UInt32 = 0; + fee3 @14 :UInt32 = 0; + fee4 @15 :UInt32 = 0; + fee5 @16 :UInt32 = 0; + fee6 @17 :UInt32 = 0; + fee7 @18 :UInt32 = 0; + # Fee stores the associated fee for a ValueStore } struct ValueStore { @@ -114,6 +137,17 @@ struct ASPreImage { value5 @10 :UInt32 = 0; value6 @11 :UInt32 = 0; value7 @12 :UInt32 = 0; + # Value stores the value which is to be swapped + + fee0 @13 :UInt32 = 0; + fee1 @14 :UInt32 = 0; + fee2 @15 :UInt32 = 0; + fee3 @16 :UInt32 = 0; + fee4 @17 :UInt32 = 0; + fee5 @18 :UInt32 = 0; + fee6 @19 :UInt32 = 0; + fee7 @20 :UInt32 = 0; + # Fee stores the associated fee for an AtomicSwap } struct AtomicSwap { @@ -126,6 +160,34 @@ struct AtomicSwap { ################################################################################ +struct TFPreImage { + chainID @0 :UInt32 = 0; + # The chainID of this object. + + tXOutIdx @1 :UInt32 = 0; + # The index at which this element appears in the transaction output list. + + fee0 @2 :UInt32 = 0; + fee1 @3 :UInt32 = 0; + fee2 @4 :UInt32 = 0; + fee3 @5 :UInt32 = 0; + fee4 @6 :UInt32 = 0; + fee5 @7 :UInt32 = 0; + fee6 @8 :UInt32 = 0; + fee7 @9 :UInt32 = 0; + # Fee stores the fee +} + +struct TxFee { + tFPreImage @0 :TFPreImage = .defaultTFPreImage; + # The structure containing particular information for this object. + + txHash @1 :Data = 0x"00"; + # The hash of the transaction that created this object. +} + +################################################################################ + struct TXInPreImage { chainID @0 :UInt32 = 0; # Chain id on which this object was created. @@ -167,6 +229,10 @@ struct TXOut { # The output if it is a valuestore atomicSwap @2 :AtomicSwap; + # The output if it is an atomicswap + + txFee @3 :TxFee; + # The output if it is a txfee } } diff --git a/application/objs/capn/application.capnp.go b/application/objs/capn/application.capnp.go index 92043b0f..2f200131 100644 --- a/application/objs/capn/application.capnp.go +++ b/application/objs/capn/application.capnp.go @@ -11,12 +11,13 @@ import ( // Constants defined in application.capnp. var ( - DefaultDSPreImage = DSPreImage{Struct: capnp.MustUnmarshalRootPtr(x_b99093b7d2518300[0:112]).Struct()} - DefaultDSLinker = DSLinker{Struct: capnp.MustUnmarshalRootPtr(x_b99093b7d2518300[112:248]).Struct()} - DefaultVSPreImage = VSPreImage{Struct: capnp.MustUnmarshalRootPtr(x_b99093b7d2518300[248:320]).Struct()} - DefaultASPreImage = ASPreImage{Struct: capnp.MustUnmarshalRootPtr(x_b99093b7d2518300[320:400]).Struct()} - DefaultTXInPreImage = TXInPreImage{Struct: capnp.MustUnmarshalRootPtr(x_b99093b7d2518300[400:440]).Struct()} - DefaultTXInLinker = TXInLinker{Struct: capnp.MustUnmarshalRootPtr(x_b99093b7d2518300[440:504]).Struct()} + DefaultDSPreImage = DSPreImage{Struct: capnp.MustUnmarshalRootPtr(x_b99093b7d2518300[0:144]).Struct()} + DefaultDSLinker = DSLinker{Struct: capnp.MustUnmarshalRootPtr(x_b99093b7d2518300[144:312]).Struct()} + DefaultVSPreImage = VSPreImage{Struct: capnp.MustUnmarshalRootPtr(x_b99093b7d2518300[312:416]).Struct()} + DefaultASPreImage = ASPreImage{Struct: capnp.MustUnmarshalRootPtr(x_b99093b7d2518300[416:528]).Struct()} + DefaultTFPreImage = TFPreImage{Struct: capnp.MustUnmarshalRootPtr(x_b99093b7d2518300[528:584]).Struct()} + DefaultTXInPreImage = TXInPreImage{Struct: capnp.MustUnmarshalRootPtr(x_b99093b7d2518300[584:624]).Struct()} + DefaultTXInLinker = TXInLinker{Struct: capnp.MustUnmarshalRootPtr(x_b99093b7d2518300[624:688]).Struct()} ) func init() { @@ -25,6 +26,7 @@ func init() { DefaultDSLinker.Segment().Message().ReadLimiter().Reset((1 << 64) - 1) DefaultVSPreImage.Segment().Message().ReadLimiter().Reset((1 << 64) - 1) DefaultASPreImage.Segment().Message().ReadLimiter().Reset((1 << 64) - 1) + DefaultTFPreImage.Segment().Message().ReadLimiter().Reset((1 << 64) - 1) DefaultTXInPreImage.Segment().Message().ReadLimiter().Reset((1 << 64) - 1) DefaultTXInLinker.Segment().Message().ReadLimiter().Reset((1 << 64) - 1) } @@ -35,12 +37,12 @@ type DSPreImage struct{ capnp.Struct } const DSPreImage_TypeID = 0xd4eb3c212b8dbb26 func NewDSPreImage(s *capnp.Segment) (DSPreImage, error) { - st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 48, PointerCount: 3}) + st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 80, PointerCount: 3}) return DSPreImage{st}, err } func NewRootDSPreImage(s *capnp.Segment) (DSPreImage, error) { - st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 48, PointerCount: 3}) + st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 80, PointerCount: 3}) return DSPreImage{st}, err } @@ -190,12 +192,76 @@ func (s DSPreImage) SetDeposit7(v uint32) { s.Struct.SetUint32(40, v) } +func (s DSPreImage) Fee0() uint32 { + return s.Struct.Uint32(44) +} + +func (s DSPreImage) SetFee0(v uint32) { + s.Struct.SetUint32(44, v) +} + +func (s DSPreImage) Fee1() uint32 { + return s.Struct.Uint32(48) +} + +func (s DSPreImage) SetFee1(v uint32) { + s.Struct.SetUint32(48, v) +} + +func (s DSPreImage) Fee2() uint32 { + return s.Struct.Uint32(52) +} + +func (s DSPreImage) SetFee2(v uint32) { + s.Struct.SetUint32(52, v) +} + +func (s DSPreImage) Fee3() uint32 { + return s.Struct.Uint32(56) +} + +func (s DSPreImage) SetFee3(v uint32) { + s.Struct.SetUint32(56, v) +} + +func (s DSPreImage) Fee4() uint32 { + return s.Struct.Uint32(60) +} + +func (s DSPreImage) SetFee4(v uint32) { + s.Struct.SetUint32(60, v) +} + +func (s DSPreImage) Fee5() uint32 { + return s.Struct.Uint32(64) +} + +func (s DSPreImage) SetFee5(v uint32) { + s.Struct.SetUint32(64, v) +} + +func (s DSPreImage) Fee6() uint32 { + return s.Struct.Uint32(68) +} + +func (s DSPreImage) SetFee6(v uint32) { + s.Struct.SetUint32(68, v) +} + +func (s DSPreImage) Fee7() uint32 { + return s.Struct.Uint32(72) +} + +func (s DSPreImage) SetFee7(v uint32) { + s.Struct.SetUint32(72, v) +} + // DSPreImage_List is a list of DSPreImage. type DSPreImage_List struct{ capnp.List } // NewDSPreImage creates a new list of DSPreImage. func NewDSPreImage_List(s *capnp.Segment, sz int32) (DSPreImage_List, error) { - l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 48, PointerCount: 3}, sz) + l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 80, PointerCount: 3}, sz) return DSPreImage_List{l}, err } @@ -246,7 +312,7 @@ func (s DSLinker) DSPreImage() DSPreImage { s.NewDSPreImage() } p, _ := s.Struct.Ptr(0) - ss, _ := p.StructDefault(x_b99093b7d2518300[504:616]) + ss, _ := p.StructDefault(x_b99093b7d2518300[688:832]) return DSPreImage{Struct: ss} } @@ -313,7 +379,7 @@ func (p DSLinker_Promise) Struct() (DSLinker, error) { } func (p DSLinker_Promise) DSPreImage() DSPreImage_Promise { - return DSPreImage_Promise{Pipeline: p.Pipeline.GetPipelineDefault(0, x_b99093b7d2518300[616:728])} + return DSPreImage_Promise{Pipeline: p.Pipeline.GetPipelineDefault(0, x_b99093b7d2518300[832:976])} } type DataStore struct{ capnp.Struct } @@ -346,7 +412,7 @@ func (s DataStore) DSLinker() DSLinker { s.NewDSLinker() } p, _ := s.Struct.Ptr(0) - ss, _ := p.StructDefault(x_b99093b7d2518300[728:864]) + ss, _ := p.StructDefault(x_b99093b7d2518300[976:1144]) return DSLinker{Struct: ss} } @@ -413,7 +479,7 @@ func (p DataStore_Promise) Struct() (DataStore, error) { } func (p DataStore_Promise) DSLinker() DSLinker_Promise { - return DSLinker_Promise{Pipeline: p.Pipeline.GetPipelineDefault(0, x_b99093b7d2518300[864:1000])} + return DSLinker_Promise{Pipeline: p.Pipeline.GetPipelineDefault(0, x_b99093b7d2518300[1144:1312])} } type VSPreImage struct{ capnp.Struct } @@ -422,12 +488,12 @@ type VSPreImage struct{ capnp.Struct } const VSPreImage_TypeID = 0xf8c203f305398e1b func NewVSPreImage(s *capnp.Segment) (VSPreImage, error) { - st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 40, PointerCount: 1}) + st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 72, PointerCount: 1}) return VSPreImage{st}, err } func NewRootVSPreImage(s *capnp.Segment) (VSPreImage, error) { - st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 40, PointerCount: 1}) + st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 72, PointerCount: 1}) return VSPreImage{st}, err } @@ -537,12 +603,76 @@ func (s VSPreImage) SetValue7(v uint32) { s.Struct.SetUint32(36, v) } +func (s VSPreImage) Fee0() uint32 { + return s.Struct.Uint32(40) +} + +func (s VSPreImage) SetFee0(v uint32) { + s.Struct.SetUint32(40, v) +} + +func (s VSPreImage) Fee1() uint32 { + return s.Struct.Uint32(44) +} + +func (s VSPreImage) SetFee1(v uint32) { + s.Struct.SetUint32(44, v) +} + +func (s VSPreImage) Fee2() uint32 { + return s.Struct.Uint32(48) +} + +func (s VSPreImage) SetFee2(v uint32) { + s.Struct.SetUint32(48, v) +} + +func (s VSPreImage) Fee3() uint32 { + return s.Struct.Uint32(52) +} + +func (s VSPreImage) SetFee3(v uint32) { + s.Struct.SetUint32(52, v) +} + +func (s VSPreImage) Fee4() uint32 { + return s.Struct.Uint32(56) +} + +func (s VSPreImage) SetFee4(v uint32) { + s.Struct.SetUint32(56, v) +} + +func (s VSPreImage) Fee5() uint32 { + return s.Struct.Uint32(60) +} + +func (s VSPreImage) SetFee5(v uint32) { + s.Struct.SetUint32(60, v) +} + +func (s VSPreImage) Fee6() uint32 { + return s.Struct.Uint32(64) +} + +func (s VSPreImage) SetFee6(v uint32) { + s.Struct.SetUint32(64, v) +} + +func (s VSPreImage) Fee7() uint32 { + return s.Struct.Uint32(68) +} + +func (s VSPreImage) SetFee7(v uint32) { + s.Struct.SetUint32(68, v) +} + // VSPreImage_List is a list of VSPreImage. type VSPreImage_List struct{ capnp.List } // NewVSPreImage creates a new list of VSPreImage. func NewVSPreImage_List(s *capnp.Segment, sz int32) (VSPreImage_List, error) { - l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 40, PointerCount: 1}, sz) + l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 72, PointerCount: 1}, sz) return VSPreImage_List{l}, err } @@ -593,7 +723,7 @@ func (s ValueStore) VSPreImage() VSPreImage { s.NewVSPreImage() } p, _ := s.Struct.Ptr(0) - ss, _ := p.StructDefault(x_b99093b7d2518300[1000:1072]) + ss, _ := p.StructDefault(x_b99093b7d2518300[1312:1416]) return VSPreImage{Struct: ss} } @@ -660,7 +790,7 @@ func (p ValueStore_Promise) Struct() (ValueStore, error) { } func (p ValueStore_Promise) VSPreImage() VSPreImage_Promise { - return VSPreImage_Promise{Pipeline: p.Pipeline.GetPipelineDefault(0, x_b99093b7d2518300[1072:1144])} + return VSPreImage_Promise{Pipeline: p.Pipeline.GetPipelineDefault(0, x_b99093b7d2518300[1416:1520])} } type ASPreImage struct{ capnp.Struct } @@ -669,12 +799,12 @@ type ASPreImage struct{ capnp.Struct } const ASPreImage_TypeID = 0xa6bc62ab6b339789 func NewASPreImage(s *capnp.Segment) (ASPreImage, error) { - st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 48, PointerCount: 1}) + st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 80, PointerCount: 1}) return ASPreImage{st}, err } func NewRootASPreImage(s *capnp.Segment) (ASPreImage, error) { - st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 48, PointerCount: 1}) + st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 80, PointerCount: 1}) return ASPreImage{st}, err } @@ -800,12 +930,76 @@ func (s ASPreImage) SetValue7(v uint32) { s.Struct.SetUint32(44, v) } +func (s ASPreImage) Fee0() uint32 { + return s.Struct.Uint32(48) +} + +func (s ASPreImage) SetFee0(v uint32) { + s.Struct.SetUint32(48, v) +} + +func (s ASPreImage) Fee1() uint32 { + return s.Struct.Uint32(52) +} + +func (s ASPreImage) SetFee1(v uint32) { + s.Struct.SetUint32(52, v) +} + +func (s ASPreImage) Fee2() uint32 { + return s.Struct.Uint32(56) +} + +func (s ASPreImage) SetFee2(v uint32) { + s.Struct.SetUint32(56, v) +} + +func (s ASPreImage) Fee3() uint32 { + return s.Struct.Uint32(60) +} + +func (s ASPreImage) SetFee3(v uint32) { + s.Struct.SetUint32(60, v) +} + +func (s ASPreImage) Fee4() uint32 { + return s.Struct.Uint32(64) +} + +func (s ASPreImage) SetFee4(v uint32) { + s.Struct.SetUint32(64, v) +} + +func (s ASPreImage) Fee5() uint32 { + return s.Struct.Uint32(68) +} + +func (s ASPreImage) SetFee5(v uint32) { + s.Struct.SetUint32(68, v) +} + +func (s ASPreImage) Fee6() uint32 { + return s.Struct.Uint32(72) +} + +func (s ASPreImage) SetFee6(v uint32) { + s.Struct.SetUint32(72, v) +} + +func (s ASPreImage) Fee7() uint32 { + return s.Struct.Uint32(76) +} + +func (s ASPreImage) SetFee7(v uint32) { + s.Struct.SetUint32(76, v) +} + // ASPreImage_List is a list of ASPreImage. type ASPreImage_List struct{ capnp.List } // NewASPreImage creates a new list of ASPreImage. func NewASPreImage_List(s *capnp.Segment, sz int32) (ASPreImage_List, error) { - l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 48, PointerCount: 1}, sz) + l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 80, PointerCount: 1}, sz) return ASPreImage_List{l}, err } @@ -856,7 +1050,7 @@ func (s AtomicSwap) ASPreImage() ASPreImage { s.NewASPreImage() } p, _ := s.Struct.Ptr(0) - ss, _ := p.StructDefault(x_b99093b7d2518300[1144:1224]) + ss, _ := p.StructDefault(x_b99093b7d2518300[1520:1632]) return ASPreImage{Struct: ss} } @@ -923,7 +1117,238 @@ func (p AtomicSwap_Promise) Struct() (AtomicSwap, error) { } func (p AtomicSwap_Promise) ASPreImage() ASPreImage_Promise { - return ASPreImage_Promise{Pipeline: p.Pipeline.GetPipelineDefault(0, x_b99093b7d2518300[1224:1304])} + return ASPreImage_Promise{Pipeline: p.Pipeline.GetPipelineDefault(0, x_b99093b7d2518300[1632:1744])} +} + +type TFPreImage struct{ capnp.Struct } + +// TFPreImage_TypeID is the unique identifier for the type TFPreImage. +const TFPreImage_TypeID = 0x828d564f51f7af4e + +func NewTFPreImage(s *capnp.Segment) (TFPreImage, error) { + st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 40, PointerCount: 0}) + return TFPreImage{st}, err +} + +func NewRootTFPreImage(s *capnp.Segment) (TFPreImage, error) { + st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 40, PointerCount: 0}) + return TFPreImage{st}, err +} + +func ReadRootTFPreImage(msg *capnp.Message) (TFPreImage, error) { + root, err := msg.RootPtr() + return TFPreImage{root.Struct()}, err +} + +func (s TFPreImage) String() string { + str, _ := text.Marshal(0x828d564f51f7af4e, s.Struct) + return str +} + +func (s TFPreImage) ChainID() uint32 { + return s.Struct.Uint32(0) +} + +func (s TFPreImage) SetChainID(v uint32) { + s.Struct.SetUint32(0, v) +} + +func (s TFPreImage) TXOutIdx() uint32 { + return s.Struct.Uint32(4) +} + +func (s TFPreImage) SetTXOutIdx(v uint32) { + s.Struct.SetUint32(4, v) +} + +func (s TFPreImage) Fee0() uint32 { + return s.Struct.Uint32(8) +} + +func (s TFPreImage) SetFee0(v uint32) { + s.Struct.SetUint32(8, v) +} + +func (s TFPreImage) Fee1() uint32 { + return s.Struct.Uint32(12) +} + +func (s TFPreImage) SetFee1(v uint32) { + s.Struct.SetUint32(12, v) +} + +func (s TFPreImage) Fee2() uint32 { + return s.Struct.Uint32(16) +} + +func (s TFPreImage) SetFee2(v uint32) { + s.Struct.SetUint32(16, v) +} + +func (s TFPreImage) Fee3() uint32 { + return s.Struct.Uint32(20) +} + +func (s TFPreImage) SetFee3(v uint32) { + s.Struct.SetUint32(20, v) +} + +func (s TFPreImage) Fee4() uint32 { + return s.Struct.Uint32(24) +} + +func (s TFPreImage) SetFee4(v uint32) { + s.Struct.SetUint32(24, v) +} + +func (s TFPreImage) Fee5() uint32 { + return s.Struct.Uint32(28) +} + +func (s TFPreImage) SetFee5(v uint32) { + s.Struct.SetUint32(28, v) +} + +func (s TFPreImage) Fee6() uint32 { + return s.Struct.Uint32(32) +} + +func (s TFPreImage) SetFee6(v uint32) { + s.Struct.SetUint32(32, v) +} + +func (s TFPreImage) Fee7() uint32 { + return s.Struct.Uint32(36) +} + +func (s TFPreImage) SetFee7(v uint32) { + s.Struct.SetUint32(36, v) +} + +// TFPreImage_List is a list of TFPreImage. +type TFPreImage_List struct{ capnp.List } + +// NewTFPreImage creates a new list of TFPreImage. +func NewTFPreImage_List(s *capnp.Segment, sz int32) (TFPreImage_List, error) { + l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 40, PointerCount: 0}, sz) + return TFPreImage_List{l}, err +} + +func (s TFPreImage_List) At(i int) TFPreImage { return TFPreImage{s.List.Struct(i)} } + +func (s TFPreImage_List) Set(i int, v TFPreImage) error { return s.List.SetStruct(i, v.Struct) } + +func (s TFPreImage_List) String() string { + str, _ := text.MarshalList(0x828d564f51f7af4e, s.List) + return str +} + +// TFPreImage_Promise is a wrapper for a TFPreImage promised by a client call. +type TFPreImage_Promise struct{ *capnp.Pipeline } + +func (p TFPreImage_Promise) Struct() (TFPreImage, error) { + s, err := p.Pipeline.Struct() + return TFPreImage{s}, err +} + +type TxFee struct{ capnp.Struct } + +// TxFee_TypeID is the unique identifier for the type TxFee. +const TxFee_TypeID = 0x89c736f29fb5bda4 + +func NewTxFee(s *capnp.Segment) (TxFee, error) { + st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 2}) + return TxFee{st}, err +} + +func NewRootTxFee(s *capnp.Segment) (TxFee, error) { + st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 2}) + return TxFee{st}, err +} + +func ReadRootTxFee(msg *capnp.Message) (TxFee, error) { + root, err := msg.RootPtr() + return TxFee{root.Struct()}, err +} + +func (s TxFee) String() string { + str, _ := text.Marshal(0x89c736f29fb5bda4, s.Struct) + return str +} + +func (s TxFee) TFPreImage() TFPreImage { + if !s.HasTFPreImage() { + s.NewTFPreImage() + } + p, _ := s.Struct.Ptr(0) + ss, _ := p.StructDefault(x_b99093b7d2518300[1744:1800]) + return TFPreImage{Struct: ss} +} + +func (s TxFee) HasTFPreImage() bool { + p, err := s.Struct.Ptr(0) + return p.IsValid() || err != nil +} + +func (s TxFee) SetTFPreImage(v TFPreImage) error { + return s.Struct.SetPtr(0, v.Struct.ToPtr()) +} + +// NewTFPreImage sets the tFPreImage field to a newly +// allocated TFPreImage struct, preferring placement in s's segment. +func (s TxFee) NewTFPreImage() (TFPreImage, error) { + ss, err := NewTFPreImage(s.Struct.Segment()) + if err != nil { + return TFPreImage{}, err + } + err = s.Struct.SetPtr(0, ss.Struct.ToPtr()) + return ss, err +} +func (s TxFee) TxHash() []byte { + p, _ := s.Struct.Ptr(1) + return []byte(p.DataDefault([]byte{0x0})) +} + +func (s TxFee) HasTxHash() bool { + p, err := s.Struct.Ptr(1) + return p.IsValid() || err != nil +} + +func (s TxFee) SetTxHash(v []byte) error { + if v == nil { + v = []byte{} + } + return s.Struct.SetData(1, v) +} + +// TxFee_List is a list of TxFee. +type TxFee_List struct{ capnp.List } + +// NewTxFee creates a new list of TxFee. +func NewTxFee_List(s *capnp.Segment, sz int32) (TxFee_List, error) { + l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 0, PointerCount: 2}, sz) + return TxFee_List{l}, err +} + +func (s TxFee_List) At(i int) TxFee { return TxFee{s.List.Struct(i)} } + +func (s TxFee_List) Set(i int, v TxFee) error { return s.List.SetStruct(i, v.Struct) } + +func (s TxFee_List) String() string { + str, _ := text.MarshalList(0x89c736f29fb5bda4, s.List) + return str +} + +// TxFee_Promise is a wrapper for a TxFee promised by a client call. +type TxFee_Promise struct{ *capnp.Pipeline } + +func (p TxFee_Promise) Struct() (TxFee, error) { + s, err := p.Pipeline.Struct() + return TxFee{s}, err +} + +func (p TxFee_Promise) TFPreImage() TFPreImage_Promise { + return TFPreImage_Promise{Pipeline: p.Pipeline.GetPipelineDefault(0, x_b99093b7d2518300[1800:1856])} } type TXInPreImage struct{ capnp.Struct } @@ -1040,7 +1465,7 @@ func (s TXInLinker) TXInPreImage() TXInPreImage { s.NewTXInPreImage() } p, _ := s.Struct.Ptr(0) - ss, _ := p.StructDefault(x_b99093b7d2518300[1304:1344]) + ss, _ := p.StructDefault(x_b99093b7d2518300[1856:1896]) return TXInPreImage{Struct: ss} } @@ -1107,7 +1532,7 @@ func (p TXInLinker_Promise) Struct() (TXInLinker, error) { } func (p TXInLinker_Promise) TXInPreImage() TXInPreImage_Promise { - return TXInPreImage_Promise{Pipeline: p.Pipeline.GetPipelineDefault(0, x_b99093b7d2518300[1344:1384])} + return TXInPreImage_Promise{Pipeline: p.Pipeline.GetPipelineDefault(0, x_b99093b7d2518300[1896:1936])} } type TXIn struct{ capnp.Struct } @@ -1140,7 +1565,7 @@ func (s TXIn) TXInLinker() TXInLinker { s.NewTXInLinker() } p, _ := s.Struct.Ptr(0) - ss, _ := p.StructDefault(x_b99093b7d2518300[1384:1448]) + ss, _ := p.StructDefault(x_b99093b7d2518300[1936:2000]) return TXInLinker{Struct: ss} } @@ -1207,7 +1632,7 @@ func (p TXIn_Promise) Struct() (TXIn, error) { } func (p TXIn_Promise) TXInLinker() TXInLinker_Promise { - return TXInLinker_Promise{Pipeline: p.Pipeline.GetPipelineDefault(0, x_b99093b7d2518300[1448:1512])} + return TXInLinker_Promise{Pipeline: p.Pipeline.GetPipelineDefault(0, x_b99093b7d2518300[2000:2064])} } type TXOut struct{ capnp.Struct } @@ -1217,10 +1642,11 @@ const ( TXOut_Which_dataStore TXOut_Which = 0 TXOut_Which_valueStore TXOut_Which = 1 TXOut_Which_atomicSwap TXOut_Which = 2 + TXOut_Which_txFee TXOut_Which = 3 ) func (w TXOut_Which) String() string { - const s = "dataStorevalueStoreatomicSwap" + const s = "dataStorevalueStoreatomicSwaptxFee" switch w { case TXOut_Which_dataStore: return s[0:9] @@ -1228,6 +1654,8 @@ func (w TXOut_Which) String() string { return s[9:19] case TXOut_Which_atomicSwap: return s[19:29] + case TXOut_Which_txFee: + return s[29:34] } return "TXOut_Which(" + strconv.FormatUint(uint64(w), 10) + ")" @@ -1364,6 +1792,41 @@ func (s TXOut) NewAtomicSwap() (AtomicSwap, error) { err = s.Struct.SetPtr(0, ss.Struct.ToPtr()) return ss, err } +func (s TXOut) TxFee() (TxFee, error) { + if s.Struct.Uint16(0) != 3 { + panic("Which() != txFee") + } + p, err := s.Struct.Ptr(0) + if err != nil { + return TxFee{}, err + } + return TxFee{Struct: p.Struct()}, err +} + +func (s TXOut) HasTxFee() bool { + if s.Struct.Uint16(0) != 3 { + return false + } + p, err := s.Struct.Ptr(0) + return p.IsValid() || err != nil +} + +func (s TXOut) SetTxFee(v TxFee) error { + s.Struct.SetUint16(0, 3) + return s.Struct.SetPtr(0, v.Struct.ToPtr()) +} + +// NewTxFee sets the txFee field to a newly +// allocated TxFee struct, preferring placement in s's segment. +func (s TXOut) NewTxFee() (TxFee, error) { + s.Struct.SetUint16(0, 3) + ss, err := NewTxFee(s.Struct.Segment()) + if err != nil { + return TxFee{}, err + } + err = s.Struct.SetPtr(0, ss.Struct.ToPtr()) + return ss, err +} // TXOut_List is a list of TXOut. type TXOut_List struct{ capnp.List } @@ -1403,6 +1866,10 @@ func (p TXOut_Promise) AtomicSwap() AtomicSwap_Promise { return AtomicSwap_Promise{Pipeline: p.Pipeline.GetPipeline(0)} } +func (p TXOut_Promise) TxFee() TxFee_Promise { + return TxFee_Promise{Pipeline: p.Pipeline.GetPipeline(0)} +} + type Tx struct{ capnp.Struct } // Tx_TypeID is the unique identifier for the type Tx. @@ -1433,7 +1900,7 @@ func (s Tx) Vin() (TXIn_List, error) { if err != nil { return TXIn_List{}, err } - l, err := p.ListDefault(x_b99093b7d2518300[1512:1536]) + l, err := p.ListDefault(x_b99093b7d2518300[2064:2088]) return TXIn_List{List: l}, err } @@ -1462,7 +1929,7 @@ func (s Tx) Vout() (TXOut_List, error) { if err != nil { return TXOut_List{}, err } - l, err := p.ListDefault(x_b99093b7d2518300[1536:1560]) + l, err := p.ListDefault(x_b99093b7d2518300[2088:2112]) return TXOut_List{List: l}, err } @@ -1512,119 +1979,157 @@ func (p Tx_Promise) Struct() (Tx, error) { return Tx{s}, err } -const schema_b99093b7d2518300 = "x\xda\xbc\x97kl\x1cW\x15\xc7\xcf\x99;3\xeb]" + - "?w\xef\x0a\x90\x10Jk%\x08\x17\x83\xe2Wb\"" + - "\x1b\xdb\xedZ\xf2V\x8e\xb2\xd3\xd9\x16S\xb9R\x07\xef" + - "\x10o\x9d}\xb0\x9e\x8d7\x88\xaaAi\xa4VrB" + - "\xa2\xa6\xd4\x91\xd2\x92\xa8\xb4J\xa9x\x04Z\xd1\xb4A" + - "\xa2\x11\x05W*R\x83ZAQK\x05\x82\xa2\x1a!" + - "@|A@3\xe8\x9c\xd9\xd7\xec\xaec#!\xa4\xfd" + - "\xb0\xf7\xb7g\xef\xfd\xdfs\xcf\xfd\x9f\x99\xdds\xda\xa4" + - "2\xa0\xed\xd5\x01\x8c\x19MwK\x91\xdf<\xd9\xb77" + - "\x7f\x12\xc2\x11\xf5\xfa1\xe3\x17?|\xe4\xd4e\xc0!" + - "\x14\xbd(\xc3\"\x00`v\x08\x81\xe6G\x84\x82\x00\xee" + - "\xfa{K\xf7\x1a\xe7\xd6NC8\x82\x95hM\x09\x00" + - "\xc8>\xf1k9B\xf1r@\xac\x00\xba\xfd\x1f\x1b\xfd" + - "\xd2\xfa\xf0\xea\xa3\xcd\x91\xaf\x88\x0dy\x8d#\x7f\xce\x91" + - "\x9f\xbd\xef@?>\xe9>\xd6\x1c9\xae~KN\xab" + - "\xf4mJ\xa5\xc8\xd5\xb1\xf7\x1e\x1f~\xe4Ck\x0dZ" + - "_Q{Q\xbeIq\xe6\xeb\xaa@\xf3m\x95\xb5\xde" + - "\xb44\xfa\xb7\x17\xde\xbdm\xady\xde\x0f\xd4\xdf\xc9\xa0" + - "F\xdf4\x8d\xe6\xbd\xedg\xff\xfe\xfe\xd7\x06\x07\xce7" + - "G>\xa3m\xc8\xe79\xf2\x12G\xde\x92\xba\xfe\xec\xe4" + - "\xe7\x8e\x9doP0\xa0GPN\xe9\xa4`L\x17h" + - "\xce\xe8\xac\xe0\xcc\xf4\xf8/\x8f\xfdu\xf8\xe9\x86\xe8\xa2" + - "\xde\x8b\xf28G\x1f\xa5\xe8U/\xfa\xe1\xc7\x86\x96\x9e" + - "\xfd\xc2\x95\xa7\xc1\x88\xa0^\x95\x81\xb4\xf8Y}C>" + - "E\x7f\x18\xba\xa0\xbf\xab\x00\xba\xef\xf7\xedy\xe2\xa7'" + - "\x8f|\xa7a\xe6\xc7\x83\x83(\xbf\x1d\xa4\x99/\x06\x05" + - "\x9a\xcf\x05y\xe6s?\x88\xcd\xbf\xf3G\xedR\xf3\xfe" + - ".\x05_\x94\x97)^>\x1f\xa4\xfd}\xe3\xc5?|" + - "\xfd/\xbb\x94\x97H\x03\xfa5\x8c\x84\xfe)\xa7B|" + - ",\xa1\xef\x02\xba\xe6\x8f.\xec\xb9j\xbf\xfcj\xf3\xa4" + - "\xbf\x0dm\xc8?s\xe4\xfb!\x9a\xf4\xe3/\x9d\xf8\xe4" + - "\xcdc\x7fz\xc3\xbf1\xae\x80L\xfb\x86<\xd2N\x1b" + - "+\xb6\x7fX\x00\xba\x1f=\xf9\x19\xed\xef\xe2\xea?(" + - "V\xf3\x0b\xb8\xd6\xb5!\xdf\xe9\xa2\xd8\xb7\xbar\x94\x84" + - "\x9d\x85\xf1\xa7^\xdb\x15\xfb\x97O\xec4\x06\x04\x80\xfc" + - "|\xf8\xaa\xb4\xc2\xf4\xb7{\xc2\xa4\xf6\xe67\xaf\x9c\xda" + - "\xbf\xfe\x84\xdbX\xe6\x11*\xf3\x08\x97y\x84\xca<\xc2" + - "\x09\xb3\xf2\xf9C\xe9\x05\xcb\x11\xe9\\\xf6\xd3\x0bV>" + - "\x9b\xdf\x97\xb2\xbfh\x15\x0f9Sf\xa2`\xc73\x01" + - "\xeb\xa0\x9d@\xc4\x9e\xda\xa9\x01b\x0f@BG\xd0\xc2" + - "\x18\xaa\x9bD\xa9M\x123g\xd3\xd9%a\x17\x12\x88" + - "F\x9bP\x01TD\x0c\xf7\xdd\x0d`|B\xa01\xac" + - "`\x181\x8a\x04\xad}\x00\xc6\xbc@cQA7\xe5" + - "-k\x818hcO-\xa3\x95E\x05h\xe1`\xc8" + - "\xfb\x802\xe1\x94f\xac\xe5E\xec\x04\x05;\x016\x95" + - "\x93\x9c\x8bgg\xd3\xdd\xd9\xa5&A\xf7\xb5\x104N" + - "\x82F\x05\x1a1\x05]g.\x9e%I\xd0\x9d\xb1X" + - "R\xb5r\xca\x92\x10\xcb\x0b\xdfP\x0cV\xc4t\xe7\xf7" + - "%K\x0d\"z\x01\x8c\x9d\x02\x8d\xc9:\x11S\xb7\x00" + - "\x18c\x02\x8d9\x05\x03\x87\xd3Y\xec\x02L\x08:\x88" + - "j\x91\x03b\x17\xad\x13\x98T\xba\x0f\xe7\x8aN-\xa4" + - "Z0\xd5\x90\x04\xe2\x0d\x0e;\xd6x\xd8[\xe4\xbd\xe5" + - "\x91[\x8ee:\x81\\\xc1n\xd8\xdd\xed-R\x9c\xb9" + - "\x03\xc08$\xd0(\xf1\x99S\xb1\xd8\x05\x00\xc0\x9e\x9a" + - "\xf3zKO*\x86\xaa\x8b\xf0@\xa8^\x80p\x97\xd3" + - "\x07\xb3\x96S,\x00\xda[\x9e\xfe]\xd6\xa1\xa2mv" + - ";\xcd\xd2Z\x95\xe3~:\xfd\x19\x81FRA\xf7\xb0" + - "\xbf\x1c\xab\x97\xb6\x9c\x16\x0dA\xdd\xfa\xec[\xe5\x9bw" + - "\x8c\x05/\xdb\xdb\xdb\xf2\xe6\xd3\xdd\xd5x|\x9b\xeal" + - "\x95\x1e\xef\xa6sySz\x86+\xe9\x91\xf7\xe0\xad\x00" + - "\xe6\x1c\x0a4S\xa8`X\xf32$-\x1c\x040\xe7" + - "\x89/\x12G%\x8a\x0a\xa2\xb4\xf1v\x003E\xcc\xfcA\xe2\xa7\x88\x07\xdb\xa2" + - "\x18D\x94'\x98?D\xfc\x0c\xf1P0\x8a!Dy" + - "\x9a\xf9*\xf15\xe2\xed\xa1(\xb6#\xcaG\x99\x9f\"" + - "~\x8exG{\x14;\x10\xe5Y\xe6g\x88\x9fG\x05" + - "\x1fXX\xb4\xd2\xd9x\x0c\xdb@\xc16\xc0\x1d\x87\xa9" + - "\xec*#\xd7\x99;Pt\xe2\xa9\x12\x15y%\"\xb7" + - "\x92\xb5\x0b\xfe\x9aI//\x17\xed\xd4\x94S\x17\x16\xb0" + - "K\xf9\xca\xf7\x09\x9et\xc0?\x1c\xf4\x0f\x87\xfc\xc3a" + - "\xffp\xc4?\xdc\xe3\x1f\xee\xad\xea\xdd\xbc\xda\x92\x9e#" + - "\xee\x88g\xaa\xf5\xb6\xa9'6\xfb\xdf\x84\xe7\xc6\xdb\xb8" + - "\x88\xf1;\xea.\xa2\xc3\x0e\x9e]\x02a\x17\xb0\xa7\xf6" + - "\xd0U\xbb1\x88\xe1\xce\x90\xb7,\xfeW\xf6\xe0\xedg" + - "\xc2\xae\xec\xc7\xe8\xa8\xea\x9a\xbe\x15\xc0\x98\x14h\xcc\xd6" + - "\xeb*\xd4t\x95K?l|\x19\xc0H\x084\xe6\x9b" + - "\x0b\xc1]\xc8e\x97\x8b\x19;\x05;\x92\xa5x\xaa\xd4" + - "\xcc'\x92\xdbkcSN.\x93^\xe86W\xac\xfc" + - "6\xf2g\x90\x91\xcdz\x1d\xc4\xb5\xfcF\xb6i3\xdf" + - "nG\x8d\xf9Mc\xb4j\x1aG\xd84\xaa\xb7\xba," + - "F\xde\xcf&P\xbb\xd4\x0az\x9eq\x9cM\xa0vI" + - "\xf5\xb2i\x9c\xe0ij\x97T\xa0g\x1a\xa7\x99\xd7." + - "\xa9*<\xd38\xcb\xf3\xac\x11\xff&{\x95\xe2\x99\xc6" + - "\x05^\xf7\x1c\xf1\x8bl\x1a\xaag\x1a\xcfp\xfcE\xe2" + - "\xcf\xb1ih\x9ei\\b\xfe=\xe2W\xd84t\xcf" + - "4.3\x7f\x81\xf8O\xd84\x02\x9ei\xbc\xcc\xfc\xc7" + - "\xc4_c\xd3h\xf3L\xe3U\xe6\xeb\xc4\xdf`\xd3\x08" + - "z\xa6q\x8d\xf9\xeb\xc4\xdf&\xde\x19\x8ab'\xa2|" + - "\x8b\xf9\xaf\x88\xff\xbe\x95\x99\xa4\xb3)\xbb\xb4\xa5U<" + - "\x90\xb2\xf3\xb9\xe5\xb4S\x1d\x17\xac\x15\xea\xcb\xfe?n" + - "\xd3\x8a\xcas\x0d\xd4\x85U\xd8`\x0b6\xd4\x82\x0d\xb7" + - "`#-\xd8\x9e\x16lo=k\xd5\xd5\xfd\x15\xd8_" + - "\xad\xc0]\\\"7Q*\xfb+\xa5C\xbc\x8fKa" + - "'\xf1\xdd\xf5m\xebS\x9c\xfa~\xe2\xa3umk\x84" + - "\xc3w\x13\x1e\xabT\x1aU\xe08\xdb\xfe(\xf1\x18W" + - "Z\xb9mM1\x1f#>S\xdf\xb6\xa6\x99O\x12\x9f" + - "\xado[q\xe61\xe2\x89\xfa\xb6\xb5\x9f\xf9\x0c\xf1d" + - "}\xdb2\x98\xcf\x12\x9f\xabo[w2O\x10\x9f\xff" + - "_\xb5\xa1\xff\x7f\x9b\xf1\xf9\xf1\x81\xa2\x03e#\xeep" + - "]\x95\x9a\xc945\x83\x98@#\xa1`'^w\xa3" + - "\xdcb\xf6\xdf]\xb3\xb8N\xe5\x037\x8a\x0a@\xf8N" + - "\xa2I\x81\xc6\xbd\xf4p\xc9\x8f\xa59\xee\x04=\xb5W" + - "e\xf6=tY\x8d\xe9\xe4@\x14\xe8\xe7\xea\xfbq\xf9" + - "g\x8b\x0d\xd7\\\x01a\xe5\xb1\xa7\xf6&X\xf9\xf9\x86" + - "=r6\x9d\x0dx/\x1c[7\xac\xff\x04\x00\x00\xff" + - "\xffD\x0b\xa4\xe4" +const schema_b99093b7d2518300 = "x\xda\xdc\x98kl\x14\xd7\x15\xc7\xef\x99\xbb\xbb\xb3\xbb" + + "x\xbd\xb3\xbe\x83Ey\x08\xb0Le\xa8i\xb1\xbd6" + + "\x06\xe1\xdaNl\xc4F\xa6x2\x1bj*\x90\xd8\xb2" + + "\x13\xbc\xc1^/\xebYX*P\xa0\x04\x09$\xa0\xa0" + + "\x90\x86H$\x10\xe5\xa1\xa6i\x9b\xa6\x0f5\x0f\"\x15" + + "\x946 \x81\x14*P\xa0*mZ5\x89\xe2~H" + + "\x1f\x1f\xfa\xa2Lu\xce\xec\xee\xcc>\x00W\xaa\x14)" + + "\x92?\xec\xfd\xf9\xcc\x9ds\xe6\xde\xfb?\xff\x99e\x1f" + + "\xcb}R\x9b\xb7WfL\x8b{}\xd6W^\xf9\xbb" + + "\xb6n\xfd\x91o2\xad\x01\xbc\xb7\xf7k\xbf\xfa\xd9\xe3" + + "\xc7^\xf7\xc8\x8c\x89\x03|J\x1c\xe72c\x1dG\xf8" + + "r\x89\x81\xf5\xfc[?=\xfd\xd7\xaew\x0e\xb1H\x03" + + "\x14#\xbd\x12\x86^\xf6\x9e\x17\xd7\xbc\xf8\xeb\x8aw'" + + "\x03+\xdf\xf0\xdb\xe7\x16/\xcf\x1ce\x91\x06O1\x92" + + "AG\xcc\xd7\x04b\x83OfL\x8f\xfb8\xe8\x9b}" + + "\x120f]\xf8p\xdbf\xed\xd4\xc9\xe3\xd5\xf3\xee\xf3" + + "\xfdZ\x1c\xc1xq\xc8\x87\xf3\xb6\xce\xeb\xde~!z" + + "\xf8\x89\xea\xc8\xa5\xf2\x94X!\xe3\xafN\x19#\xbf\xfc" + + "\xc8\xbaVx\xcez\xb2:\xf2\x05\xf9\xbb\xe2\xfb\x14\xf9" + + "\x12E\x1e^\xf5\xe1\xd3\xd1\xc7\x1bOV\xe4\xba\xd4\xdf" + + "\x04\xa2\xc7\x8f\xb9v\xfb9\xe8\x03~\xcau\xc1\xb6\xee" + + "\xbf\xbc\xf6\xbb\xfbOV\xcf\x9b\xf3\xffA\xec\xc3x\xb1" + + "\xc7\x8f\xf3\xde\xff\xce\xad\x1f}\xab\xbd\xedLud[" + + "`J\xf4\x04\xf0\xd7\x8a\x00F.I\xde~\xb9\xef\xab" + + "\xfb\xcfTdp1\xd0\x00\xe2\x06\xc6\xe9W\x03\x1c\xf4" + + "\xf7\x03\x94\xc1\x89\xc1\x9e\xf7\xf6\xff9\xfabE\xf4\xbc" + + "`\x13\x88\xa5A\x8cn\x09r\xd0\xa3A\x8a>\xf4d" + + "\xc7\xb6\x97\xbf~\xf6E\\\xde`)\x0d\xc0\x9bk\xc1" + + ")\xb1\x09/\xe8\xd8\x10<\xeda`}\xbc\xb8\xeb\x99" + + "_\x1e\xdd\xf5\x83\x8a\x99;\xc3\xed \x06\xc38s_" + + "\x98\x83>\x14\xa6\x99O\xfdx`\xe3\xcd\x8f\xbc\xafV" + + "\xd7\x17\x0b\xbf!4\x8c\x17k\xc3X\xdf\xe97>\xf8" + + "\xf6'\x8b\xa471\x07(\xcf\xe1r\xf8_\xe2\x06\x85" + + "^\x0b\xbf\xc2\xc0\xd2\xdfz\xb6\xeb\xbcq\xeeb\xf5\xa4" + + "\xbb\x94)q@\xa1M\xa1\xe0\xa4\x9f\x7f\xf3\xc8\x17\x16" + + "\xae\xfa\xd3\xd5\xf2\xc2p\xbb\x8a\x99\x91)\xb10\x82\x85" + + "\xcd\x8b\xbc\x87\x85\xdd\x8a|\xf2\xcf\xa7\x07z\xaeU\x14" + + "\xb6\xa1\xb1\x09D\xaa\x11\x0bK6r\xd03\x8dT\xd8" + + "\x9c\xa3+\xbc\x7f\xe3\xe7\xff\x813\x07\xca\xd3\xcd5N" + + "\x89}xA\xc7\x9e\xc6/\xe1\xcc\xcd\xd9\x9e\x17.-" + + "\x1a\xf8wYi\x83 {\x18\x137g\x9f\x17\x1f\xcc" + + "\xc6\xcb~?\xfb#\x06\xd6\xc2kg\x8f\xad\xbd\xf0\x8c" + + "U\x91\xc5\xb99M \xae\xcc\xc1,.\xcd\xe1\xa0_" + + "\x9fCY$2\x99\xb1\xd4\x96\x84)\xa5&\xd2_\xdc" + + "\x92\xc8\xa43+\xe3\xab\x87\xb3F,<\x9e\xd8j\x0c" + + "\x03h-\xdc\xc3\x98\x07\x00D\x00\xeecL\xf7\x00\x07" + + "]\x01\x09\"\x00* \x0f\xc1\x03\x8c\xe9u\xc8g!" + + "\x97$\x15$\x001\x13\x960\xa6+\xc8\xe7\"\xe7\\" + + "\x05\x0e >G\x1c\x7f\xeb\x0b\x90{<*x\x00\xc4" + + "<\xe2\xb3\x907#\xf7zU\xf0\x02\x88\x85\xc4\xe7\"" + + "oA\xee\xf3\xa9\xe0\x03\x10\x8b\x88/@\xde\x8a\\\x96" + + "U\x90\x01\xc4b\xe2\xcd\xc8\x97!\xf7\xfbU\xf0\x03\x88" + + "\xa5\xc4[\x90G\x91\x07\x02*\x04\x00D\x1b\xf1V\xe4" + + "\xdd \xc1\xa3[F\x13\xa9tl\x00\xfcL\x02?\x03" + + "\xcb\x1cY\x973c\xc9\xf9\xd5\x86\xc1pi\xfc\xc5" + + "\xa5\x89,\xfe\x1acZ\x0b\x07-\xea\xacKdp%" + + "cZ\x1f\x07mH\x02\xcb\xa4U\x1dO0\xbe\xd5\x00" + + "\xc5\xd1c\x06\xa00\xa6x\x99\xa7\xd7\xcc\xafIL\x8e" + + "B\x88I\x10b,\x02A\xd7\xfe\xe0\xce\xfd\x93\xc6\xc3" + + "\x89\xdc\x98\xd9\xaf\xd3\x84\xb2\xbdM@q4\xc0\x9er" + + "8\x08,P>\x89\xab\x88\x01}(\x95\xde\xc6\x8d\xec" + + "4\xea\xd8\x8eu\x8cq\xd0\xf2\x12XI\xbd\xac\x8e\xd2" + + "\xf9,\xde\x94\xb3@$\x10\xb4\xff\x98t\xd7\x9a\xdc\xcf" + + "t$\x96\x1eJ\x85\xd3\xdb\xaa\x12z\xa4FB=\x98" + + "P7\x07m\x00\x1f\xecH,\x8d)1:1\xa08" + + ":TH\x09\xa0p\xe3\xbb&\x03\xc5d\xc2\xb8\xc2\x15" + + "I41\xa65s\xd0\xfa\\I\xf4/aL[\xc5" + + "A\x1b\x91@\xde\x91JC=\x83a\x8e\x0bQ\x92L" + + "\x06P\x8f\xf7\x91\xfb\xa4\xf0\x8e\x89\x9c\xe9\x84\x94\x04\xa5" + + "\x142\x0cp\x97\xc5\x1e\xa8\\\xec{<\xf7\x9aK\x9e" + + "0\x13\xba)Od\x8d\x8a\xea\x1e\xa8\xf1\x88\xf7<\xc8" + + "\x98\xb6\x9b\x83v\x90\xd6\x1c7\x8b\x91\xc5\x03\xa88}" + + "\xdc\xbeu\x9f\xa4y\x82<\xd2\x1ft'\xc0\xad\xc9\xd4" + + "\xd6t\xc2\xcce\x19\x18\xf7\\\xfd\xf5\x89\xb1\x9c\xa1\x87" + + "\xcd\xea\xd4jm\xc7M\xb8\xfa#\x1c\xb4\xa4\x04\xd6\x8e" + + "\xf2\xedX\x12\xf5\xc2c\x09\x00\xf3\xdf{\xedk=o" + + "\xaa\x18\xb2\xf6\xd3\x9e^\xc9w\x9en}\xe5\xf2\xdd1" + + "\xcfZ\x8f\xc7>\xe9\xa5\x86\x10/5\x84\x1e\x09\x1bB" + + "\xb7\x84\xbeEB\xc1.4\x84~\xa9\x9d1}\x15\xf2" + + "5\xc8\xa1\xd0\x10\x06%l\x14\x03\xc8\x87%\x09\x10c" + + "?XK\xe1k\x10\xc7\xa5B\x9f\xc0~\xf0\x10\x85\xc7" + + "\x91o\x96\x0a}\x02\xfb\xc1&\xa9\x891}\x04y\x12" + + "\xb9\xcfk\xf7\x83\x84\xb4\x921}#\xf2Q\xe4\xb2\xcf" + + "\xee\x07\x06\xf1\xcd\xc8\xc7\x90\xfbe\xbb\x1f\xa4\x88'\x91" + + "g\x90\x07\xfcv?\x18'>\x8a\xdcD\x1e\x0c\xa8\x10" + + "\x04\x10\xdb\x89\x8f!\xcf#\x9f\x11Ta\x06\x80\xc8\x11" + + "\xcf \xdf\x8d\xbcn\x86\x0au\x00b\x17q\x13\xf9^" + + "\xe4\xa1:\x15B\x00b\x8f\x84\xfd&\x8f\xfc1\xe4\xf5" + + "!\x15\xea\x01\xc4>\xe2\xbb\x91\x1fD\x1e\xaeW!\x0c" + + " \x0e\x10\xdf\x8b\xfc0r%\xac\x82\x02 \x0e\x11\x7f" + + "\x0c\xf91\xe4\x11E\xc5]*\x8e\x10?\x88\xfc\x04\xf2" + + "\x86\x88\x0a\x0d\x00\xe28\xf1\xc3\xc8O\"\x17\x0d*\x08" + + "\x00\xf1\x04\xf1c\xc8O!W\x85\x8a\x0b)\x9e\"~" + + "\x02\xf9\x19\xa9\xba/\xce\xdf\x81\xc7\xe6n]r\xfe\xc4" + + "\xce\xb4\x91-\xdf\xf3\xa9\xc9\xc9\x9c\x91\xec7]a\xb2" + + "\x91\xcf\x14\x7f\xf7\xd2\xa4m\xe5\xc3\xf6\xf2aG\xf90" + + "Z>\xec,\x1fv\x95\x0f\x97\x7fj\x1d\xbc\xfaT\xc6" + + "\xed\xce1?6^:\x97w\xec\x1d\xd5}\xa2\xd7\xee" + + "Z\xd3\x10\xac\x18j\xe9\x1a\x0eZ\xbc\xd0\xaeP[\x18" + + "7\xb2\xa08\xaf:\x8e\xb2\x00DBA\xfb\xb6\xf0?" + + "\xc9\xa8]O\xafQ\xacG\xab+\xe55x\x9fcE" + + "\x9c\xbc\xb2N^\x05\x89\x88h\xdf`L\x1b\xe6\xa0m" + + "\xaca\xc4\xb6L\xa4's\xe3F\x92\xcd\x8f\xe7c\xc9" + + "|5\xef\x8dO\xaf\xdd\xf7\x9b\x13\xe3\xa9-a}g" + + "\"3\x8d\xe7\x97@\xc1\xdf\xc8A\x1b\x95\xc0J\x94\x0b" + + "\xfe\x1dM\xcft\x9d\xc7@\xb9\xb8\x8e\x94\xc4u\x03\x89" + + "kI\xfd\x8af{\x13\x89\xa5#~\x12\xd8\xdaj\x90" + + "X:b\xe6+\x88\xeb8M\xe3\x88\x19\x07[\\\xb7" + + "\x13w\xc4\xcc\xc3mq\xddE\xf38\xe2\xe4\x95lq" + + "\xddG\xf7u\xc4I\xf6\xd8\xe2z\x88\xe2\x1d\xb1\xf1{" + + "mq=N\xdc\x11\x95\x80\xcf\x16\xd7\xa7\x88\x9fD\xfe" + + "<\x89\xabl\x8b\xeb\xb3\xc4\xcf \xff\x1e\x89\xab\xdf\x16" + + "\xd7\x97\x88\x7f\x07\xf9OH\\\x03\xb6\xb8\xbeJ\xfc\x87" + + "\xc8\xcf\x92\xb8\x06mq}\x9d\xf8k\xc8\xdf&q\x9d" + + "a\x8b\xeb9\x12\xb3\xb3\xc8/\x90\xb8\xd6\xd9\xe2\xfa\x0b" + + "\xe2?G~\x89\xc45d\x8b\xebE\xe2o#\x7f\x97" + + "\xc4\xb5\xde\x16\xd7\xcb\xc4/ \xbfJ\xe2\x1a\xb6\xc5\xf5" + + "\x0a\xf1K\xc8\xaf\x93\xb8*\xb6\xb8^#\xfe.\xf2\xdf" + + "\x90\xb8Flq\xbdA\xfc*\xf2\xf7\x91\xcflPa" + + "&\x80\xb8I\xfc:\xf2?\xd6\x12\xddT:i\xe4\xef" + + ")\xa9\x8f&\x8d\xcc\xc4d\xca,\x8d\xb3\x89\x9d\xe8\xbf" + + "\xca/\x9c\xa6d\x17\xe6js\x85\x15Y{\x0d\xd6Q" + + "\x83Ek\xb0\xce\x1a\xac\xab\x06[\xfei\xbew\xd5P" + + "\xed\xd5\x15^\xaa\xc6\xabTM\x93Y~\xd0\x87J\x07" + + "\xdd\x8b'\xf1A\\\xf0\xba\xe2\x01\xa5\xb7m:p\x1e" + + "\xe4\x8a\xdbD\x85h\x83\xd7!\x9f\xe52Q3)\\" + + "A<\xb7x\x9e\xe9\xa5\x9aL\xc8,\xe4\xcdt\x9e\x0b" + + "&j!\xf1\xb9\xc8[\xdc&j\x11\xf1\x05\xc8[\xdd" + + "&j1\xf1f\xe4\xcb\xdc&j)\xf1\x16\xe4Q\xb7" + + "\x89j#\xde\x8a\xbc\xdbm\xa2:\x89/C\xbe\xcam" + + "\xa2V\xd0\xbe\x8f\"\xefs\x9b\xa8\x1e\xe2\x8e\xc7,\x9a" + + "\xa8~\xe2\x8e\xc7,\x9a\xa8A\xe2}\xc8\x87\xdc&*" + + "F\xbc\xe4=K&j-q\xc7|\x16M\x94F|" + + "\x08\xf9\x88\xdbD=D|\x18\xf9\xc6\xff\x97)\xfa\xec" + + "\x9a\x9e2w\xb0.g\xd2g\x0b\x85{\xea,\xcb\x83" + + "\xd6&\x81\xd6d3\x07mL\x82\x10\xdc\xb6T2<" + + ")\xec\xc2\xa3\x1c4S\x82\x90\xf4\x1fK\x05\x89\xb1\xc8" + + "v\xa4\x19\x0e\xdan\x09B\xfc\x96\xa5\x02g,\xb2\xab" + + "\x9d1\xcd\xe4\xa0\xed\xc5\x17Ez\xc5\x9c \xb7\xa28" + + "\x1fQ\xe9`\x82E\xcfB7'\x18\xcf\xe2\xbfK_" + + "N\x0b\xffN\x90)\xd0w2\x9e\xc8\x80\xe2|#\xb4" + + "\xff=\xdf\xcc\xaf6\xf0\xb2\xd2\xe7\xe9\xe2ew\xf5w" + + "C\xa9\xb4l\x7fT\xb8\xb7\xd9\xfao\x00\x00\x00\xff\xff" + + "Z\xbe\x9cC" func init() { schemas.Register(schema_b99093b7d2518300, + 0x828d564f51f7af4e, + 0x89c736f29fb5bda4, 0x8e703729a3de1278, 0x91989c51606be6c8, 0x958c34c871381d2c, @@ -1640,14 +2145,19 @@ func init() { 0xbb0225ef96e5ba9f, 0xc9c165c236a1bd53, 0xd4eb3c212b8dbb26, + 0xd53d449df9ef11fc, 0xf8c203f305398e1b, 0xfb4425cca53d7224, 0xff9ec84d90bcd521) } var x_b99093b7d2518300 = []byte{ - 0, 0, 0, 0, 13, 0, 0, 0, - 0, 0, 0, 0, 6, 0, 3, 0, + 0, 0, 0, 0, 17, 0, 0, 0, + 0, 0, 0, 0, 10, 0, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1660,10 +2170,14 @@ var x_b99093b7d2518300 = []byte{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, - 4, 0, 0, 0, 6, 0, 3, 0, - 49, 0, 0, 0, 10, 0, 0, 0, + 4, 0, 0, 0, 10, 0, 3, 0, + 65, 0, 0, 0, 10, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1677,8 +2191,12 @@ var x_b99093b7d2518300 = []byte{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 8, 0, 0, 0, - 0, 0, 0, 0, 5, 0, 1, 0, + 0, 0, 0, 0, 12, 0, 0, 0, + 0, 0, 0, 0, 9, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1686,8 +2204,12 @@ var x_b99093b7d2518300 = []byte{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 9, 0, 0, 0, - 0, 0, 0, 0, 6, 0, 1, 0, + 0, 0, 0, 0, 13, 0, 0, 0, + 0, 0, 0, 0, 10, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1696,6 +2218,13 @@ var x_b99093b7d2518300 = []byte{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1709,8 +2238,12 @@ var x_b99093b7d2518300 = []byte{ 1, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 13, 0, 0, 0, - 0, 0, 0, 0, 6, 0, 3, 0, + 0, 0, 0, 0, 17, 0, 0, 0, + 0, 0, 0, 0, 10, 0, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1723,8 +2256,12 @@ var x_b99093b7d2518300 = []byte{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 13, 0, 0, 0, - 0, 0, 0, 0, 6, 0, 3, 0, + 0, 0, 0, 0, 17, 0, 0, 0, + 0, 0, 0, 0, 10, 0, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1737,10 +2274,14 @@ var x_b99093b7d2518300 = []byte{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, - 4, 0, 0, 0, 6, 0, 3, 0, - 49, 0, 0, 0, 10, 0, 0, 0, + 4, 0, 0, 0, 10, 0, 3, 0, + 65, 0, 0, 0, 10, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1754,10 +2295,14 @@ var x_b99093b7d2518300 = []byte{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, - 4, 0, 0, 0, 6, 0, 3, 0, - 49, 0, 0, 0, 10, 0, 0, 0, + 4, 0, 0, 0, 10, 0, 3, 0, + 65, 0, 0, 0, 10, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1771,8 +2316,12 @@ var x_b99093b7d2518300 = []byte{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 8, 0, 0, 0, - 0, 0, 0, 0, 5, 0, 1, 0, + 0, 0, 0, 0, 12, 0, 0, 0, + 0, 0, 0, 0, 9, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1780,8 +2329,12 @@ var x_b99093b7d2518300 = []byte{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 8, 0, 0, 0, - 0, 0, 0, 0, 5, 0, 1, 0, + 0, 0, 0, 0, 12, 0, 0, 0, + 0, 0, 0, 0, 9, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1789,8 +2342,12 @@ var x_b99093b7d2518300 = []byte{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 9, 0, 0, 0, - 0, 0, 0, 0, 6, 0, 1, 0, + 0, 0, 0, 0, 13, 0, 0, 0, + 0, 0, 0, 0, 10, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1799,8 +2356,12 @@ var x_b99093b7d2518300 = []byte{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 9, 0, 0, 0, - 0, 0, 0, 0, 6, 0, 1, 0, + 0, 0, 0, 0, 13, 0, 0, 0, + 0, 0, 0, 0, 10, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1809,6 +2370,20 @@ var x_b99093b7d2518300 = []byte{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, diff --git a/application/objs/capn/gen.go b/application/objs/capn/gen.go index 4e6fc27c..914155d9 100644 --- a/application/objs/capn/gen.go +++ b/application/objs/capn/gen.go @@ -7,4 +7,4 @@ import ( // Import check to ensure capnp is installed. var _ = capnp.Tag -//go:generate capnp compile -I /home/et3p/go/src/zombiezen.com/go/capnproto2/std -ogo application.capnp +//go:generate capnp compile -I $GOPATH/src/zombiezen.com/go/capnproto2/std -ogo application.capnp diff --git a/application/objs/constants.go b/application/objs/constants.go index deead08a..63e39031 100644 --- a/application/objs/constants.go +++ b/application/objs/constants.go @@ -18,6 +18,8 @@ const ( DataStoreSVA ) +// SignerRole is the defined type utilized for designation for signers +// in AtomicSwap objects type SignerRole uint8 const ( diff --git a/application/objs/ds.go b/application/objs/ds.go index 8d5d0d32..a5690e08 100644 --- a/application/objs/ds.go +++ b/application/objs/ds.go @@ -4,6 +4,7 @@ import ( mdefs "github.com/MadBase/MadNet/application/objs/capn" "github.com/MadBase/MadNet/application/objs/datastore" "github.com/MadBase/MadNet/application/objs/uint256" + "github.com/MadBase/MadNet/application/wrapper" "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/errorz" "github.com/MadBase/MadNet/utils" @@ -207,6 +208,14 @@ func (b *DataStore) GenericOwner() (*Owner, error) { return onr, nil } +// IsExpired returns true if the datastore is free for garbage collection +func (b *DataStore) IsExpired(currentHeight uint32) (bool, error) { + if b == nil { + return false, errorz.ErrInvalid{}.New("not initialized") + } + return b.DSLinker.IsExpired(currentHeight) +} + // EpochOfExpiration returns the epoch in which the datastore may be garbage // collected func (b *DataStore) EpochOfExpiration() (uint32, error) { @@ -232,6 +241,86 @@ func (b *DataStore) Value() (*uint256.Uint256, error) { return b.DSLinker.Value() } +// Fee returns the fee stored in the object at the time of creation +func (b *DataStore) Fee() (*uint256.Uint256, error) { + if b == nil { + return nil, errorz.ErrInvalid{}.New("not initialized") + } + return b.DSLinker.Fee() +} + +// ValuePlusFee returns the Value of the object with the associated fee +// +// Given a DataStore with data of size dataSize bytes which are to be stored +// for of numEpochs, the value is +// +// value := (dataSize + BaseDatasizeConst) * (numEpochs + 2) +// +// Here, BaseDatasizeConst is a constant which includes the base cost of the +// actual storage object. Furthermore, we include 2 additional epochs into +// the standard cost for initial burning as well as miner reward. +// +// Given the base cost, we also want to be able to include additional fees. +// These fees would be on a per-epoch basis. Thus, we have the form +// +// valuePlusFee := (dataSize + BaseDatasizeConst + perEpochFee) * (numEpochs + 2) +// = (dataSize + BaseDatasizeConst) * (numEpochs + 2) +// + perEpochFee * (numEpochs + 2) +// = value + fee +// +// with +// +// fee := perEpochFee * (numEpochs + 2) +// +// The fee is burned at creation. +func (b *DataStore) ValuePlusFee() (*uint256.Uint256, error) { + value, err := b.Value() + if err != nil { + return nil, err + } + fee, err := b.Fee() + if err != nil { + return nil, err + } + total, err := new(uint256.Uint256).Add(value, fee) + if err != nil { + return nil, err + } + return total, nil +} + +// ValidateFee validates the fee of the datastore at the time of creation +func (b *DataStore) ValidateFee(storage *wrapper.Storage) error { + // Get Fee + fee, err := b.Fee() + if err != nil { + return err + } + // Compute correct fee value + value, err := b.Value() + if err != nil { + return err + } + perEpochFee, err := storage.GetDataStoreEpochFee() + if err != nil { + return err + } + dataSize := uint32(len(b.DSLinker.DSPreImage.RawData)) + numEpochs32, err := NumEpochsEquation(dataSize, value) + if err != nil { + return err + } + totalEpochs, _ := new(uint256.Uint256).FromUint64(uint64(numEpochs32) + 2) + feeTrue, err := new(uint256.Uint256).Mul(perEpochFee, totalEpochs) + if err != nil { + return err + } + if fee.Cmp(feeTrue) != 0 { + return errorz.ErrInvalid{}.New("invalid fee") + } + return nil +} + // ValidatePreSignature validates the signature of the datastore at the time of // creation func (b *DataStore) ValidatePreSignature() error { diff --git a/application/objs/ds_test.go b/application/objs/ds_test.go index 2cf17450..05e67873 100644 --- a/application/objs/ds_test.go +++ b/application/objs/ds_test.go @@ -2,6 +2,7 @@ package objs import ( "bytes" + "math/big" "testing" "github.com/MadBase/MadNet/application/objs/uint256" @@ -50,6 +51,7 @@ func makeDataStoreGood(secpPrivk []byte) *DataStore { RawData: rawdata, TXOutIdx: txOutIdx, Owner: owner, + Fee: new(uint256.Uint256).SetZero(), } dsl := &DSLinker{ DSPreImage: dsp, @@ -93,6 +95,7 @@ func TestDataStoreGood(t *testing.T) { RawData: rawdata, TXOutIdx: txoid, Owner: owner, + Fee: new(uint256.Uint256).SetZero(), } txHash := make([]byte, constants.HashLen) dsl := &DSLinker{ @@ -206,6 +209,7 @@ func TestDataStoreBad2(t *testing.T) { RawData: rawdata, TXOutIdx: txoid, Owner: owner, + Fee: new(uint256.Uint256).SetZero(), } txHash := make([]byte, constants.HashLen) dsl := &DSLinker{ @@ -257,6 +261,7 @@ func TestOwnerSig(t *testing.T) { RawData: rawdata, TXOutIdx: txoid, Owner: owner, + Fee: new(uint256.Uint256).SetZero(), } txHash := make([]byte, constants.HashLen) dsl := &DSLinker{ @@ -319,7 +324,10 @@ func TestOwnerSig(t *testing.T) { { bnsigner := &crypto.BNSigner{} - bnsigner.SetPrivk(crypto.Hasher([]byte("d"))) + err := bnsigner.SetPrivk(crypto.Hasher([]byte("d"))) + if err != nil { + t.Fatal(err) + } txIn, err := ds2.MakeTxIn() if err != nil { t.Fatal(err) @@ -349,7 +357,10 @@ func TestOwnerSig2(t *testing.T) { } ownerSigner := &crypto.BNSigner{} - ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))) + err = ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))) + if err != nil { + t.Fatal(err) + } ownerPubk, err := ownerSigner.Pubkey() if err != nil { @@ -367,6 +378,7 @@ func TestOwnerSig2(t *testing.T) { RawData: rawdata, TXOutIdx: txoid, Owner: owner, + Fee: new(uint256.Uint256).SetZero(), } txHash := make([]byte, constants.HashLen) dsl := &DSLinker{ @@ -429,7 +441,10 @@ func TestOwnerSig2(t *testing.T) { { bnsigner := &crypto.BNSigner{} - bnsigner.SetPrivk(crypto.Hasher([]byte("d"))) + err := bnsigner.SetPrivk(crypto.Hasher([]byte("d"))) + if err != nil { + t.Fatal(err) + } txIn, err := ds2.MakeTxIn() if err != nil { t.Fatal(err) @@ -460,7 +475,10 @@ func TestDeposit(t *testing.T) { } ownerSigner := &crypto.BNSigner{} - ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))) + err = ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))) + if err != nil { + t.Fatal(err) + } ownerPubk, err := ownerSigner.Pubkey() if err != nil { @@ -478,6 +496,7 @@ func TestDeposit(t *testing.T) { RawData: rawdata, TXOutIdx: txoid, Owner: owner, + Fee: new(uint256.Uint256).SetZero(), } txHash := make([]byte, constants.HashLen) dsl := &DSLinker{ @@ -820,6 +839,147 @@ func TestDSValueCall(t *testing.T) { if err == nil { t.Fatal("Should have raised an error (2)") } + + // Prep DataStore + numEpochs := uint32(3) + dataSize := uint32(1) + data := make([]byte, int(dataSize)) + ds.DSLinker = &DSLinker{} + ds.DSLinker.DSPreImage = &DSPreImage{} + ds.DSLinker.DSPreImage.RawData = data + deposit32 := (constants.BaseDatasizeConst + dataSize) * (numEpochs + 2) + deposit, err := new(uint256.Uint256).FromUint64(uint64(deposit32)) + if err != nil { + t.Fatal(err) + } + ds.DSLinker.DSPreImage.Deposit = deposit + + // Check value and deposit agree + value, err := ds.Value() + if err != nil { + t.Fatal(err) + } + if value.Cmp(deposit) != 0 { + t.Fatal("true value and deposit do not agree") + } +} + +func TestDSValuePlusFeeCallGood(t *testing.T) { + // Test for failures due to not being initialized + utxo := &TXOut{} + _, err := utxo.dataStore.ValuePlusFee() + if err == nil { + t.Fatal("Should have raised an error (1)") + } + ds := &DataStore{} + _, err = ds.ValuePlusFee() + if err == nil { + t.Fatal("Should have raised an error (2)") + } + + // Prep DataStore + numEpochs := uint32(3) + dataSize := uint32(1) + data := make([]byte, int(dataSize)) + ds.DSLinker = &DSLinker{} + ds.DSLinker.DSPreImage = &DSPreImage{} + ds.DSLinker.DSPreImage.RawData = data + deposit32 := (constants.BaseDatasizeConst + dataSize) * (numEpochs + 2) + deposit, err := new(uint256.Uint256).FromUint64(uint64(deposit32)) + if err != nil { + t.Fatal(err) + } + ds.DSLinker.DSPreImage.Deposit = deposit + ds.DSLinker.DSPreImage.Fee = new(uint256.Uint256) + + // Check value and valuePlusFee agree with fee == 0 + value, err := ds.Value() + if err != nil { + t.Fatal(err) + } + valuePlusFee, err := ds.ValuePlusFee() + if err != nil { + t.Fatal(err) + } + if value.Cmp(valuePlusFee) != 0 { + t.Fatal("true value and valuePlusFee do not agree (1)") + } + + // Prep for 1000 fee + perEpochFee := uint32(1000) + + fee32 := perEpochFee * (numEpochs + 2) + fee, err := new(uint256.Uint256).FromUint64(uint64(fee32)) + if err != nil { + t.Fatal(err) + } + ds.DSLinker.DSPreImage.Fee = fee.Clone() + + // Check value and valuePlusFee agree with fee != 0 + valuePlusFee, err = ds.ValuePlusFee() + if err != nil { + t.Fatal(err) + } + vpfTrue, err := new(uint256.Uint256).Add(value, fee) + if err != nil { + t.Fatal(err) + } + if vpfTrue.Cmp(valuePlusFee) != 0 { + t.Fatal("true value and valuePlusFee do not agree (2)") + } + if value.Eq(valuePlusFee) { + t.Fatal("value and valuePlusFee should not be equal") + } +} + +func TestDSValuePlusFeeCallBad1(t *testing.T) { + // Test for failures due to not being initialized + utxo := &TXOut{} + _, err := utxo.dataStore.ValuePlusFee() + if err == nil { + t.Fatal("Should have raised an error (1)") + } + ds := &DataStore{} + _, err = ds.ValuePlusFee() + if err == nil { + t.Fatal("Should have raised an error (2)") + } +} + +func TestDSValuePlusFeeCallBad2(t *testing.T) { + // Test for failure due to large of values + dataSize32 := constants.MaxDataStoreSize + numEpochs32 := constants.MaxUint32 + deposit64 := (uint64(constants.BaseDatasizeConst) + uint64(dataSize32)) * (2 + uint64(numEpochs32)) + deposit, err := new(uint256.Uint256).FromUint64(deposit64) + if err != nil { + t.Fatal(err) + } + ds := &DataStore{} + ds.DSLinker = &DSLinker{} + ds.DSLinker.DSPreImage = &DSPreImage{} + ds.DSLinker.DSPreImage.RawData = make([]byte, dataSize32) + ds.DSLinker.DSPreImage.Deposit = deposit + + _, err = ds.ValuePlusFee() + if err == nil { + t.Fatal("Should have raised an error") + } +} + +func TestDSValuePlusFeeCallBad3(t *testing.T) { + // Test for failure due to invalid Deposit + dataSize32 := uint32(1) + ds := &DataStore{} + ds.DSLinker = &DSLinker{} + ds.DSLinker.DSPreImage = &DSPreImage{} + ds.DSLinker.DSPreImage.RawData = make([]byte, dataSize32) + ds.DSLinker.DSPreImage.Deposit = new(uint256.Uint256).SetOne() + + _, err := ds.ValuePlusFee() + if err == nil { + t.Fatal("Should have raised an error") + } } func TestDSValidatePreSignature(t *testing.T) { @@ -943,3 +1103,80 @@ func TestDSMakeTxIn(t *testing.T) { t.Fatal("Should have raised an error (4)") } } + +func TestDSIsExpired(t *testing.T) { + currentHeight := uint32(1) + utxo := &TXOut{} + _, err := utxo.dataStore.IsExpired(currentHeight) + if err == nil { + t.Fatal("Should have raised an error (1)") + } + + ds := &DataStore{} + _, err = ds.IsExpired(currentHeight) + if err == nil { + t.Fatal("Should have raised an error (2)") + } +} + +func TestDSValidateFee(t *testing.T) { + msg := makeMockStorageGetter() + storage := makeStorage(msg) + + utxo := &TXOut{} + err := utxo.dataStore.ValidateFee(storage) + if err == nil { + t.Fatal("Should have raised an error (1)") + } + + ds := &DataStore{} + err = ds.ValidateFee(storage) + if err == nil { + t.Fatal("Should have raised an error (2)") + } + + ds.DSLinker = &DSLinker{} + ds.DSLinker.DSPreImage = &DSPreImage{} + ds.DSLinker.DSPreImage.RawData = make([]byte, 0) + ds.DSLinker.DSPreImage.Fee = new(uint256.Uint256).SetZero() + err = ds.ValidateFee(storage) + if err == nil { + t.Fatal("Should have raised an error (3)") + } + + // Store 1 byte for 1 epoch + rawData := make([]byte, 1) + numEpochs := uint32(1) + ds.DSLinker.DSPreImage.RawData = rawData + deposit32 := (constants.BaseDatasizeConst + uint32(len(rawData))) * (numEpochs + 2) + deposit, err := new(uint256.Uint256).FromUint64(uint64(deposit32)) + if err != nil { + t.Fatal(err) + } + ds.DSLinker.DSPreImage.Deposit = deposit + err = ds.ValidateFee(storage) + if err != nil { + t.Fatal(err) + } + + // Set perEpochFee to 1, raising an error + perEpochFee32 := uint32(1) + msg.SetDataStoreEpochFee(big.NewInt(int64(perEpochFee32))) + storage = makeStorage(msg) + err = ds.ValidateFee(storage) + if err == nil { + t.Fatal("Should have raised an error (4)") + } + + // Correct Fee value + fee32 := (perEpochFee32) * (numEpochs + 2) + fee, err := new(uint256.Uint256).FromUint64(uint64(fee32)) + if err != nil { + t.Fatal(err) + } + ds.DSLinker.DSPreImage.Fee = fee + err = ds.ValidateFee(storage) + if err != nil { + t.Fatal(err) + } +} diff --git a/application/objs/dsl.go b/application/objs/dsl.go index ac5ec7c9..2f4771ad 100644 --- a/application/objs/dsl.go +++ b/application/objs/dsl.go @@ -169,6 +169,14 @@ func (b *DSLinker) SetTXOutIdx(idx uint32) error { return nil } +// IsExpired returns true if the datastore is free for garbage collection +func (b *DSLinker) IsExpired(currentHeight uint32) (bool, error) { + if b == nil { + return false, errorz.ErrInvalid{}.New("not initialized") + } + return b.DSPreImage.IsExpired(currentHeight) +} + // EpochOfExpiration returns the epoch in which the datastore may be garbage // collected func (b *DSLinker) EpochOfExpiration() (uint32, error) { @@ -194,6 +202,14 @@ func (b *DSLinker) Value() (*uint256.Uint256, error) { return b.DSPreImage.Value() } +// Fee returns the fee stored in the object at the time of creation +func (b *DSLinker) Fee() (*uint256.Uint256, error) { + if b == nil || b.DSPreImage == nil || b.DSPreImage.Fee == nil { + return nil, errorz.ErrInvalid{}.New("not initialized") + } + return b.DSPreImage.Fee.Clone(), nil +} + // ValidateSignature validates the signature of the datastore at the time of // consumption func (b *DSLinker) ValidateSignature(currentHeight uint32, msg []byte, sig *DataStoreSignature) error { diff --git a/application/objs/dsl_test.go b/application/objs/dsl_test.go index c6dc4898..64d24aaf 100644 --- a/application/objs/dsl_test.go +++ b/application/objs/dsl_test.go @@ -42,6 +42,7 @@ func TestDSLinkerGood(t *testing.T) { RawData: rawdata, TXOutIdx: txoid, Owner: owner, + Fee: new(uint256.Uint256).SetZero(), } txHash := make([]byte, constants.HashLen) dsl := &DSLinker{ @@ -145,6 +146,7 @@ func TestDSLinkerBad2(t *testing.T) { RawData: rawdata, TXOutIdx: txoid, Owner: owner, + Fee: new(uint256.Uint256).SetZero(), } txHash := make([]byte, 31) // Invalid TxHash dsl := &DSLinker{ @@ -397,6 +399,20 @@ func TestDSLinkerSetTXOutIdx(t *testing.T) { } } +func TestDSLinkerIsExpired(t *testing.T) { + ds := &DataStore{} + currentHeight := uint32(1) + _, err := ds.DSLinker.IsExpired(currentHeight) + if err == nil { + t.Fatal("Should have raised error (1)") + } + dsl := &DSLinker{} + _, err = dsl.IsExpired(currentHeight) + if err == nil { + t.Fatal("Should have raised error (2)") + } +} + func TestDSLinkerEpochOfExpiration(t *testing.T) { ds := &DataStore{} _, err := ds.DSLinker.EpochOfExpiration() diff --git a/application/objs/dsowner_test.go b/application/objs/dsowner_test.go index 6eff09c8..73a4d827 100644 --- a/application/objs/dsowner_test.go +++ b/application/objs/dsowner_test.go @@ -264,7 +264,10 @@ func TestDSOwnerValidateSignatureBN(t *testing.T) { privk := make([]byte, 32) privk[0] = 1 privk[31] = 1 - signer.SetPrivk(privk) + err = signer.SetPrivk(privk) + if err != nil { + t.Fatal(err) + } pk, err := signer.Pubkey() if err != nil { t.Fatal(err) diff --git a/application/objs/dspi.go b/application/objs/dspi.go index 633a122f..c511fb6d 100644 --- a/application/objs/dspi.go +++ b/application/objs/dspi.go @@ -20,6 +20,7 @@ type DSPreImage struct { RawData []byte TXOutIdx uint32 Owner *DataStoreOwner + Fee *uint256.Uint256 } // UnmarshalBinary takes a byte slice and returns the corresponding @@ -75,6 +76,20 @@ func (b *DSPreImage) UnmarshalCapn(bc mdefs.DSPreImage) error { return err } b.Owner = owner + fObj := &uint256.Uint256{} + u32array[0] = bc.Fee0() + u32array[1] = bc.Fee1() + u32array[2] = bc.Fee2() + u32array[3] = bc.Fee3() + u32array[4] = bc.Fee4() + u32array[5] = bc.Fee5() + u32array[6] = bc.Fee6() + u32array[7] = bc.Fee7() + err = fObj.FromUint32Array(u32array) + if err != nil { + return err + } + b.Fee = fObj // protects against zero bytes errors in equations return b.ValidateDeposit() } @@ -132,6 +147,18 @@ func (b *DSPreImage) MarshalCapn(seg *capnp.Segment) (mdefs.DSPreImage, error) { bc.SetDeposit5(u32array[5]) bc.SetDeposit6(u32array[6]) bc.SetDeposit7(u32array[7]) + u32array, err = b.Fee.ToUint32Array() + if err != nil { + return bc, err + } + bc.SetFee0(u32array[0]) + bc.SetFee1(u32array[1]) + bc.SetFee2(u32array[2]) + bc.SetFee3(u32array[3]) + bc.SetFee4(u32array[4]) + bc.SetFee5(u32array[5]) + bc.SetFee6(u32array[6]) + bc.SetFee7(u32array[7]) bc.SetTXOutIdx(b.TXOutIdx) return bc, nil } @@ -165,12 +192,12 @@ func (b *DSPreImage) RemainingValue(currentHeight uint32) (*uint256.Uint256, err if err != nil { return nil, err } - return result.Clone(), nil + return result, nil } // Value returns the value stored in the object at the time of creation func (b *DSPreImage) Value() (*uint256.Uint256, error) { - if b == nil || b.Deposit == nil || b.Deposit.Eq(uint256.Zero()) { + if b == nil || b.Deposit == nil || b.Deposit.IsZero() { return nil, errorz.ErrInvalid{}.New("not initialized") } return b.Deposit.Clone(), nil @@ -216,7 +243,7 @@ func (b *DSPreImage) IsExpired(currentHeight uint32) (bool, error) { // EpochOfExpiration returns the epoch in which the datastore may be garbage // collected func (b *DSPreImage) EpochOfExpiration() (uint32, error) { - if b == nil || b.Deposit == nil || b.Deposit.Eq(uint256.Zero()) || len(b.RawData) == 0 { + if b == nil || b.Deposit == nil || b.Deposit.IsZero() || len(b.RawData) == 0 { return 0, errorz.ErrInvalid{}.New("not initialized") } dataSize := uint32(len(b.RawData)) @@ -230,7 +257,7 @@ func (b *DSPreImage) EpochOfExpiration() (uint32, error) { // ValidateDeposit validates the deposit func (b *DSPreImage) ValidateDeposit() error { - if b == nil || b.Deposit == nil { + if b == nil || b.Deposit == nil || b.Deposit.IsZero() || b.Fee == nil { return errorz.ErrInvalid{}.New("not initialized") } if b.ChainID == 0 { @@ -282,14 +309,8 @@ func RewardDepositEquation(depositOrig *uint256.Uint256, dataSize32 uint32, epoc // This ensures // epochDiff == epochFinal - epochInitial >= 0 epochDiff := epochFinal - epochInitial - dataSize, err := new(uint256.Uint256).FromUint64(uint64(dataSize32)) - if err != nil { - return nil, err - } - epochCost, err := new(uint256.Uint256).Add(uint256.BaseDatasizeConst(), dataSize) - if err != nil { - return nil, err - } + dataSize, _ := new(uint256.Uint256).FromUint64(uint64(dataSize32)) + epochCost, _ := new(uint256.Uint256).Add(uint256.BaseDatasizeConst(), dataSize) numEpochs, err := NumEpochsEquation(dataSize32, depositClone) if err != nil { return nil, err @@ -306,10 +327,7 @@ func RewardDepositEquation(depositOrig *uint256.Uint256, dataSize32 uint32, epoc if err != nil { return nil, err } - tmp3, err := new(uint256.Uint256).Mul(uint256.Two(), epochCost) - if err != nil { - return nil, err - } + tmp3, _ := new(uint256.Uint256).Mul(uint256.Two(), epochCost) remainder, err := new(uint256.Uint256).Add(tmp, tmp3) if err != nil { return nil, err @@ -361,37 +379,16 @@ func BaseDepositEquation(dataSize32 uint32, numEpochs32 uint32) (*uint256.Uint25 // dataSize is too large so we do not perform any checks return nil, errorz.ErrInvalid{}.New("Error in BaseDepositEquation: dataSize is too large") } - dataSize, err := new(uint256.Uint256).FromUint64(uint64(dataSize32)) - if err != nil { - return nil, err - } + dataSize, _ := new(uint256.Uint256).FromUint64(uint64(dataSize32)) // tmp1 < 2^31 - epochCost, err := new(uint256.Uint256).Add(dataSize, uint256.BaseDatasizeConst()) - if err != nil { - return nil, err - } + epochCost, _ := new(uint256.Uint256).Add(dataSize, uint256.BaseDatasizeConst()) // We have // tmp2 < 2^33 - numEpochs, err := new(uint256.Uint256).FromUint64(uint64(numEpochs32)) - if err != nil { - return nil, err - } - totalEpochs, err := new(uint256.Uint256).Add(uint256.Two(), numEpochs) - if err != nil { - return nil, err - } + numEpochs, _ := new(uint256.Uint256).FromUint64(uint64(numEpochs32)) + totalEpochs, _ := new(uint256.Uint256).Add(uint256.Two(), numEpochs) // The above ensures no overflow occurs in the following multiplication, as // deposit == tmp1*tmp2 < 2^64 - depositUint256, err := new(uint256.Uint256).Mul(epochCost, totalEpochs) - if err != nil { - return nil, err - } - //if depositUint256.Gt(constants.Uint256MaxUint32()) { - // // deposit cannot be represented by uint32 value - // return nil, errorz.ErrInvalid{}.New("Error in BaseDepositEquation: required deposit is too large to be uint32") - //} - // The above check ensures this conversion succeeds - // deposit := uint32(depositUint64) + depositUint256, _ := new(uint256.Uint256).Mul(epochCost, totalEpochs) return depositUint256, nil } @@ -402,8 +399,7 @@ func BaseDepositEquation(dataSize32 uint32, numEpochs32 uint32) (*uint256.Uint25 // numEpochs = (deposit / (dataSize + BaseDatasizeConst)) - 2 // // We have additional checks to ensure there is no integer overflow. -func NumEpochsEquation(dataSize32 uint32, depositOrig *uint256.Uint256) (uint32, error) { - depositClone := depositOrig.Clone() +func NumEpochsEquation(dataSize32 uint32, deposit *uint256.Uint256) (uint32, error) { if dataSize32 > constants.MaxDataStoreSize { return 0, errorz.ErrInvalid{}.New("Error in NumEpochsEquation: dataSize is too large") } @@ -416,15 +412,9 @@ func NumEpochsEquation(dataSize32 uint32, depositOrig *uint256.Uint256) (uint32, // Unsigned integer arithmetic ensures // // tmp >= 0 - dataSize, err := new(uint256.Uint256).FromUint64(uint64(dataSize32)) - if err != nil { - return 0, err - } - totalDataSize, err := new(uint256.Uint256).Add(dataSize, uint256.BaseDatasizeConst()) - if err != nil { - return 0, err - } - tmp, err := new(uint256.Uint256).Div(depositClone, totalDataSize) + dataSize, _ := new(uint256.Uint256).FromUint64(uint64(dataSize32)) + totalDataSize, _ := new(uint256.Uint256).Add(dataSize, uint256.BaseDatasizeConst()) + tmp, err := new(uint256.Uint256).Div(deposit, totalDataSize) if err != nil { return 0, err } @@ -432,10 +422,7 @@ func NumEpochsEquation(dataSize32 uint32, depositOrig *uint256.Uint256) (uint32, return 0, errorz.ErrInvalid{}.New("Error in NumEpochsEquation: invalid dataSize and deposit causing integer overflow") } // The above check ensures there is no integer overflow in this subtraction - numEpochs, err := new(uint256.Uint256).Sub(tmp, uint256.Two()) - if err != nil { - return 0, err - } + numEpochs, _ := new(uint256.Uint256).Sub(tmp, uint256.Two()) numEpochs32, err := numEpochs.ToUint32() if err != nil { return 0, err diff --git a/application/objs/dspi_test.go b/application/objs/dspi_test.go index f4f7c956..4f970d90 100644 --- a/application/objs/dspi_test.go +++ b/application/objs/dspi_test.go @@ -41,6 +41,7 @@ func TestDSPreImageGood(t *testing.T) { RawData: rawdata, TXOutIdx: txoid, Owner: owner, + Fee: new(uint256.Uint256).SetZero(), } dsp2 := &DSPreImage{} dspBytes, err := dsp.MarshalBinary() @@ -310,6 +311,7 @@ func TestDSOwnerSig(t *testing.T) { RawData: rawdata, TXOutIdx: txoid, Owner: owner, + Fee: new(uint256.Uint256).SetZero(), } _, err = dsp.MarshalBinary() if err != nil { @@ -374,6 +376,7 @@ func TestDSPreImagePreHash(t *testing.T) { dsp.RawData = rawData dsp.TXOutIdx = txOutIdx dsp.Owner = dso + dsp.Fee = new(uint256.Uint256).SetZero() _, err = dsp.PreHash() if err != nil { @@ -792,10 +795,17 @@ func TestDSPreImageValidateDeposit(t *testing.T) { dsp.Deposit = deposit err = dsp.ValidateDeposit() if err == nil { - // Fails because dsp.Owner == nil + // Fails because dsp.Fee == nil t.Fatal("Should raise an error (7)") } + dsp.Fee = new(uint256.Uint256) + err = dsp.ValidateDeposit() + if err == nil { + // Fails because dsp.Owner == nil + t.Fatal("Should raise an error (8)") + } + dso := &DataStoreOwner{} curveSpec := constants.CurveSecp256k1 acct := make([]byte, constants.OwnerLen) diff --git a/application/objs/mockstorage_test.go b/application/objs/mockstorage_test.go new file mode 100644 index 00000000..1178ffb6 --- /dev/null +++ b/application/objs/mockstorage_test.go @@ -0,0 +1,145 @@ +package objs + +import ( + "math/big" + "time" + + "github.com/MadBase/MadNet/application/wrapper" + "github.com/MadBase/MadNet/dynamics" + "github.com/dgraph-io/badger/v2" +) + +func makeMockStorageGetter() *mockStorageGetter { + maxBytes := uint32(0) + dataStoreEpochFee := new(big.Int) + atomicSwapFee := new(big.Int) + valueStoreFee := new(big.Int) + minTxFee := new(big.Int) + + msg := &mockStorageGetter{ + maxBytes: maxBytes, + dataStoreEpochFee: dataStoreEpochFee, + valueStoreFee: valueStoreFee, + atomicSwapFee: atomicSwapFee, + minTxFee: minTxFee, + } + return msg +} + +func makeStorage(msg dynamics.StorageGetter) *wrapper.Storage { + storage := wrapper.NewStorage(msg) + return storage +} + +type mockStorageGetter struct { + maxBytes uint32 + dataStoreEpochFee *big.Int + valueStoreFee *big.Int + atomicSwapFee *big.Int + minTxFee *big.Int + maxTxVectorLength int +} + +func (msg *mockStorageGetter) GetMaxBytes() uint32 { + return msg.maxBytes +} + +func (msg *mockStorageGetter) SetMaxBytes(value uint32) { + msg.maxBytes = value +} + +func (msg *mockStorageGetter) GetMaxProposalSize() uint32 { + return msg.maxBytes +} + +func (msg *mockStorageGetter) GetProposalStepTimeout() time.Duration { + return time.Duration(0) +} +func (msg *mockStorageGetter) GetPreVoteStepTimeout() time.Duration { + return time.Duration(0) +} +func (msg *mockStorageGetter) GetPreCommitStepTimeout() time.Duration { + return time.Duration(0) +} +func (msg *mockStorageGetter) GetDeadBlockRoundNextRoundTimeout() time.Duration { + return time.Duration(0) +} +func (msg *mockStorageGetter) GetDownloadTimeout() time.Duration { + return time.Duration(0) +} +func (msg *mockStorageGetter) GetSrvrMsgTimeout() time.Duration { + return time.Duration(0) +} +func (msg *mockStorageGetter) GetMsgTimeout() time.Duration { + return time.Duration(0) +} +func (msg *mockStorageGetter) GetMaxTxVectorLength() int { + return 128 +} + +func (msg *mockStorageGetter) UpdateStorage(txn *badger.Txn, update dynamics.Updater) error { + return nil +} +func (msg *mockStorageGetter) LoadStorage(txn *badger.Txn, epoch uint32) error { + return nil +} + +func (msg *mockStorageGetter) GetDataStoreEpochFee() *big.Int { + return msg.dataStoreEpochFee +} + +func (msg *mockStorageGetter) SetDataStoreEpochFee(value *big.Int) { + if value == nil { + panic("invalid value") + } + msg.dataStoreEpochFee.Set(value) +} + +func (msg *mockStorageGetter) GetDataStoreValidVersion() uint32 { + return 0 +} + +func (msg *mockStorageGetter) GetValueStoreFee() *big.Int { + return msg.valueStoreFee +} + +func (msg *mockStorageGetter) SetValueStoreFee(value *big.Int) { + if value == nil { + panic("invalid value") + } + msg.valueStoreFee.Set(value) +} + +func (msg *mockStorageGetter) GetValueStoreValidVersion() uint32 { + return 0 +} + +func (msg *mockStorageGetter) GetAtomicSwapFee() *big.Int { + return msg.atomicSwapFee +} + +func (msg *mockStorageGetter) SetAtomicSwapFee(value *big.Int) { + if value == nil { + panic("invalid value") + } + msg.atomicSwapFee.Set(value) +} + +func (msg *mockStorageGetter) GetAtomicSwapValidStopEpoch() uint32 { + return 0 +} + +func (msg *mockStorageGetter) GetMinTxFee() *big.Int { + return msg.minTxFee +} + +func (msg *mockStorageGetter) SetMinTxFee(value *big.Int) { + if value == nil { + panic("invalid value") + } + msg.minTxFee.Set(value) +} + +func (msg *mockStorageGetter) GetTxValidVersion() uint32 { + return 0 +} diff --git a/application/objs/tf.go b/application/objs/tf.go new file mode 100644 index 00000000..d8695432 --- /dev/null +++ b/application/objs/tf.go @@ -0,0 +1,176 @@ +package objs + +import ( + mdefs "github.com/MadBase/MadNet/application/objs/capn" + "github.com/MadBase/MadNet/application/objs/txfee" + "github.com/MadBase/MadNet/application/objs/uint256" + "github.com/MadBase/MadNet/constants" + "github.com/MadBase/MadNet/errorz" + "github.com/MadBase/MadNet/utils" + capnp "zombiezen.com/go/capnproto2" +) + +// TxFee stores the transaction fee in a Tx +type TxFee struct { + TFPreImage *TFPreImage + TxHash []byte + // + utxoID []byte +} + +// New creates a new TxFee; fees must always +func (b *TxFee) New(chainID uint32, fee *uint256.Uint256) error { + if chainID == 0 { + return errorz.ErrInvalid{}.New("not initialized") + } + if fee == nil || fee.IsZero() { + return errorz.ErrInvalid{}.New("Error in TxFee.New: fee is nil") + } + tfp := &TFPreImage{ + ChainID: chainID, + Fee: fee.Clone(), + } + b.TFPreImage = tfp + return nil +} + +// UnmarshalBinary takes a byte slice and returns the corresponding +// TxFee object +func (b *TxFee) UnmarshalBinary(data []byte) error { + if b == nil { + return errorz.ErrInvalid{}.New("not initialized") + } + bc, err := txfee.Unmarshal(data) + if err != nil { + return err + } + return b.UnmarshalCapn(bc) +} + +// MarshalBinary takes the ValueStore object and returns the canonical +// byte slice +func (b *TxFee) MarshalBinary() ([]byte, error) { + if b == nil { + return nil, errorz.ErrInvalid{}.New("not initialized") + } + bc, err := b.MarshalCapn(nil) + if err != nil { + return nil, err + } + return txfee.Marshal(bc) +} + +// UnmarshalCapn unmarshals the capnproto definition of the object +func (b *TxFee) UnmarshalCapn(bc mdefs.TxFee) error { + if err := txfee.Validate(bc); err != nil { + return err + } + b.TFPreImage = &TFPreImage{} + if err := b.TFPreImage.UnmarshalCapn(bc.TFPreImage()); err != nil { + return err + } + b.TxHash = utils.CopySlice(bc.TxHash()) + return nil +} + +// MarshalCapn marshals the object into its capnproto definition +func (b *TxFee) MarshalCapn(seg *capnp.Segment) (mdefs.TxFee, error) { + if b == nil { + return mdefs.TxFee{}, errorz.ErrInvalid{}.New("not initialized") + } + var bc mdefs.TxFee + if seg == nil { + _, seg, err := capnp.NewMessage(capnp.SingleSegment(nil)) + if err != nil { + return bc, err + } + tmp, err := mdefs.NewRootTxFee(seg) + if err != nil { + return bc, err + } + bc = tmp + } else { + tmp, err := mdefs.NewTxFee(seg) + if err != nil { + return bc, err + } + bc = tmp + } + seg = bc.Struct.Segment() + bt, err := b.TFPreImage.MarshalCapn(seg) + if err != nil { + return bc, err + } + if err := bc.SetTFPreImage(bt); err != nil { + return bc, err + } + if err := bc.SetTxHash(utils.CopySlice(b.TxHash)); err != nil { + return bc, err + } + return bc, nil +} + +// PreHash calculates the PreHash of the object +func (b *TxFee) PreHash() ([]byte, error) { + if b == nil { + return nil, errorz.ErrInvalid{}.New("not initialized") + } + return b.TFPreImage.PreHash() +} + +// UTXOID calculates the UTXOID of the object +func (b *TxFee) UTXOID() ([]byte, error) { + if b == nil || b.TFPreImage == nil || len(b.TxHash) != constants.HashLen { + return nil, errorz.ErrInvalid{}.New("not initialized") + } + if b.utxoID != nil { + return utils.CopySlice(b.utxoID), nil + } + b.utxoID = MakeUTXOID(b.TxHash, b.TFPreImage.TXOutIdx) + return utils.CopySlice(b.utxoID), nil +} + +// TXOutIdx returns the TXOutIdx of the object +func (b *TxFee) TXOutIdx() (uint32, error) { + if b == nil || b.TFPreImage == nil { + return 0, errorz.ErrInvalid{}.New("not initialized") + } + return b.TFPreImage.TXOutIdx, nil +} + +// SetTXOutIdx sets the TXOutIdx of the object +func (b *TxFee) SetTXOutIdx(idx uint32) error { + if b == nil || b.TFPreImage == nil { + return errorz.ErrInvalid{}.New("not initialized") + } + b.TFPreImage.TXOutIdx = idx + return nil +} + +// SetTxHash sets the TxHash of the object +func (b *TxFee) SetTxHash(txHash []byte) error { + if b == nil || b.TFPreImage == nil { + return errorz.ErrInvalid{}.New("not initialized") + } + if len(txHash) != constants.HashLen { + return errorz.ErrInvalid{}.New("Invalid hash length") + } + b.TxHash = utils.CopySlice(txHash) + return nil +} + +// ChainID returns the ChainID of the object +func (b *TxFee) ChainID() (uint32, error) { + if b == nil || b.TFPreImage == nil || b.TFPreImage.ChainID == 0 { + return 0, errorz.ErrInvalid{}.New("not initialized") + } + return b.TFPreImage.ChainID, nil +} + +// Fee returns the Fee of the object; Fee should always be nonzero +func (b *TxFee) Fee() (*uint256.Uint256, error) { + if b == nil || b.TFPreImage == nil || b.TFPreImage.Fee == nil || b.TFPreImage.Fee.IsZero() { + return nil, errorz.ErrInvalid{}.New("not initialized") + } + return b.TFPreImage.Fee.Clone(), nil +} diff --git a/application/objs/tf_test.go b/application/objs/tf_test.go new file mode 100644 index 00000000..0452aaf6 --- /dev/null +++ b/application/objs/tf_test.go @@ -0,0 +1,397 @@ +package objs + +import ( + "bytes" + "testing" + + "github.com/MadBase/MadNet/application/objs/uint256" + "github.com/MadBase/MadNet/constants" +) + +func TestTxFeeGood(t *testing.T) { + cid := uint32(2) + fee, err := new(uint256.Uint256).FromUint64(65537) + if err != nil { + t.Fatal(err) + } + txoid := uint32(17) + + tfp := &TFPreImage{ + ChainID: cid, + Fee: fee, + TXOutIdx: txoid, + } + txHash := make([]byte, constants.HashLen) + tf := &TxFee{ + TFPreImage: tfp, + TxHash: txHash, + } + tf2 := &TxFee{} + tfBytes, err := tf.MarshalBinary() + if err != nil { + t.Fatal(err) + } + err = tf2.UnmarshalBinary(tfBytes) + if err != nil { + t.Fatal(err) + } + tfEqual(t, tf, tf2) +} + +func tfEqual(t *testing.T, tf1, tf2 *TxFee) { + tfpi1 := tf1.TFPreImage + tfpi2 := tf2.TFPreImage + tfpiEqual(t, tfpi1, tfpi2) + if !bytes.Equal(tf1.TxHash, tf2.TxHash) { + t.Fatal("Do not agree on TxHash!") + } +} + +func TestTxFeeBad1(t *testing.T) { + cid := uint32(0) // Invalid ChainID + fee, err := new(uint256.Uint256).FromUint64(65537) + if err != nil { + t.Fatal(err) + } + txoid := uint32(17) + + tfp := &TFPreImage{ + ChainID: cid, + Fee: fee, + TXOutIdx: txoid, + } + txHash := make([]byte, constants.HashLen) + tf := &TxFee{ + TFPreImage: tfp, + TxHash: txHash, + } + tf2 := &TxFee{} + tfBytes, err := tf.MarshalBinary() + if err != nil { + t.Fatal(err) + } + err = tf2.UnmarshalBinary(tfBytes) + if err == nil { + t.Fatal("Should raise error for invalid TFPreImage!") + } +} + +func TestTxFeeBad2(t *testing.T) { + cid := uint32(2) + fee, err := new(uint256.Uint256).FromUint64(65537) + if err != nil { + t.Fatal(err) + } + txoid := uint32(17) + + tfp := &TFPreImage{ + ChainID: cid, + Fee: fee, + TXOutIdx: txoid, + } + txHash := make([]byte, constants.HashLen+1) // Invalid TxHash + tf := &TxFee{ + TFPreImage: tfp, + TxHash: txHash, + } + tf2 := &TxFee{} + tfBytes, err := tf.MarshalBinary() + if err != nil { + t.Fatal(err) + } + err = tf2.UnmarshalBinary(tfBytes) + if err == nil { + t.Fatal("Should raise error for invalid TxHash: incorrect byte length!") + } +} + +func TestTxFeeNew(t *testing.T) { + utxo := &TXOut{} + chainID := uint32(0) + fee, err := new(uint256.Uint256).FromUint64(65537) + if err != nil { + t.Fatal(err) + } + err = utxo.txFee.New(chainID, nil) + if err == nil { + t.Fatal("Should raise an error (1)") + } + + tf := &TxFee{} + err = tf.New(chainID, nil) + if err == nil { + t.Fatal("Should raise an error (2)") + } + + chainID = 1 + err = tf.New(chainID, nil) + if err == nil { + t.Fatal("Should raise an error (3)") + } + + err = tf.New(chainID, fee) + if err != nil { + t.Fatal(err) + } +} + +func TestTxFeeMarshalBinary(t *testing.T) { + utxo := &TXOut{} + _, err := utxo.txFee.MarshalBinary() + if err == nil { + t.Fatal("Should raise an error (1)") + } + _, err = utxo.txFee.MarshalCapn(nil) + if err == nil { + t.Fatal("Should raise an error (2)") + } + tf := &TxFee{} + _, err = tf.MarshalBinary() + if err == nil { + t.Fatal("Should raise an error (3)") + } + _, err = tf.MarshalCapn(nil) + if err == nil { + t.Fatal("Should raise an error (4)") + } + + cid := uint32(2) + fee, err := new(uint256.Uint256).FromUint64(65537) + if err != nil { + t.Fatal(err) + } + txoid := uint32(17) + + tfp := &TFPreImage{ + ChainID: cid, + Fee: fee, + TXOutIdx: txoid, + } + txHash := make([]byte, constants.HashLen) + tf = &TxFee{ + TFPreImage: tfp, + TxHash: txHash, + } + tfBytes, err := tf.MarshalBinary() + if err != nil { + t.Fatal(err) + } + tf2 := &TxFee{} + err = tf2.UnmarshalBinary(tfBytes) + if err != nil { + t.Fatal(err) + } + tfEqual(t, tf, tf2) +} + +func TestTxFeeUnmarshalBinary(t *testing.T) { + data := make([]byte, 0) + utxo := &TXOut{} + err := utxo.txFee.UnmarshalBinary(data) + if err == nil { + t.Fatal("Should raise an error (1)") + } + tf := &TxFee{} + err = tf.UnmarshalBinary(data) + if err == nil { + t.Fatal("Should raise an error (2)") + } + + cid := uint32(2) + fee, err := new(uint256.Uint256).FromUint64(65537) + if err != nil { + t.Fatal(err) + } + txoid := uint32(17) + + tfp := &TFPreImage{ + ChainID: cid, + Fee: fee, + TXOutIdx: txoid, + } + txHash := make([]byte, constants.HashLen) + tf = &TxFee{ + TFPreImage: tfp, + TxHash: txHash, + } + tfBytes, err := tf.MarshalBinary() + if err != nil { + t.Fatal(err) + } + tf2 := &TxFee{} + err = tf2.UnmarshalBinary(tfBytes) + if err != nil { + t.Fatal(err) + } + tfEqual(t, tf, tf2) +} + +func TestTxFeePreHash(t *testing.T) { + utxo := &TXOut{} + _, err := utxo.txFee.PreHash() + if err == nil { + t.Fatal("Should raise an error (1)") + } + tf := &TxFee{} + _, err = tf.PreHash() + if err == nil { + t.Fatal("Should raise an error (2)") + } +} + +func TestTxFeeTXOutIdx(t *testing.T) { + utxo := &TXOut{} + _, err := utxo.txFee.TXOutIdx() + if err == nil { + t.Fatal("Should raise an error (1)") + } + tf := &TxFee{} + _, err = tf.TXOutIdx() + if err == nil { + t.Fatal("Should raise an error (2)") + } + tf.TFPreImage = &TFPreImage{} + txOutIdx := uint32(17) + tf.TFPreImage.TXOutIdx = txOutIdx + out, err := tf.TXOutIdx() + if err != nil { + t.Fatal(err) + } + if out != txOutIdx { + t.Fatal("TXOutIdxes do not match") + } +} + +func TestTxFeeUTXOID(t *testing.T) { + utxo := &TXOut{} + _, err := utxo.txFee.UTXOID() + if err == nil { + t.Fatal("Should raise an error (1)") + } + tf := &TxFee{} + _, err = tf.UTXOID() + if err == nil { + t.Fatal("Should raise an error (2)") + } + + cid := uint32(2) + fee, err := new(uint256.Uint256).FromUint64(65537) + if err != nil { + t.Fatal(err) + } + txoid := uint32(17) + + tfp := &TFPreImage{ + ChainID: cid, + Fee: fee, + TXOutIdx: txoid, + } + tf = &TxFee{ + TFPreImage: tfp, + TxHash: nil, + } + _, err = tf.UTXOID() + if err == nil { + t.Fatal("Should raise an error (3)") + } + + txHash := make([]byte, constants.HashLen) + tf.TxHash = txHash + utxoID, err := tf.UTXOID() + if err != nil { + t.Fatal(err) + } + out, err := tf.UTXOID() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(out, utxoID) { + t.Fatal("utxoIDs do not match") + } +} + +func TestTxFeeSetTXOutIdx(t *testing.T) { + idx := uint32(0) + utxo := &TXOut{} + err := utxo.txFee.SetTXOutIdx(idx) + if err == nil { + t.Fatal("Should raise an error (1)") + } + tf := &TxFee{} + err = tf.SetTXOutIdx(idx) + if err == nil { + t.Fatal("Should raise an error (2)") + } + tf.TFPreImage = &TFPreImage{} + err = tf.SetTXOutIdx(idx) + if err != nil { + t.Fatal(err) + } + out, err := tf.TXOutIdx() + if err != nil { + t.Fatal(err) + } + if out != idx { + t.Fatal("TXOutIdxes do not match") + } +} + +func TestTxFeeSetTxHash(t *testing.T) { + tf := &TxFee{} + txHash := make([]byte, 0) + err := tf.SetTxHash(txHash) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + tf.TFPreImage = &TFPreImage{} + err = tf.SetTxHash(txHash) + if err == nil { + t.Fatal("Should have raised error (2)") + } + + txHash = make([]byte, constants.HashLen) + err = tf.SetTxHash(txHash) + if err != nil { + t.Fatal("Should pass") + } +} + +func TestTxFeeChainID(t *testing.T) { + tf := &TxFee{} + _, err := tf.ChainID() + if err == nil { + t.Fatal("Should raise an error") + } + tf.TFPreImage = &TFPreImage{} + cid := uint32(17) + tf.TFPreImage.ChainID = cid + chainID, err := tf.ChainID() + if err != nil { + t.Fatal(err) + } + if cid != chainID { + t.Fatal("ChainIDs do not match") + } +} + +func TestTxFeeFee(t *testing.T) { + tf := &TxFee{} + _, err := tf.Fee() + if err == nil { + t.Fatal("Should raise an error") + } + tf.TFPreImage = &TFPreImage{} + feeTrue, err := new(uint256.Uint256).FromUint64(1234567890) + if err != nil { + t.Fatal(err) + } + tf.TFPreImage.Fee = feeTrue.Clone() + fee, err := tf.Fee() + if err != nil { + t.Fatal(err) + } + if !fee.Eq(feeTrue) { + t.Fatal("Fees do not match") + } +} diff --git a/application/objs/tfpi.go b/application/objs/tfpi.go new file mode 100644 index 00000000..182af5b4 --- /dev/null +++ b/application/objs/tfpi.go @@ -0,0 +1,128 @@ +package objs + +import ( + mdefs "github.com/MadBase/MadNet/application/objs/capn" + "github.com/MadBase/MadNet/application/objs/tfpreimage" + "github.com/MadBase/MadNet/application/objs/uint256" + "github.com/MadBase/MadNet/crypto" + "github.com/MadBase/MadNet/errorz" + "github.com/MadBase/MadNet/utils" + capnp "zombiezen.com/go/capnproto2" +) + +// TFPreImage is a txfee preimage +type TFPreImage struct { + ChainID uint32 + TXOutIdx uint32 + Fee *uint256.Uint256 + // + preHash []byte +} + +// UnmarshalBinary takes a byte slice and returns the corresponding +// TFPreImage object +func (b *TFPreImage) UnmarshalBinary(data []byte) error { + if b == nil { + return errorz.ErrInvalid{}.New("not initialized") + } + bc, err := tfpreimage.Unmarshal(data) + if err != nil { + return err + } + return b.UnmarshalCapn(bc) +} + +// MarshalBinary takes the TFPreImage object and returns the canonical +// byte slice +func (b *TFPreImage) MarshalBinary() ([]byte, error) { + if b == nil { + return nil, errorz.ErrInvalid{}.New("not initialized") + } + bc, err := b.MarshalCapn(nil) + if err != nil { + return nil, err + } + return tfpreimage.Marshal(bc) +} + +// UnmarshalCapn unmarshals the capnproto definition of the object +func (b *TFPreImage) UnmarshalCapn(bc mdefs.TFPreImage) error { + if err := tfpreimage.Validate(bc); err != nil { + return err + } + b.ChainID = bc.ChainID() + u32array := [8]uint32{} + u32array[0] = bc.Fee0() + u32array[1] = bc.Fee1() + u32array[2] = bc.Fee2() + u32array[3] = bc.Fee3() + u32array[4] = bc.Fee4() + u32array[5] = bc.Fee5() + u32array[6] = bc.Fee6() + u32array[7] = bc.Fee7() + fObj := &uint256.Uint256{} + err := fObj.FromUint32Array(u32array) + if err != nil { + return err + } + b.Fee = fObj + b.TXOutIdx = bc.TXOutIdx() + return nil +} + +// MarshalCapn marshals the object into its capnproto definition +func (b *TFPreImage) MarshalCapn(seg *capnp.Segment) (mdefs.TFPreImage, error) { + if b == nil { + return mdefs.TFPreImage{}, errorz.ErrInvalid{}.New("not initialized") + } + var bc mdefs.TFPreImage + if seg == nil { + _, seg, err := capnp.NewMessage(capnp.SingleSegment(nil)) + if err != nil { + return bc, err + } + tmp, err := mdefs.NewRootTFPreImage(seg) + if err != nil { + return bc, err + } + bc = tmp + } else { + tmp, err := mdefs.NewTFPreImage(seg) + if err != nil { + return bc, err + } + bc = tmp + } + bc.SetChainID(b.ChainID) + u32array, err := b.Fee.ToUint32Array() + if err != nil { + return bc, err + } + bc.SetFee0(u32array[0]) + bc.SetFee1(u32array[1]) + bc.SetFee2(u32array[2]) + bc.SetFee3(u32array[3]) + bc.SetFee4(u32array[4]) + bc.SetFee5(u32array[5]) + bc.SetFee6(u32array[6]) + bc.SetFee7(u32array[7]) + bc.SetTXOutIdx(b.TXOutIdx) + return bc, nil +} + +// PreHash calculates the PreHash of the object +func (b *TFPreImage) PreHash() ([]byte, error) { + if b == nil { + return nil, errorz.ErrInvalid{}.New("not initialized") + } + if b.preHash != nil { + return utils.CopySlice(b.preHash), nil + } + msg, err := b.MarshalBinary() + if err != nil { + return nil, err + } + hsh := crypto.Hasher(msg) + b.preHash = hsh + return utils.CopySlice(b.preHash), nil +} diff --git a/application/objs/tfpi_test.go b/application/objs/tfpi_test.go new file mode 100644 index 00000000..1225b7ed --- /dev/null +++ b/application/objs/tfpi_test.go @@ -0,0 +1,144 @@ +package objs + +import ( + "bytes" + "testing" + + "github.com/MadBase/MadNet/application/objs/uint256" +) + +func TestTFPreImageGood(t *testing.T) { + cid := uint32(2) + fee, err := new(uint256.Uint256).FromUint64(65537) + if err != nil { + t.Fatal(err) + } + txoid := uint32(17) + + tfp := &TFPreImage{ + ChainID: cid, + Fee: fee, + TXOutIdx: txoid, + } + tfp2 := &TFPreImage{} + tfpBytes, err := tfp.MarshalBinary() + if err != nil { + t.Fatal(err) + } + err = tfp2.UnmarshalBinary(tfpBytes) + if err != nil { + t.Fatal(err) + } + tfpiEqual(t, tfp, tfp2) +} + +func tfpiEqual(t *testing.T, tfpi1, tfpi2 *TFPreImage) { + if tfpi1.ChainID != tfpi2.ChainID { + t.Fatal("Do not agree on ChainID!") + } + if !tfpi1.Fee.Eq(tfpi2.Fee) { + t.Fatal("Do not agree on Next!") + } + if tfpi1.TXOutIdx != tfpi2.TXOutIdx { + t.Fatal("Do not agree on TXOutIdx!") + } +} + +func TestTFPreImageBad1(t *testing.T) { + cid := uint32(0) // Invalid ChainID + fee, err := new(uint256.Uint256).FromUint64(65537) + if err != nil { + t.Fatal(err) + } + txoid := uint32(17) + + tfp := &TFPreImage{ + ChainID: cid, + Fee: fee, + TXOutIdx: txoid, + } + tfp2 := &TFPreImage{} + tfpBytes, err := tfp.MarshalBinary() + if err != nil { + t.Fatal(err) + } + err = tfp2.UnmarshalBinary(tfpBytes) + if err == nil { + t.Fatal("Should raise error for invalid ChainID!") + } +} + +func TestTFPreImageMarshalBinary(t *testing.T) { + tf := &TxFee{} + _, err := tf.TFPreImage.MarshalBinary() + if err == nil { + t.Fatal("Should raise an error (1)") + } + + tfp := &TFPreImage{} + _, err = tfp.MarshalBinary() + if err == nil { + t.Fatal("Should raise an error (2)") + } +} + +func TestTFPreImageUnmarshalBinary(t *testing.T) { + data := make([]byte, 0) + tf := &TxFee{} + err := tf.TFPreImage.UnmarshalBinary(data) + if err == nil { + t.Fatal("Should raise an error (1)") + } + + tfp := &TFPreImage{} + err = tfp.UnmarshalBinary(data) + if err == nil { + t.Fatal("Should raise an error (2)") + } +} + +func TestTFPreImagePreHash(t *testing.T) { + tf := &TxFee{} + _, err := tf.TFPreImage.PreHash() + if err == nil { + t.Fatal("Should raise an error (1)") + } + + tfp := &TFPreImage{} + _, err = tfp.PreHash() + if err == nil { + t.Fatal("Should raise an error (2)") + } + + // preHash is present; should not fail + tfpGoodPH := &TFPreImage{} + tfpGoodPH.preHash = make([]byte, 32) + tfpGoodPHOut, err := tfpGoodPH.PreHash() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(tfpGoodPHOut, tfpGoodPH.preHash) { + t.Fatal("PreHashes do not match (1)") + } + + // Make new + cid := uint32(2) + fee, err := new(uint256.Uint256).FromUint64(65537) + if err != nil { + t.Fatal(err) + } + txoid := uint32(17) + + tfp = &TFPreImage{ + ChainID: cid, + Fee: fee, + TXOutIdx: txoid, + } + out, err := tfp.PreHash() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(out, tfp.preHash) { + t.Fatal("PreHashes do not match (2)") + } +} diff --git a/application/objs/tfpreimage/tfpreimage.go b/application/objs/tfpreimage/tfpreimage.go new file mode 100644 index 00000000..e60d4e9e --- /dev/null +++ b/application/objs/tfpreimage/tfpreimage.go @@ -0,0 +1,52 @@ +package tfpreimage + +import ( + mdefs "github.com/MadBase/MadNet/application/objs/capn" + "github.com/MadBase/MadNet/constants" + "github.com/MadBase/MadNet/errorz" + "github.com/MadBase/MadNet/utils" + capnp "zombiezen.com/go/capnproto2" +) + +// Marshal will marshal the TFPreImage object. +func Marshal(v mdefs.TFPreImage) ([]byte, error) { + raw, err := capnp.Canonicalize(v.Struct) + if err != nil { + return nil, err + } + out := utils.CopySlice(raw) + return out, nil +} + +// Unmarshal will unmarshal the TFPreImage object. +func Unmarshal(data []byte) (mdefs.TFPreImage, error) { + var err error + fn := func() (mdefs.TFPreImage, error) { + defer func() { + if r := recover(); r != nil { + err = errorz.ErrInvalid{}.New("bad serialization") + } + }() + dataCopy := utils.CopySlice(data) + msg := &capnp.Message{Arena: capnp.SingleSegment(dataCopy)} + obj, tmp := mdefs.ReadRootTFPreImage(msg) + err = tmp + return obj, err + } + obj, err := fn() + if err != nil { + return mdefs.TFPreImage{}, err + } + return obj, nil +} + +// Validate will validate the TFPreImage object +func Validate(v mdefs.TFPreImage) error { + if v.ChainID() < 1 { + return errorz.ErrInvalid{}.New("tfpreimage capn obj is not valid; invalid ChainID") + } + if int(v.TXOutIdx()) >= constants.MaxTxVectorLength { + return errorz.ErrInvalid{}.New("tfpreimage capn obj is not valid: output index is too large") + } + return nil +} diff --git a/application/objs/tx.go b/application/objs/tx.go index 1f69a6f7..f61541ef 100644 --- a/application/objs/tx.go +++ b/application/objs/tx.go @@ -8,6 +8,7 @@ import ( mdefs "github.com/MadBase/MadNet/application/objs/capn" "github.com/MadBase/MadNet/application/objs/tx" + "github.com/MadBase/MadNet/application/wrapper" trie "github.com/MadBase/MadNet/badgerTrie" "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/crypto" @@ -42,6 +43,12 @@ func (b *Tx) MarshalBinary() ([]byte, error) { if b == nil { return nil, errorz.ErrInvalid{}.New("not initialized") } + if len(b.Vin) > constants.MaxTxVectorLength { + return nil, errorz.ErrInvalid{}.New("invalid tx: len(vin) > MaxTxVectorLength") + } + if len(b.Vout) > constants.MaxTxVectorLength { + return nil, errorz.ErrInvalid{}.New("invalid tx: len(vout) > MaxTxVectorLength") + } bc, err := b.MarshalCapn(nil) if err != nil { return nil, err @@ -202,8 +209,8 @@ func (b *Tx) ValidateDataStoreIndexes(opset map[string]bool) (map[string]bool, e return nil, err } tmp := []byte{} - tmp = append(tmp, utils.CopySlice(ownerBytes)...) - tmp = append(tmp, utils.CopySlice(index)...) + tmp = append(tmp, ownerBytes...) + tmp = append(tmp, index...) hsh := crypto.Hasher(tmp) if !opset[string(hsh)] { opset[string(hsh)] = true @@ -352,7 +359,7 @@ func (b *Tx) GeneratedUTXOID() ([][]byte, error) { // GeneratedPreHash returns the list of PreHashs from Vout func (b *Tx) GeneratedPreHash() ([][]byte, error) { - if b == nil || len(b.Vout) == 0 || len(b.Vin) == 0 { + if b == nil || len(b.Vout) == 0 { return nil, errorz.ErrInvalid{}.New("not initialized") } return b.Vout.PreHash() @@ -360,7 +367,7 @@ func (b *Tx) GeneratedPreHash() ([][]byte, error) { // ValidateSignature validates the signatures of the objects func (b *Tx) ValidateSignature(currentHeight uint32, refUTXOs Vout) error { - if b == nil || len(b.Vout) == 0 || len(b.Vin) == 0 { + if b == nil || len(b.Vin) == 0 { return errorz.ErrInvalid{}.New("not initialized") } return refUTXOs.ValidateSignature(currentHeight, b.Vin) @@ -368,20 +375,39 @@ func (b *Tx) ValidateSignature(currentHeight uint32, refUTXOs Vout) error { // ValidatePreSignature validates the presignatures of the objects func (b *Tx) ValidatePreSignature() error { - if b == nil || len(b.Vout) == 0 || len(b.Vin) == 0 { + if b == nil || len(b.Vout) == 0 { return errorz.ErrInvalid{}.New("not initialized") } return b.Vout.ValidatePreSignature() } +// ValidateFees validates the fees of the object. +// currentHeight and refUTXOs are needed to verify if we have a cleanup tx. +func (b *Tx) ValidateFees(currentHeight uint32, refUTXOs Vout, storage *wrapper.Storage) error { + if b == nil || len(b.Vout) == 0 || len(b.Vin) == 0 { + return errorz.ErrInvalid{}.New("not initialized") + } + if b.IsCleanupTx(currentHeight, refUTXOs) { + // Tx is a valid Cleanup Tx, so we do not worry about fees + return nil + } + if err := b.Vout.ValidateFees(storage); err != nil { + return err + } + if err := b.Vout.ValidateTxFee(storage); err != nil { + return err + } + return nil +} + // ValidateEqualVinVout checks the following // calc sum on inputs from utxos and currentHeight // sum inputs must equal sum outputs -func (b *Tx) ValidateEqualVinVout(refUTXOs Vout, currentHeight uint32) error { +func (b *Tx) ValidateEqualVinVout(currentHeight uint32, refUTXOs Vout) error { if b == nil || len(b.Vout) == 0 || len(b.Vin) == 0 { return errorz.ErrInvalid{}.New("not initialized") } - valueOut, err := b.Vout.Value() + valueOut, err := b.Vout.ValuePlusFee() if err != nil { return err } @@ -399,7 +425,7 @@ func (b *Tx) ValidateEqualVinVout(refUTXOs Vout, currentHeight uint32) error { if err != nil { return err } - if valueOut.Clone().Cmp(valueIn.Clone()) == 0 { + if valueOut.Cmp(valueIn) == 0 { return nil } return errorz.ErrInvalid{}.New(fmt.Sprintf("input value does not match output value: IN:%v vs OUT:%v", valueIn, valueOut)) @@ -407,14 +433,11 @@ func (b *Tx) ValidateEqualVinVout(refUTXOs Vout, currentHeight uint32) error { // ValidateChainID validates that all elements have the correct ChainID func (b *Tx) ValidateChainID(chainID uint32) error { - if b == nil { - return errorz.ErrInvalid{}.New("not initialized a") - } - if len(b.Vout) == 0 { - return errorz.ErrInvalid{}.New("not initialized b") + if b == nil || len(b.Vout) == 0 || len(b.Vin) == 0 { + return errorz.ErrInvalid{}.New("not initialized") } - if len(b.Vin) == 0 { - return errorz.ErrInvalid{}.New("not initialized c") + if chainID == 0 { + return errorz.ErrInvalid{}.New("chainID invalid: cannot be 0") } for _, inp := range b.Vin { inpCid, err := inp.ChainID() @@ -439,7 +462,7 @@ func (b *Tx) ValidateChainID(chainID uint32) error { // CannotBeMinedUntil ... func (b *Tx) CannotBeMinedUntil() (uint32, error) { - if b == nil || len(b.Vout) == 0 || len(b.Vin) == 0 { + if b == nil || len(b.Vout) == 0 { return 0, errorz.ErrInvalid{}.New("not initialized") } maxBH := uint32(1) @@ -457,7 +480,7 @@ func (b *Tx) CannotBeMinedUntil() (uint32, error) { // ValidateIssuedAtForMining ... func (b *Tx) ValidateIssuedAtForMining(currentHeight uint32) error { - if b == nil || len(b.Vout) == 0 || len(b.Vin) == 0 { + if b == nil || len(b.Vout) == 0 { return errorz.ErrInvalid{}.New("not initialized") } hmap := make(map[uint32]bool) @@ -489,7 +512,7 @@ func (b *Tx) ValidateIssuedAtForMining(currentHeight uint32) error { // EpochOfExpirationForMining ... func (b *Tx) EpochOfExpirationForMining() (uint32, error) { - if b == nil || len(b.Vout) == 0 || len(b.Vin) == 0 { + if b == nil || len(b.Vout) == 0 { return 0, errorz.ErrInvalid{}.New("not initialized") } hmap := make(map[uint32]bool) @@ -517,7 +540,7 @@ func (b *Tx) EpochOfExpirationForMining() (uint32, error) { } // Validate ... -func (b *Tx) Validate(set map[string]bool, currentHeight uint32, consumedUTXOs Vout) (map[string]bool, error) { +func (b *Tx) Validate(set map[string]bool, currentHeight uint32, consumedUTXOs Vout, storage *wrapper.Storage) (map[string]bool, error) { if b == nil || len(b.Vin) == 0 || len(b.Vout) == 0 { return nil, errorz.ErrInvalid{}.New("empty input or output vector in tx") } @@ -532,7 +555,7 @@ func (b *Tx) Validate(set map[string]bool, currentHeight uint32, consumedUTXOs V if err != nil { return nil, err } - err = b.ValidateEqualVinVout(consumedUTXOs, currentHeight) + err = b.ValidateEqualVinVout(currentHeight, consumedUTXOs) if err != nil { return nil, err } @@ -540,6 +563,10 @@ func (b *Tx) Validate(set map[string]bool, currentHeight uint32, consumedUTXOs V if err != nil { return nil, err } + err = b.ValidateFees(currentHeight, consumedUTXOs, storage) + if err != nil { + return nil, err + } return set, nil } @@ -572,7 +599,7 @@ func (b *Tx) PostValidatePending(currentHeight uint32, consumedUTXOs Vout) error if b == nil { return errorz.ErrInvalid{}.New("not initialized") } - err := b.ValidateEqualVinVout(consumedUTXOs, currentHeight) + err := b.ValidateEqualVinVout(currentHeight, consumedUTXOs) if err != nil { return err } @@ -583,5 +610,26 @@ func (b *Tx) PostValidatePending(currentHeight uint32, consumedUTXOs Vout) error return nil } +// IsCleanupTx checks if Tx is a cleanup transaction. +// Cleanup transactions are unique in that there is no associated TxFee +// or ValueStoreFee. The CleaupTx must consist of *expired* DataStores +// with value equal to that in the only ValueStore in Vout. +func (b *Tx) IsCleanupTx(currentHeight uint32, refUTXOs Vout) bool { + if b == nil { + return false + } + // Confirm Vin + cleanupVin := b.Vin.IsCleanupVin(currentHeight, refUTXOs) + if !cleanupVin { + return false + } + // Confirm Vout + cleanupVout := b.Vout.IsCleanupVout() + if !cleanupVout { + return false + } + return true +} + // XXXIsTx allows compile time type checking for transaction interfaces func (b *Tx) XXXIsTx() {} diff --git a/application/objs/tx/tx.go b/application/objs/tx/tx.go index aca9dff7..ef9372b3 100644 --- a/application/objs/tx/tx.go +++ b/application/objs/tx/tx.go @@ -2,6 +2,7 @@ package tx import ( mdefs "github.com/MadBase/MadNet/application/objs/capn" + "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/errorz" "github.com/MadBase/MadNet/utils" capnp "zombiezen.com/go/capnproto2" @@ -51,6 +52,9 @@ func Validate(v mdefs.Tx) error { if vin.Len() == 0 { return errorz.ErrInvalid{}.New("tx capn obj is not valid; invalid Vin; zero length object") } + if vin.Len() > constants.MaxTxVectorLength { + return errorz.ErrInvalid{}.New("tx capn obj is not valid; invalid Vin; length object too large") + } if !v.HasVout() { return errorz.ErrInvalid{}.New("tx capn obj does not have Vout") } @@ -61,5 +65,8 @@ func Validate(v mdefs.Tx) error { if vout.Len() == 0 { return errorz.ErrInvalid{}.New("tx capn obj is not valid; invalid Vout; zero length object") } + if vout.Len() > constants.MaxTxVectorLength { + return errorz.ErrInvalid{}.New("tx capn obj is not valid; invalid Vout; length object too large") + } return nil } diff --git a/application/objs/tx_test.go b/application/objs/tx_test.go index 53a44ef1..ee66b4df 100644 --- a/application/objs/tx_test.go +++ b/application/objs/tx_test.go @@ -3,6 +3,7 @@ package objs import ( "bytes" "encoding/hex" + "math/big" "strconv" "testing" @@ -23,10 +24,12 @@ func makeVS(t *testing.T, ownerSigner Signer, i int) *TXOut { owner := &ValueStoreOwner{} owner.New(ownerAcct, constants.CurveSecp256k1) + fee := new(uint256.Uint256) vsp := &VSPreImage{ ChainID: cid, Value: val, Owner: owner, + Fee: fee.Clone(), } var txHash []byte if i == 0 { @@ -56,7 +59,130 @@ func makeVS(t *testing.T, ownerSigner Signer, i int) *TXOut { return utxInputs } +func makeVSWithValueFee(t *testing.T, ownerSigner Signer, i int, value, fee *uint256.Uint256) *TXOut { + if value == nil || fee == nil { + panic("invalid value or fee") + } + cid := uint32(2) + + ownerPubk, err := ownerSigner.Pubkey() + if err != nil { + t.Fatal(err) + } + ownerAcct := crypto.GetAccount(ownerPubk) + owner := &ValueStoreOwner{} + owner.New(ownerAcct, constants.CurveSecp256k1) + + vsp := &VSPreImage{ + ChainID: cid, + Value: value, + Owner: owner, + Fee: fee.Clone(), + } + var txHash []byte + if i == 0 { + txHash = make([]byte, constants.HashLen) + } else { + txHash = crypto.Hasher([]byte(strconv.Itoa(i))) + } + vs := &ValueStore{ + VSPreImage: vsp, + TxHash: txHash, + } + vs2 := &ValueStore{} + vsBytes, err := vs.MarshalBinary() + if err != nil { + t.Fatal(err) + } + err = vs2.UnmarshalBinary(vsBytes) + if err != nil { + t.Fatal(err) + } + vsEqual(t, vs, vs2) + utxInputs := &TXOut{} + err = utxInputs.NewValueStore(vs) + if err != nil { + t.Fatal(err) + } + return utxInputs +} + +func makeDSWithValueFee(t *testing.T, ownerSigner Signer, i int, rawData []byte, index []byte, startEpoch uint32, numEpochs uint32, fee *uint256.Uint256) *TXOut { + if fee == nil || len(rawData) == 0 { + panic("invalid fee or rawData") + } + cid := uint32(2) + + ownerPubk, err := ownerSigner.Pubkey() + if err != nil { + t.Fatal(err) + } + ownerAcct := crypto.GetAccount(ownerPubk) + owner := &DataStoreOwner{} + owner.New(ownerAcct, constants.CurveSecp256k1) + + dataSize32 := uint32(len(rawData)) + deposit, err := BaseDepositEquation(dataSize32, numEpochs) + if err != nil { + t.Fatal(err) + } + + dsp := &DSPreImage{ + ChainID: cid, + Index: index, + IssuedAt: startEpoch, + Deposit: deposit.Clone(), + RawData: rawData, + Owner: owner, + Fee: fee.Clone(), + } + err = dsp.ValidateDeposit() + if err != nil { + t.Fatal(err) + } + var txHash []byte + if i == 0 { + txHash = make([]byte, constants.HashLen) + } else { + txHash = crypto.Hasher([]byte(strconv.Itoa(i))) + } + dsl := &DSLinker{ + DSPreImage: dsp, + TxHash: txHash, + } + ds := &DataStore{ + DSLinker: dsl, + } + err = ds.PreSign(ownerSigner) + if err != nil { + t.Fatal(err) + } + err = ds.ValidatePreSignature() + if err != nil { + t.Fatal(err) + } + + ds2 := &DataStore{} + dsBytes, err := ds.MarshalBinary() + if err != nil { + t.Fatal(err) + } + err = ds2.UnmarshalBinary(dsBytes) + if err != nil { + t.Fatal(err) + } + dsEqual(t, ds, ds2) + utxInputs := &TXOut{} + err = utxInputs.NewDataStore(ds) + if err != nil { + t.Fatal(err) + } + return utxInputs +} + func TestTx(t *testing.T) { + msg := makeMockStorageGetter() + storage := makeStorage(msg) ownerSigner := &crypto.Secp256k1Signer{} if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { @@ -153,7 +279,7 @@ func TestTx(t *testing.T) { if err != nil { t.Fatal(err) } - err = tx.ValidateEqualVinVout(consumedUTXOs, 1) + err = tx.ValidateEqualVinVout(1, consumedUTXOs) if err != nil { t.Fatal(err) } @@ -169,13 +295,13 @@ func TestTx(t *testing.T) { if err != nil { t.Fatal(err) } - _, err = tx2.Validate(nil, 1, consumedUTXOs) + _, err = tx2.Validate(nil, 1, consumedUTXOs, storage) if err != nil { t.Fatal(err) } txVec := TxVec([]*Tx{tx}) - err = txVec.Validate(1, consumedUTXOs) + err = txVec.Validate(1, consumedUTXOs, storage) if err != nil { t.Fatal(err) } @@ -232,7 +358,10 @@ func TestTx(t *testing.T) { } signer := &crypto.BNSigner{} - signer.SetPrivk(privk) + err = signer.SetPrivk(privk) + if err != nil { + t.Fatal(err) + } pubk, _ := signer.Pubkey() account := crypto.GetAccount(pubk) @@ -251,6 +380,7 @@ func TestTx(t *testing.T) { t.Fatal(err) } + fee := new(uint256.Uint256) val, err := new(uint256.Uint256).FromUint64(300) if err != nil { t.Fatal(err) @@ -265,6 +395,7 @@ func TestTx(t *testing.T) { CurveSpec: constants.CurveBN256Eth, Account: account, }, + Fee: fee.Clone(), }, } @@ -322,10 +453,1282 @@ func TestTx(t *testing.T) { } -func TestTxConsumedPreHash(t *testing.T) { +func TestTxMarshalGood(t *testing.T) { tx := &Tx{} - _, err := tx.ConsumedPreHash() + + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + value64 := uint64(10000) + value, err := new(uint256.Uint256).FromUint64(value64) + if err != nil { + t.Fatal(err) + } + fee64 := uint64(0) + fee, err := new(uint256.Uint256).FromUint64(fee64) + if err != nil { + t.Fatal(err) + } + utxo1 := makeVSWithValueFee(t, ownerSigner, 1, value, fee) + txin1, err := utxo1.MakeTxIn() + if err != nil { + t.Fatal(err) + } + err = utxo1.valueStore.Sign(txin1, ownerSigner) + if err != nil { + t.Fatal(err) + } + + utxo2 := makeVSWithValueFee(t, ownerSigner, 2, value, fee) + tx.Vin = []*TXIn{txin1} + tx.Vout = []*TXOut{utxo2} + + err = tx.SetTxHash() + if err != nil { + t.Fatal(err) + } + + txb, err := tx.MarshalBinary() + if err != nil { + t.Fatal(err) + } + tx2 := &Tx{} + err = tx2.UnmarshalBinary(txb) + if err != nil { + t.Fatal(err) + } +} + +func TestTxMarshalBad1(t *testing.T) { + tx := &Tx{} + txb, err := tx.MarshalBinary() + if err != nil { + t.Fatal(err) + } + tx2 := &Tx{} + err = tx2.UnmarshalBinary(txb) if err == nil { - t.Fatal("Should raise an error") + t.Fatal("Should have raised error") + } +} + +func TestTxMarshalBad2(t *testing.T) { + txin := &TXIn{} + vin := Vin{} + vout := Vout{} + for i := 0; i < constants.MaxTxVectorLength+1; i++ { + vin = append(vin, txin) + } + tx := &Tx{ + Vin: vin, + Vout: vout, + } + _, err := tx.MarshalBinary() + if err == nil { + t.Fatal("Should have raised error (1)") + } + + utxo := &TXOut{} + vin = Vin{} + vout = Vout{} + for i := 0; i < constants.MaxTxVectorLength+1; i++ { + vout = append(vout, utxo) + } + tx = &Tx{ + Vin: vin, + Vout: vout, + } + _, err = tx.MarshalBinary() + if err == nil { + t.Fatal("Should have raised error (2)") + } +} + +func TestTxValidateChainIDBad1(t *testing.T) { + chainID := uint32(1) + tx := &Tx{} + err := tx.ValidateChainID(chainID) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestTxValidateChainIDBad2(t *testing.T) { + chainID := uint32(0) + tx := &Tx{ + Vin: Vin{&TXIn{}}, + Vout: Vout{&TXOut{}}, + } + err := tx.ValidateChainID(chainID) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestTxCannotBeMinedUntilBad(t *testing.T) { + tx := &Tx{} + _, err := tx.CannotBeMinedUntil() + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestTxValidateIssuedAtForMiningGood(t *testing.T) { + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + value64 := uint64(10000) + value, err := new(uint256.Uint256).FromUint64(value64) + if err != nil { + t.Fatal(err) + } + fee64 := uint64(0) + fee, err := new(uint256.Uint256).FromUint64(fee64) + if err != nil { + t.Fatal(err) + } + utxo1 := makeVSWithValueFee(t, ownerSigner, 1, value, fee) + txin1, err := utxo1.MakeTxIn() + if err != nil { + t.Fatal(err) + } + err = utxo1.valueStore.Sign(txin1, ownerSigner) + if err != nil { + t.Fatal(err) + } + + tx := &Tx{} + utxo2 := makeVSWithValueFee(t, ownerSigner, 2, value, fee) + tx.Vin = []*TXIn{txin1} + tx.Vout = []*TXOut{utxo2} + + currentHeight := uint32(1) + err = tx.ValidateIssuedAtForMining(currentHeight) + if err != nil { + t.Fatal(err) + } +} + +func TestTxEpochOfExpirationForMiningBad(t *testing.T) { + tx := &Tx{} + _, err := tx.EpochOfExpirationForMining() + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestTxEpochOfExpirationForMiningGood(t *testing.T) { + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + value64 := uint64(10000) + value, err := new(uint256.Uint256).FromUint64(value64) + if err != nil { + t.Fatal(err) + } + fee64 := uint64(0) + fee, err := new(uint256.Uint256).FromUint64(fee64) + if err != nil { + t.Fatal(err) + } + utxo1 := makeVSWithValueFee(t, ownerSigner, 1, value, fee) + txin1, err := utxo1.MakeTxIn() + if err != nil { + t.Fatal(err) + } + err = utxo1.valueStore.Sign(txin1, ownerSigner) + if err != nil { + t.Fatal(err) + } + + tx := &Tx{} + utxo2 := makeVSWithValueFee(t, ownerSigner, 2, value, fee) + tx.Vin = []*TXIn{txin1} + tx.Vout = []*TXOut{utxo2} + + height, err := tx.EpochOfExpirationForMining() + if err != nil { + t.Fatal(err) + } + if height != constants.MaxUint32 { + t.Fatal("Incorrect height") + } +} + +func TestTxValidateIssuedAtForMiningBad(t *testing.T) { + currentHeight := uint32(1) + tx := &Tx{} + err := tx.ValidateIssuedAtForMining(currentHeight) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestTxValidateUniqueGood(t *testing.T) { + tx := &Tx{} + + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + value64 := uint64(10000) + value, err := new(uint256.Uint256).FromUint64(value64) + if err != nil { + t.Fatal(err) + } + fee64 := uint64(0) + fee, err := new(uint256.Uint256).FromUint64(fee64) + if err != nil { + t.Fatal(err) + } + utxo1 := makeVSWithValueFee(t, ownerSigner, 1, value, fee) + txin1, err := utxo1.MakeTxIn() + if err != nil { + t.Fatal(err) + } + err = utxo1.valueStore.Sign(txin1, ownerSigner) + if err != nil { + t.Fatal(err) + } + + utxo2 := makeVSWithValueFee(t, ownerSigner, 2, value, fee) + tx.Vin = []*TXIn{txin1} + tx.Vout = []*TXOut{utxo2} + + _, err = tx.ValidateUnique(nil) + if err != nil { + t.Fatal(err) + } +} + +func TestTxValidateUniqueBad1(t *testing.T) { + tx := &Tx{} + + txin1 := &TXIn{} + tx.Vin = []*TXIn{txin1} + + _, err := tx.ValidateUnique(nil) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestTxValidateUniqueBad2(t *testing.T) { + tx := &Tx{} + + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + value64 := uint64(10000) + value, err := new(uint256.Uint256).FromUint64(value64) + if err != nil { + t.Fatal(err) + } + fee64 := uint64(0) + fee, err := new(uint256.Uint256).FromUint64(fee64) + if err != nil { + t.Fatal(err) + } + utxo1 := makeVSWithValueFee(t, ownerSigner, 1, value, fee) + txin1, err := utxo1.MakeTxIn() + if err != nil { + t.Fatal(err) + } + err = utxo1.valueStore.Sign(txin1, ownerSigner) + if err != nil { + t.Fatal(err) + } + + utxo2 := &TXOut{} + tx.Vin = []*TXIn{txin1} + tx.Vout = []*TXOut{utxo2} + + _, err = tx.ValidateUnique(nil) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestTxValidateUniqueBad3(t *testing.T) { + tx := &Tx{} + + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + value64 := uint64(10000) + value, err := new(uint256.Uint256).FromUint64(value64) + if err != nil { + t.Fatal(err) + } + fee64 := uint64(0) + fee, err := new(uint256.Uint256).FromUint64(fee64) + if err != nil { + t.Fatal(err) + } + utxo1 := makeVSWithValueFee(t, ownerSigner, 1, value, fee) + txin1, err := utxo1.MakeTxIn() + if err != nil { + t.Fatal(err) + } + err = utxo1.valueStore.Sign(txin1, ownerSigner) + if err != nil { + t.Fatal(err) + } + + utxo2 := makeVSWithValueFee(t, ownerSigner, 2, value, fee) + tx.Vin = []*TXIn{txin1, txin1} + tx.Vout = []*TXOut{utxo2} + + _, err = tx.ValidateUnique(nil) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestTxValidateUniqueBad4(t *testing.T) { + tx := &Tx{} + + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + value64 := uint64(10000) + value, err := new(uint256.Uint256).FromUint64(value64) + if err != nil { + t.Fatal(err) + } + fee64 := uint64(0) + fee, err := new(uint256.Uint256).FromUint64(fee64) + if err != nil { + t.Fatal(err) + } + utxo1 := makeVSWithValueFee(t, ownerSigner, 1, value, fee) + txin1, err := utxo1.MakeTxIn() + if err != nil { + t.Fatal(err) + } + err = utxo1.valueStore.Sign(txin1, ownerSigner) + if err != nil { + t.Fatal(err) + } + + utxo2 := makeVSWithValueFee(t, ownerSigner, 2, value, fee) + tx.Vin = []*TXIn{txin1} + tx.Vout = []*TXOut{utxo2, utxo2} + + _, err = tx.ValidateUnique(nil) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestTxValidateDataStoreIndexesGood1(t *testing.T) { + tx := &Tx{} + _, err := tx.ValidateDataStoreIndexes(nil) + if err != nil { + t.Fatal(err) + } +} + +func TestTxValidateDataStoreIndexesGood2(t *testing.T) { + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + index := make([]byte, constants.HashLen) + index[0] = 1 + + fee := uint256.Zero() + rawData := make([]byte, 1) + iat := uint32(1) + numEpochs := uint32(1) + utxo1 := makeDSWithValueFee(t, ownerSigner, 0, rawData, index, iat, numEpochs, fee) + + tx := &Tx{ + Vout: Vout{utxo1}, + } + _, err := tx.ValidateDataStoreIndexes(nil) + if err != nil { + t.Fatal(err) + } +} + +func TestTxValidateDataStoreIndexesBad1(t *testing.T) { + utxo := &TXOut{} + utxo.hasDataStore = true + tx := &Tx{ + Vout: Vout{utxo}, + } + _, err := tx.ValidateDataStoreIndexes(nil) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestTxValidateDataStoreIndexesBad2(t *testing.T) { + ds := &DataStore{} + utxo := &TXOut{} + utxo.NewDataStore(ds) + tx := &Tx{ + Vout: Vout{utxo}, + } + _, err := tx.ValidateDataStoreIndexes(nil) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestTxValidateDataStoreIndexesBad3(t *testing.T) { + ds := &DataStore{} + ds.DSLinker = &DSLinker{} + ds.DSLinker.DSPreImage = &DSPreImage{} + ds.DSLinker.DSPreImage.Index = make([]byte, constants.HashLen) + utxo := &TXOut{} + utxo.NewDataStore(ds) + tx := &Tx{ + Vout: Vout{utxo}, + } + _, err := tx.ValidateDataStoreIndexes(nil) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestTxValidateDataStoreIndexesBad4(t *testing.T) { + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + index := make([]byte, constants.HashLen) + index[0] = 1 + + fee := uint256.Zero() + rawData := make([]byte, 1) + iat := uint32(1) + numEpochs := uint32(1) + utxo1 := makeDSWithValueFee(t, ownerSigner, 0, rawData, index, iat, numEpochs, fee) + + tx := &Tx{ + Vout: Vout{utxo1, utxo1}, + } + _, err := tx.ValidateDataStoreIndexes(nil) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestTxConsumedPreHash(t *testing.T) { + tx := &Tx{} + _, err := tx.ConsumedPreHash() + if err == nil { + t.Fatal("Should raise an error") + } +} + +func TestTxConsumedUTXOID(t *testing.T) { + tx := &Tx{} + _, err := tx.ConsumedUTXOID() + if err == nil { + t.Fatal("Should raise an error") + } +} + +func TestTxGeneratedUTXOID(t *testing.T) { + tx := &Tx{} + _, err := tx.GeneratedUTXOID() + if err == nil { + t.Fatal("Should raise an error") + } +} + +func TestTxGeneratedPreHash(t *testing.T) { + tx := &Tx{} + _, err := tx.GeneratedPreHash() + if err == nil { + t.Fatal("Should raise an error") + } +} + +func TestTxValidateSignature(t *testing.T) { + currentHeight := uint32(1) + refUTXOs := Vout{} + tx := &Tx{} + err := tx.ValidateSignature(currentHeight, refUTXOs) + if err == nil { + t.Fatal("Should raise an error") + } +} + +func TestTxValidatePreSignature(t *testing.T) { + tx := &Tx{} + err := tx.ValidatePreSignature() + if err == nil { + t.Fatal("Should raise an error") + } +} + +func TestTxCallTxHash(t *testing.T) { + tx := &Tx{} + hashTrue := crypto.Hasher([][]byte{}...) + hash, err := tx.TxHash() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(hash, hashTrue) { + t.Fatal("txhashes do not match") + } +} + +func TestTxCallTxHashBad1(t *testing.T) { + txin := &TXIn{} + tx := &Tx{ + Vin: Vin{txin}, + } + _, err := tx.TxHash() + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestTxCallTxHashBad2(t *testing.T) { + utxo := &TXOut{} + tx := &Tx{ + Vout: Vout{utxo}, + } + _, err := tx.TxHash() + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestTxValidateFeesGood1(t *testing.T) { + msg := makeMockStorageGetter() + storage := makeStorage(msg) + + tx := &Tx{} + + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + value64 := uint64(10000) + value, err := new(uint256.Uint256).FromUint64(value64) + if err != nil { + t.Fatal(err) + } + fee64 := uint64(0) + fee, err := new(uint256.Uint256).FromUint64(fee64) + if err != nil { + t.Fatal(err) + } + utxo1 := makeVSWithValueFee(t, ownerSigner, 1, value, fee) + txin1, err := utxo1.MakeTxIn() + if err != nil { + t.Fatal(err) + } + + utxo2 := makeVSWithValueFee(t, ownerSigner, 2, value, fee) + tx.Vin = []*TXIn{txin1} + tx.Vout = []*TXOut{utxo2} + + err = tx.ValidateFees(0, nil, storage) + if err != nil { + t.Fatal(err) + } +} + +func TestTxValidateFeesGood2(t *testing.T) { + tx := &Tx{} + + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + value64 := uint64(10000) + value, err := new(uint256.Uint256).FromUint64(value64) + if err != nil { + t.Fatal(err) + } + fee64 := uint64(0) + fee, err := new(uint256.Uint256).FromUint64(fee64) + if err != nil { + t.Fatal(err) + } + utxo1 := makeVSWithValueFee(t, ownerSigner, 1, value, fee) + txin1, err := utxo1.MakeTxIn() + if err != nil { + t.Fatal(err) + } + + utxo2 := makeVSWithValueFee(t, ownerSigner, 2, value, fee) + tx.Vin = []*TXIn{txin1} + tx.Vout = []*TXOut{utxo2} + + msg := makeMockStorageGetter() + minTxFee := big.NewInt(1) + msg.SetMinTxFee(minTxFee) + storage := makeStorage(msg) + err = tx.ValidateFees(0, nil, storage) + if err != nil { + t.Fatal(err) + } +} + +func TestTxValidateFeesBad1(t *testing.T) { + msg := makeMockStorageGetter() + storage := makeStorage(msg) + + tx := &Tx{} + err := tx.ValidateFees(0, nil, storage) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestTxValidateFeesBad2(t *testing.T) { + txin := &TXIn{} + utxo := &TXOut{} + tx := &Tx{ + Vin: []*TXIn{txin}, + Vout: []*TXOut{utxo}, + } + err := tx.ValidateFees(0, nil, nil) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestTxValidateFeesBad3(t *testing.T) { + tx := &Tx{} + + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + value64 := uint64(10000) + value, err := new(uint256.Uint256).FromUint64(value64) + if err != nil { + t.Fatal(err) + } + fee64 := uint64(0) + fee, err := new(uint256.Uint256).FromUint64(fee64) + if err != nil { + t.Fatal(err) + } + utxo1 := makeVSWithValueFee(t, ownerSigner, 1, value, fee) + txin1, err := utxo1.MakeTxIn() + if err != nil { + t.Fatal(err) + } + + txf1 := &TxFee{} + chainID := uint32(1) + txf1.New(chainID, value) + utxo1.NewTxFee(txf1) + txf2 := &TxFee{} + txf2.New(chainID, fee) + utxo2 := &TXOut{} + utxo2.NewTxFee(txf2) + + tx.Vin = []*TXIn{txin1} + tx.Vout = []*TXOut{utxo1, utxo2} + + msg := makeMockStorageGetter() + storage := makeStorage(msg) + err = tx.ValidateFees(0, nil, storage) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestTxValidateFeesBad4(t *testing.T) { + tx := &Tx{} + + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + value64 := uint64(10000) + value, err := new(uint256.Uint256).FromUint64(value64) + if err != nil { + t.Fatal(err) + } + fee64 := uint64(0) + fee, err := new(uint256.Uint256).FromUint64(fee64) + if err != nil { + t.Fatal(err) + } + utxo1 := makeVSWithValueFee(t, ownerSigner, 1, value, fee) + txin1, err := utxo1.MakeTxIn() + if err != nil { + t.Fatal(err) + } + + txf1 := &TxFee{} + chainID := uint32(1) + zero := new(uint256.Uint256) + txf1.New(chainID, zero) + utxo1.NewTxFee(txf1) + + tx.Vin = []*TXIn{txin1} + tx.Vout = []*TXOut{utxo1} + + msg := makeMockStorageGetter() + storage := makeStorage(msg) + err = tx.ValidateFees(0, nil, storage) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestTxValidateFeesBad5(t *testing.T) { + tx := &Tx{} + + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + value64 := uint64(10000) + value, err := new(uint256.Uint256).FromUint64(value64) + if err != nil { + t.Fatal(err) + } + fee64 := uint64(0) + fee, err := new(uint256.Uint256).FromUint64(fee64) + if err != nil { + t.Fatal(err) + } + utxo1 := makeVSWithValueFee(t, ownerSigner, 1, value, fee) + txin1, err := utxo1.MakeTxIn() + if err != nil { + t.Fatal(err) + } + + txf1 := &TxFee{} + chainID := uint32(1) + one := uint256.One() + txf1.New(chainID, one) + utxo1.NewTxFee(txf1) + + tx.Vin = []*TXIn{txin1} + tx.Vout = []*TXOut{utxo1} + + msg := makeMockStorageGetter() + minFeeBig := big.NewInt(2) + msg.SetMinTxFee(minFeeBig) + storage := makeStorage(msg) + err = tx.ValidateFees(0, nil, storage) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestTxIsCleanupTxBad1(t *testing.T) { + // Invalid Tx + tx := &Tx{} + currentHeight := uint32(0) + refUTXOs := Vout{} + cleanup := tx.IsCleanupTx(currentHeight, refUTXOs) + if cleanup { + t.Fatal("Should not be CleanupTx") + } +} + +func TestTxIsCleanupTxBad2(t *testing.T) { + // Invalid Vin; no DataStore + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + value64 := uint64(10000) + value, err := new(uint256.Uint256).FromUint64(value64) + if err != nil { + t.Fatal(err) + } + fee64 := uint64(0) + fee, err := new(uint256.Uint256).FromUint64(fee64) + if err != nil { + t.Fatal(err) + } + utxo1 := makeVSWithValueFee(t, ownerSigner, 1, value, fee) + txin1, err := utxo1.MakeTxIn() + if err != nil { + t.Fatal(err) + } + + // Invalid Vin; not DataStore + vin := []*TXIn{txin1} + refUTXOs := []*TXOut{utxo1} + tx := &Tx{ + Vin: vin, + Vout: Vout{}, + } + currentHeight := uint32(1) + cleanup := tx.IsCleanupTx(currentHeight, refUTXOs) + if cleanup { + t.Fatal("Should not be CleanupTx") + } +} + +func TestTxIsCleanupTxBad3(t *testing.T) { + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + index := make([]byte, constants.HashLen) + index[0] = 1 + + fee := uint256.Zero() + rawData := make([]byte, 1) + iat := uint32(1) + numEpochs := uint32(1) + utxo1 := makeDSWithValueFee(t, ownerSigner, 0, rawData, index, iat, numEpochs, fee) + txin1, err := utxo1.MakeTxIn() + if err != nil { + t.Fatal(err) + } + + // Invalid Vin; DataStore not expired + vin := []*TXIn{txin1} + refUTXOs := []*TXOut{utxo1} + tx := &Tx{ + Vin: vin, + Vout: Vout{}, + } + currentHeight := uint32(1) + cleanup := tx.IsCleanupTx(currentHeight, refUTXOs) + if cleanup { + t.Fatal("Should not be CleanupTx") + } +} + +func TestTxIsCleanupTxBad4(t *testing.T) { + // Must have valid Vin and invalid Vout (not present) + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + index := make([]byte, constants.HashLen) + index[0] = 1 + + fee := uint256.Zero() + rawData := make([]byte, 1) + iat := uint32(1) + numEpochs := uint32(1) + utxo1 := makeDSWithValueFee(t, ownerSigner, 0, rawData, index, iat, numEpochs, fee) + txin1, err := utxo1.MakeTxIn() + if err != nil { + t.Fatal(err) + } + + vin := []*TXIn{txin1} + refUTXOs := []*TXOut{utxo1} + tx := &Tx{ + Vin: vin, + Vout: Vout{}, + } + currentHeight := constants.EpochLength*(iat+numEpochs) + 1 + cleanup := tx.IsCleanupTx(currentHeight, refUTXOs) + if cleanup { + t.Fatal("Should not be CleanupTx") + } +} + +func TestTxIsCleanupTxBad5(t *testing.T) { + // Must have valid Vin and invalid Vout (incorrect utxo type) + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + index := make([]byte, constants.HashLen) + index[0] = 1 + + fee := uint256.Zero() + rawData := make([]byte, 1) + iat := uint32(1) + numEpochs := uint32(1) + utxo1 := makeDSWithValueFee(t, ownerSigner, 0, rawData, index, iat, numEpochs, fee) + txin1, err := utxo1.MakeTxIn() + if err != nil { + t.Fatal(err) + } + + utxo2 := &TXOut{} + ds := &DataStore{} + utxo2.NewDataStore(ds) + + vin := []*TXIn{txin1} + refUTXOs := []*TXOut{utxo1} + vout := Vout{utxo2} + tx := &Tx{ + Vin: vin, + Vout: vout, + } + currentHeight := constants.EpochLength*(iat+numEpochs) + 1 + cleanup := tx.IsCleanupTx(currentHeight, refUTXOs) + if cleanup { + t.Fatal("Should not be CleanupTx") + } +} + +func TestTxIsCleanupTxBad6(t *testing.T) { + // Must have valid Vin and invalid Vout (bad ValueStore) + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + index := make([]byte, constants.HashLen) + index[0] = 1 + + fee := uint256.Zero() + rawData := make([]byte, 1) + iat := uint32(1) + numEpochs := uint32(1) + utxo1 := makeDSWithValueFee(t, ownerSigner, 0, rawData, index, iat, numEpochs, fee) + txin1, err := utxo1.MakeTxIn() + if err != nil { + t.Fatal(err) + } + + utxo2 := &TXOut{} + vs := &ValueStore{} + utxo2.NewValueStore(vs) + + vin := []*TXIn{txin1} + refUTXOs := []*TXOut{utxo1} + vout := Vout{utxo2} + tx := &Tx{ + Vin: vin, + Vout: vout, + } + currentHeight := constants.EpochLength*(iat+numEpochs) + 1 + cleanup := tx.IsCleanupTx(currentHeight, refUTXOs) + if cleanup { + t.Fatal("Should not be CleanupTx") + } +} + +func TestTxIsCleanupTxBad7(t *testing.T) { + // Must have valid Vin and invalid Vout (bad ValueStore) + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + index := make([]byte, constants.HashLen) + index[0] = 1 + + fee := uint256.Zero() + rawData := make([]byte, 1) + iat := uint32(1) + numEpochs := uint32(1) + utxo1 := makeDSWithValueFee(t, ownerSigner, 0, rawData, index, iat, numEpochs, fee) + txin1, err := utxo1.MakeTxIn() + if err != nil { + t.Fatal(err) + } + + value := uint256.One() + vsFee := uint256.One() + utxo2 := makeVSWithValueFee(t, ownerSigner, 0, value, vsFee) + + vin := []*TXIn{txin1} + refUTXOs := []*TXOut{utxo1} + vout := Vout{utxo2} + tx := &Tx{ + Vin: vin, + Vout: vout, + } + currentHeight := constants.EpochLength*(iat+numEpochs) + 1 + cleanup := tx.IsCleanupTx(currentHeight, refUTXOs) + if cleanup { + t.Fatal("Should not be CleanupTx") + } +} + +func TestTxIsCleanupTxGood1(t *testing.T) { + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + fee := uint256.Zero() + index := make([]byte, constants.HashLen) + index[0] = 1 + rawData := make([]byte, 1) + iat := uint32(1) + numEpochs := uint32(1) + utxo1 := makeDSWithValueFee(t, ownerSigner, 0, rawData, index, iat, numEpochs, fee) + txin1, err := utxo1.MakeTxIn() + if err != nil { + t.Fatal(err) + } + + // Compute remainingValue to have correct ValueStore + currentHeight := constants.EpochLength*(iat+numEpochs) + 1 + remainingValue, err := utxo1.RemainingValue(currentHeight) + if err != nil { + t.Fatal(err) + } + utxo2 := makeVSWithValueFee(t, ownerSigner, 1, remainingValue, fee) + + vin := []*TXIn{txin1} + refUTXOs := []*TXOut{utxo1} + vout := []*TXOut{utxo2} + tx := &Tx{ + Vin: vin, + Vout: vout, + } + cleanup := tx.IsCleanupTx(currentHeight, refUTXOs) + if !cleanup { + t.Fatal("Should be valid CleanupTx") + } +} + +func TestTxIsCleanupTxGood2(t *testing.T) { + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + fee := uint256.Zero() + index1 := make([]byte, constants.HashLen) + index1[0] = 1 + rawData1 := make([]byte, 1) + iat := uint32(1) + numEpochs := uint32(1) + utxo1 := makeDSWithValueFee(t, ownerSigner, 0, rawData1, index1, iat, numEpochs, fee) + txin1, err := utxo1.MakeTxIn() + if err != nil { + t.Fatal(err) + } + + index2 := make([]byte, constants.HashLen) + index2[0] = 2 + rawData2 := make([]byte, 100) + utxo2 := makeDSWithValueFee(t, ownerSigner, 0, rawData2, index2, iat, numEpochs, fee) + txin2, err := utxo2.MakeTxIn() + if err != nil { + t.Fatal(err) + } + + // Compute remainingValue to have correct ValueStore + currentHeight := constants.EpochLength*(iat+numEpochs) + 1 + vin := []*TXIn{txin1, txin2} + refUTXOs := Vout{utxo1, utxo2} + remainingValue, err := refUTXOs.RemainingValue(currentHeight) + if err != nil { + t.Fatal(err) + } + utxo3 := makeVSWithValueFee(t, ownerSigner, 1, remainingValue, fee) + + vout := []*TXOut{utxo3} + tx := &Tx{ + Vin: vin, + Vout: vout, + } + cleanup := tx.IsCleanupTx(currentHeight, refUTXOs) + if !cleanup { + t.Fatal("Should be valid CleanupTx") + } +} + +func TestTxIsCleanupTxGood3(t *testing.T) { + // This does a full test of validation logic; + // these fees should not affect the validity of the cleanup transaction + // because no fees apply in this case. + msg := makeMockStorageGetter() + dsFeeBig := big.NewInt(100) + msg.SetDataStoreEpochFee(dsFeeBig) + vsFeeBig := big.NewInt(1000) + msg.SetValueStoreFee(vsFeeBig) + tfFeeBig := big.NewInt(10000) + msg.SetMinTxFee(tfFeeBig) + msg.SetDataStoreEpochFee(dsFeeBig) + storage := makeStorage(msg) + + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + dsFee, err := new(uint256.Uint256).FromBigInt(dsFeeBig) + if err != nil { + t.Fatal(err) + } + index1 := make([]byte, constants.HashLen) + index1[0] = 1 + rawData1 := make([]byte, 1) + iat := uint32(1) + numEpochs := uint32(3) + utxo1 := makeDSWithValueFee(t, ownerSigner, 0, rawData1, index1, iat, numEpochs, dsFee) + idx := uint32(0) + err = utxo1.SetTXOutIdx(idx) + if err != nil { + t.Fatal(err) + } + txin1, err := utxo1.MakeTxIn() + if err != nil { + t.Fatal(err) + } + err = utxo1.dataStore.Sign(txin1, ownerSigner) + if err != nil { + t.Fatal(err) + } + + index2 := make([]byte, constants.HashLen) + index2[0] = 2 + rawData2 := make([]byte, 2) + utxo2 := makeDSWithValueFee(t, ownerSigner, 0, rawData2, index2, iat, numEpochs, dsFee) + idx = uint32(1) + err = utxo2.SetTXOutIdx(idx) + if err != nil { + t.Fatal(err) + } + txin2, err := utxo2.MakeTxIn() + if err != nil { + t.Fatal(err) + } + err = utxo2.dataStore.Sign(txin2, ownerSigner) + if err != nil { + t.Fatal(err) + } + + index3 := make([]byte, constants.HashLen) + index3[0] = 3 + rawData3 := make([]byte, 3) + utxo3 := makeDSWithValueFee(t, ownerSigner, 0, rawData3, index3, iat, numEpochs, dsFee) + idx = uint32(2) + err = utxo3.SetTXOutIdx(idx) + if err != nil { + t.Fatal(err) + } + txin3, err := utxo3.MakeTxIn() + if err != nil { + t.Fatal(err) + } + err = utxo3.dataStore.Sign(txin3, ownerSigner) + if err != nil { + t.Fatal(err) + } + + // Compute remainingValue to have correct ValueStore + cleanupFee := uint256.Zero() + currentHeight := constants.EpochLength*(iat+numEpochs) + 1 + vin := []*TXIn{txin1, txin2, txin3} + refUTXOs := Vout{utxo1, utxo2, utxo3} + remainingValue, err := refUTXOs.RemainingValue(currentHeight) + if err != nil { + t.Fatal(err) + } + utxo4 := makeVSWithValueFee(t, ownerSigner, 1, remainingValue, cleanupFee) + + vout := []*TXOut{utxo4} + tx := &Tx{ + Vin: vin, + Vout: vout, + } + err = tx.SetTxHash() + if err != nil { + t.Fatal(err) + } + + chainID := uint32(2) + err = tx.PreValidatePending(chainID) + if err != nil { + t.Fatal(err) + } + _, err = tx.Validate(nil, currentHeight, refUTXOs, storage) + if err != nil { + t.Fatal(err) + } + err = tx.PostValidatePending(currentHeight, refUTXOs) + if err != nil { + t.Fatal(err) + } +} + +func TestTxValidateEqualVinVoutBad1(t *testing.T) { + currentHeight := uint32(0) + refUTXOs := Vout{} + tx := &Tx{} + err := tx.ValidateEqualVinVout(currentHeight, refUTXOs) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestTxValidateEqualVinVoutBad2(t *testing.T) { + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + txin := &TXIn{} + utxo := &TXOut{} + + currentHeight := uint32(1) + refUTXOs := Vout{} + tx := &Tx{ + Vin: Vin{txin}, + Vout: Vout{utxo}, + } + err := tx.ValidateEqualVinVout(currentHeight, refUTXOs) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestTxValidateEqualVinVoutBad3(t *testing.T) { + ownerSigner := &crypto.Secp256k1Signer{} + if err := ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))); err != nil { + t.Fatal(err) + } + + txin := &TXIn{} + utxo := &TXOut{} + vs := &ValueStore{} + zero := uint256.Zero() + one := uint256.One() + vs.VSPreImage = &VSPreImage{} + vs.VSPreImage.Value = one.Clone() + vs.VSPreImage.Fee = zero.Clone() + err := utxo.NewValueStore(vs) + if err != nil { + t.Fatal(err) + } + + currentHeight := uint32(1) + tx := &Tx{ + Vin: Vin{txin}, + Vout: Vout{utxo}, + } + err = tx.ValidateEqualVinVout(currentHeight, nil) + if err == nil { + t.Fatal("Should have raised error") } } diff --git a/application/objs/txfee/txfee.go b/application/objs/txfee/txfee.go new file mode 100644 index 00000000..8df6bade --- /dev/null +++ b/application/objs/txfee/txfee.go @@ -0,0 +1,55 @@ +package txfee + +import ( + mdefs "github.com/MadBase/MadNet/application/objs/capn" + "github.com/MadBase/MadNet/constants" + "github.com/MadBase/MadNet/errorz" + "github.com/MadBase/MadNet/utils" + capnp "zombiezen.com/go/capnproto2" +) + +// Marshal will marshal the TxFee object. +func Marshal(v mdefs.TxFee) ([]byte, error) { + raw, err := capnp.Canonicalize(v.Struct) + if err != nil { + return nil, err + } + out := utils.CopySlice(raw) + return out, nil +} + +// Unmarshal will unmarshal the TxFee object. +func Unmarshal(data []byte) (mdefs.TxFee, error) { + var err error + fn := func() (mdefs.TxFee, error) { + defer func() { + if r := recover(); r != nil { + err = errorz.ErrInvalid{}.New("bad serialization") + } + }() + dataCopy := utils.CopySlice(data) + msg := &capnp.Message{Arena: capnp.SingleSegment(dataCopy)} + obj, tmp := mdefs.ReadRootTxFee(msg) + err = tmp + return obj, err + } + obj, err := fn() + if err != nil { + return mdefs.TxFee{}, err + } + return obj, nil +} + +// Validate will validate the TxFee object +func Validate(v mdefs.TxFee) error { + if !v.HasTFPreImage() { + return errorz.ErrInvalid{}.New("txfee capn obj does not have TFPreImage") + } + if !v.HasTxHash() { + return errorz.ErrInvalid{}.New("txfee capn obj does not have TxHash") + } + if len(v.TxHash()) != constants.HashLen { + return errorz.ErrInvalid{}.New("txfee capn obj is not valid: invalid TxHash; incorrect byte length") + } + return nil +} diff --git a/application/objs/txin.go b/application/objs/txin.go index 3ddb552c..49c0cc23 100644 --- a/application/objs/txin.go +++ b/application/objs/txin.go @@ -117,7 +117,7 @@ func (b *TXIn) TxHash() ([]byte, error) { if b == nil || b.TXInLinker == nil || len(b.TXInLinker.TxHash) != constants.HashLen { return nil, errorz.ErrInvalid{}.New("not initialized") } - return b.TXInLinker.TxHash, nil + return utils.CopySlice(b.TXInLinker.TxHash), nil } // SetTxHash sets the TxHash of the TXIn object diff --git a/application/objs/txin_test.go b/application/objs/txin_test.go index 213c3a40..ade81894 100644 --- a/application/objs/txin_test.go +++ b/application/objs/txin_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/MadBase/MadNet/constants" + "github.com/MadBase/MadNet/utils" ) func TestTXInGood(t *testing.T) { @@ -160,6 +161,16 @@ func TestTXInTxHash(t *testing.T) { if err == nil { t.Fatal("Should raise an error (2)") } + + txHashTrue := make([]byte, constants.HashLen) + txIn.TXInLinker.TxHash = utils.CopySlice(txHashTrue) + txHash, err := txIn.TxHash() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(txHash, txHashTrue) { + t.Fatal("TxHashes do not match") + } } func TestTXInSetTxHash(t *testing.T) { @@ -170,17 +181,22 @@ func TestTXInSetTxHash(t *testing.T) { t.Fatal("Should raise an error (1)") } - txHash := make([]byte, constants.HashLen) - err = txIn.SetTxHash(txHash) + txIn.TXInLinker = &TXInLinker{} + err = txIn.SetTxHash(txHashBad) if err == nil { t.Fatal("Should raise an error (2)") } - txIn.TXInLinker = &TXInLinker{} + txHash := make([]byte, constants.HashLen) err = txIn.SetTxHash(txHash) if err == nil { t.Fatal("Should raise an error (3)") } + + err = txIn.SetTxHash(txHash) + if err == nil { + t.Fatal("Should raise an error (4)") + } } func TestTXInChainID(t *testing.T) { diff --git a/application/objs/txinl.go b/application/objs/txinl.go index 1d080a13..b35cff7b 100644 --- a/application/objs/txinl.go +++ b/application/objs/txinl.go @@ -145,5 +145,5 @@ func (b *TXInLinker) ConsumedTxHash() ([]byte, error) { if b == nil || b.TXInPreImage == nil || len(b.TXInPreImage.ConsumedTxHash) != constants.HashLen { return nil, errorz.ErrInvalid{}.New("not initialized") } - return b.TXInPreImage.ConsumedTxHash, nil + return utils.CopySlice(b.TXInPreImage.ConsumedTxHash), nil } diff --git a/application/objs/txinl_test.go b/application/objs/txinl_test.go index a47c1777..3f7bc794 100644 --- a/application/objs/txinl_test.go +++ b/application/objs/txinl_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/MadBase/MadNet/constants" + "github.com/MadBase/MadNet/utils" ) func TestTXInLinkerGood(t *testing.T) { @@ -175,6 +176,22 @@ func TestTXInLinkerChainID(t *testing.T) { if err == nil { t.Fatal("Should raise an error (2)") } + + txinl.TXInPreImage = &TXInPreImage{} + _, err = txinl.ChainID() + if err == nil { + t.Fatal("Should raise an error (3)") + } + + chainID := uint32(17) + txinl.TXInPreImage.ChainID = chainID + retChainID, err := txinl.ChainID() + if err != nil { + t.Fatal(err) + } + if retChainID != chainID { + t.Fatal("ChainIDs do not match") + } } func TestTXInLinkerSetTxHash(t *testing.T) { @@ -191,18 +208,18 @@ func TestTXInLinkerSetTxHash(t *testing.T) { t.Fatal("Should raise an error (2)") } - txHash := make([]byte, constants.HashLen) - err = txin.TXInLinker.SetTxHash(txHash) + txinl.TXInPreImage = &TXInPreImage{} + err = txinl.SetTxHash(txHashBad) if err == nil { t.Fatal("Should raise an error (3)") } - err = txinl.SetTxHash(txHash) + txHash := make([]byte, constants.HashLen) + err = txin.TXInLinker.SetTxHash(txHash) if err == nil { t.Fatal("Should raise an error (4)") } - txinl.TXInPreImage = &TXInPreImage{} err = txinl.SetTxHash(txHash) if err != nil { t.Fatal("Should not raise an error") @@ -221,6 +238,17 @@ func TestTXInLinkerConsumedTxIdx(t *testing.T) { if err == nil { t.Fatal("Should raise an error (2)") } + + consumedTxIdx := uint32(25519) + txinl.TXInPreImage = &TXInPreImage{} + txinl.TXInPreImage.ConsumedTxIdx = consumedTxIdx + txIdx, err := txinl.ConsumedTxIdx() + if err != nil { + t.Fatal(err) + } + if txIdx != consumedTxIdx { + t.Fatal("ConsumedTxIdxes do not match") + } } func TestTXInLinkerConsumedTxHash(t *testing.T) { @@ -235,4 +263,15 @@ func TestTXInLinkerConsumedTxHash(t *testing.T) { if err == nil { t.Fatal("Should raise an error (2)") } + + txhashTrue := make([]byte, constants.HashLen) + txinl.TXInPreImage = &TXInPreImage{} + txinl.TXInPreImage.ConsumedTxHash = utils.CopySlice(txhashTrue) + txhash, err := txinl.ConsumedTxHash() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(txhash, txhashTrue) { + t.Fatal("ConsumedTxHashes do not match") + } } diff --git a/application/objs/txvec.go b/application/objs/txvec.go index 071e1d59..12160020 100644 --- a/application/objs/txvec.go +++ b/application/objs/txvec.go @@ -1,5 +1,10 @@ package objs +import ( + "github.com/MadBase/MadNet/application/wrapper" + "github.com/MadBase/MadNet/constants" +) + // TxVec is a vector of transactions Tx type TxVec []*Tx @@ -67,10 +72,10 @@ func (txv TxVec) PreValidateApplyState(chainID uint32) error { } // Validate ... -func (txv TxVec) Validate(currentHeight uint32, consumedUTXOs Vout) error { +func (txv TxVec) Validate(currentHeight uint32, consumedUTXOs Vout, storage *wrapper.Storage) error { set := make(map[string]bool) - voutMap := make(map[[32]byte]*TXOut) - var key [32]byte + voutMap := make(map[[constants.HashLen]byte]*TXOut) + var key [constants.HashLen]byte for i := 0; i < len(consumedUTXOs); i++ { utxoID, err := consumedUTXOs[i].UTXOID() if err != nil { @@ -89,7 +94,7 @@ func (txv TxVec) Validate(currentHeight uint32, consumedUTXOs Vout) error { copy(key[:], utxoIDs[j]) utxoSet[j] = voutMap[key] } - if set, err = txv[i].Validate(set, currentHeight, utxoSet); err != nil { + if set, err = txv[i].Validate(set, currentHeight, utxoSet, storage); err != nil { return err } } diff --git a/application/objs/uint256/uint256.go b/application/objs/uint256/uint256.go index edbbf7df..9939cd83 100644 --- a/application/objs/uint256/uint256.go +++ b/application/objs/uint256/uint256.go @@ -146,6 +146,16 @@ func (u *Uint256) FromBigInt(a *big.Int) (*Uint256, error) { return u.Clone(), nil } +// ToBigInt converts Uint256 into big.Int +func (u *Uint256) ToBigInt() (*big.Int, error) { + buf, err := u.MarshalBinary() + if err != nil { + return nil, err + } + a := new(big.Int).SetBytes(buf) + return a, nil +} + // FromUint64 converts a uint64 into Uint256 func (u *Uint256) FromUint64(a uint64) (*Uint256, error) { buf := utils.MarshalUint64(a) @@ -386,6 +396,18 @@ func (u *Uint256) SetZero() *Uint256 { return u.Clone() } +// IsZero determines if u is 0 +func (u *Uint256) IsZero() bool { + if u.val == nil { + u.val = &uint256.Int{} + } + z := new(Uint256).SetZero() + if u.Eq(z) { + return true + } + return false +} + // DSPIMinDeposit returns constants.DSPIMinDeposit as Uint256 func DSPIMinDeposit() *Uint256 { u, _ := new(Uint256).FromUint64(uint64(constants.DSPIMinDeposit)) diff --git a/application/objs/uint256/uint256_test.go b/application/objs/uint256/uint256_test.go index be2840f4..3d0eef81 100644 --- a/application/objs/uint256/uint256_test.go +++ b/application/objs/uint256/uint256_test.go @@ -469,6 +469,46 @@ func TestUint256FromBigInt(t *testing.T) { } } +func TestUint256ToBigInt(t *testing.T) { + u := &Uint256{} + _, err := u.ToBigInt() + if err == nil { + t.Fatal("Should have raised error (1)") + } + + u.SetZero() + b, err := u.ToBigInt() + if err != nil { + t.Fatal(err) + } + if b.Sign() != 0 { + t.Fatal("b should be 0") + } + + bigOne := new(big.Int).SetUint64(1) + u.SetOne() + b, err = u.ToBigInt() + if err != nil { + t.Fatal(err) + } + if b.Cmp(bigOne) != 0 { + t.Fatal("b should be 1") + } + + big25519 := new(big.Int).SetUint64(25519) + _, err = u.FromUint64(25519) + if err != nil { + t.Fatal(err) + } + b, err = u.ToBigInt() + if err != nil { + t.Fatal(err) + } + if b.Cmp(big25519) != 0 { + t.Fatal("b should be 25519") + } +} + func TestUint256FromUint64(t *testing.T) { obj := &testObj{} _, err := obj.Value.FromUint64(0) @@ -2482,6 +2522,18 @@ func TestUint256Zero(t *testing.T) { } } +func TestUint256IsZero(t *testing.T) { + u := Zero() + if !u.IsZero() { + t.Fatal("IsZero() should return true") + } + + u = One() + if u.IsZero() { + t.Fatal("IsZero() should return false") + } +} + func TestUint256One(t *testing.T) { u := One() uTrue := new(Uint256).SetOne() diff --git a/application/objs/utxo.go b/application/objs/utxo.go index 52591f6e..35c50307 100644 --- a/application/objs/utxo.go +++ b/application/objs/utxo.go @@ -4,6 +4,7 @@ import ( mdefs "github.com/MadBase/MadNet/application/objs/capn" "github.com/MadBase/MadNet/application/objs/uint256" "github.com/MadBase/MadNet/application/objs/utxo" + "github.com/MadBase/MadNet/application/wrapper" "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/errorz" "github.com/MadBase/MadNet/utils" @@ -15,16 +16,18 @@ type TXOut struct { dataStore *DataStore valueStore *ValueStore atomicSwap *AtomicSwap + txFee *TxFee // not part of serialized object below this line hasDataStore bool hasValueStore bool hasAtomicSwap bool + hasTxFee bool } // CreateValueStore makes a new ValueStore -func (b *TXOut) CreateValueStore(chainID uint32, value *uint256.Uint256, acct []byte, curveSpec constants.CurveSpec, txHash []byte) error { +func (b *TXOut) CreateValueStore(chainID uint32, value *uint256.Uint256, fee *uint256.Uint256, acct []byte, curveSpec constants.CurveSpec, txHash []byte) error { vs := &ValueStore{} - err := vs.New(chainID, value, acct, curveSpec, txHash) + err := vs.New(chainID, value, fee, acct, curveSpec, txHash) if err != nil { return err } @@ -46,9 +49,11 @@ func (b *TXOut) NewDataStore(v *DataStore) error { b.hasDataStore = true b.hasValueStore = false b.hasAtomicSwap = false + b.hasTxFee = false b.dataStore = v b.atomicSwap = nil b.valueStore = nil + b.txFee = nil return nil } @@ -57,9 +62,11 @@ func (b *TXOut) NewValueStore(v *ValueStore) error { b.hasDataStore = false b.hasValueStore = true b.hasAtomicSwap = false + b.hasTxFee = false b.dataStore = nil b.valueStore = v b.atomicSwap = nil + b.txFee = nil return nil } @@ -68,9 +75,24 @@ func (b *TXOut) NewAtomicSwap(v *AtomicSwap) error { b.hasDataStore = false b.hasValueStore = false b.hasAtomicSwap = true + b.hasTxFee = false b.dataStore = nil b.valueStore = nil b.atomicSwap = v + b.txFee = nil + return nil +} + +// NewTxFee makes a TXOut object which with the specified TxFee +func (b *TXOut) NewTxFee(v *TxFee) error { + b.hasDataStore = false + b.hasValueStore = false + b.hasAtomicSwap = false + b.hasTxFee = true + b.dataStore = nil + b.valueStore = nil + b.atomicSwap = nil + b.txFee = v return nil } @@ -98,6 +120,14 @@ func (b *TXOut) HasAtomicSwap() bool { return b.hasAtomicSwap } +// HasTxFee specifies if the TXOut object has a TxFee +func (b *TXOut) HasTxFee() bool { + if b == nil { + return false + } + return b.hasTxFee +} + // DataStore returns the DataStore of the TXOut object if it exists func (b *TXOut) DataStore() (*DataStore, error) { if b.HasDataStore() { @@ -119,7 +149,15 @@ func (b *TXOut) AtomicSwap() (*AtomicSwap, error) { if b.HasAtomicSwap() { return b.atomicSwap, nil } - return nil, errorz.ErrInvalid{}.New("object does not have a AtomicSwap") + return nil, errorz.ErrInvalid{}.New("object does not have an AtomicSwap") +} + +// TxFee returns the TxFee of the TXOut object if it exists +func (b *TXOut) TxFee() (*TxFee, error) { + if b.HasTxFee() { + return b.txFee, nil + } + return nil, errorz.ErrInvalid{}.New("object does not have a TxFee") } // UnmarshalBinary takes a byte slice and returns the corresponding @@ -160,6 +198,12 @@ func (b *TXOut) UnmarshalCapn(bc mdefs.TXOut) error { } b.dataStore = obj b.hasDataStore = true + b.valueStore = nil + b.hasValueStore = false + b.atomicSwap = nil + b.hasAtomicSwap = false + b.txFee = nil + b.hasTxFee = false case bc.HasValueStore(): cObj, err := bc.ValueStore() if err != nil { @@ -170,8 +214,14 @@ func (b *TXOut) UnmarshalCapn(bc mdefs.TXOut) error { if err != nil { return err } + b.dataStore = nil + b.hasDataStore = false b.valueStore = obj b.hasValueStore = true + b.atomicSwap = nil + b.hasAtomicSwap = false + b.txFee = nil + b.hasTxFee = false case bc.HasAtomicSwap(): cObj, err := bc.AtomicSwap() if err != nil { @@ -182,8 +232,32 @@ func (b *TXOut) UnmarshalCapn(bc mdefs.TXOut) error { if err != nil { return err } + b.dataStore = nil + b.hasDataStore = false + b.valueStore = nil + b.hasValueStore = false b.atomicSwap = obj b.hasAtomicSwap = true + b.txFee = nil + b.hasTxFee = false + case bc.HasTxFee(): + cObj, err := bc.TxFee() + if err != nil { + return err + } + obj := &TxFee{} + err = obj.UnmarshalCapn(cObj) + if err != nil { + return err + } + b.dataStore = nil + b.hasDataStore = false + b.valueStore = nil + b.hasValueStore = false + b.atomicSwap = nil + b.hasAtomicSwap = false + b.txFee = obj + b.hasTxFee = true default: return errorz.ErrInvalid{}.New("TXOut type not defined in UnmarshalCapn") } @@ -239,6 +313,14 @@ func (b *TXOut) MarshalCapn(seg *capnp.Segment) (mdefs.TXOut, error) { if err := bc.SetAtomicSwap(as); err != nil { return bc, err } + case b.hasTxFee: + tf, err := b.txFee.MarshalCapn(seg) + if err != nil { + return bc, err + } + if err := bc.SetTxFee(tf); err != nil { + return bc, err + } default: return mdefs.TXOut{}, errorz.ErrInvalid{}.New("TXOut type not defined in MarshalCapn") } @@ -257,6 +339,9 @@ func (b *TXOut) PreHash() ([]byte, error) { case b.HasAtomicSwap(): obj, _ := b.AtomicSwap() return obj.PreHash() + case b.HasTxFee(): + obj, _ := b.TxFee() + return obj.PreHash() default: return nil, errorz.ErrInvalid{}.New("TXOut type not defined in PreHash") } @@ -274,6 +359,9 @@ func (b *TXOut) UTXOID() ([]byte, error) { case b.HasAtomicSwap(): obj, _ := b.AtomicSwap() return obj.UTXOID() + case b.HasTxFee(): + obj, _ := b.TxFee() + return obj.UTXOID() default: return nil, errorz.ErrInvalid{}.New("TXOut type not defined in UTXOID") } @@ -291,6 +379,9 @@ func (b *TXOut) ChainID() (uint32, error) { case b.HasAtomicSwap(): obj, _ := b.AtomicSwap() return obj.ChainID() + case b.HasTxFee(): + obj, _ := b.TxFee() + return obj.ChainID() default: return 0, errorz.ErrInvalid{}.New("TXOut type not defined for ChainID") } @@ -308,6 +399,9 @@ func (b *TXOut) TXOutIdx() (uint32, error) { case b.HasAtomicSwap(): obj, _ := b.AtomicSwap() return obj.TXOutIdx() + case b.HasTxFee(): + obj, _ := b.TxFee() + return obj.TXOutIdx() default: return 0, errorz.ErrInvalid{}.New("TXOut type not defined in TXOutIdx") } @@ -325,6 +419,9 @@ func (b *TXOut) SetTXOutIdx(idx uint32) error { case b.HasAtomicSwap(): obj, _ := b.AtomicSwap() return obj.SetTXOutIdx(idx) + case b.HasTxFee(): + obj, _ := b.TxFee() + return obj.SetTXOutIdx(idx) default: return errorz.ErrInvalid{}.New("TXOut type not defined in SetTXOutIdx") } @@ -352,6 +449,12 @@ func (b *TXOut) TxHash() ([]byte, error) { return nil, errorz.ErrInvalid{}.New("not initialized") } return utils.CopySlice(obj.TxHash), nil + case b.HasTxFee(): + obj, _ := b.TxFee() + if obj == nil || len(obj.TxHash) != constants.HashLen { + return nil, errorz.ErrInvalid{}.New("not initialized") + } + return utils.CopySlice(obj.TxHash), nil default: return nil, errorz.ErrInvalid{}.New("TXOut type not defined in TxHash") } @@ -369,11 +472,30 @@ func (b *TXOut) SetTxHash(txHash []byte) error { case b.HasAtomicSwap(): obj, _ := b.AtomicSwap() return obj.SetTxHash(utils.CopySlice(txHash)) + case b.HasTxFee(): + obj, _ := b.TxFee() + return obj.SetTxHash(utils.CopySlice(txHash)) default: return errorz.ErrInvalid{}.New("TXOut type not defined in SetTxHash") } } +// IsExpired returns true if the utxo has expired +func (b *TXOut) IsExpired(currentHeight uint32) (bool, error) { + switch { + case b.HasDataStore(): + obj, _ := b.DataStore() + return obj.IsExpired(currentHeight) + case b.HasValueStore(): + return false, nil + case b.HasAtomicSwap(): + obj, _ := b.AtomicSwap() + return obj.IsExpired(currentHeight) + default: + return false, errorz.ErrInvalid{}.New("TXOut type not defined in IsExpired") + } +} + // RemainingValue returns the remaining value after discount func (b *TXOut) RemainingValue(currentHeight uint32) (*uint256.Uint256, error) { switch { @@ -421,7 +543,51 @@ func (b *TXOut) Value() (*uint256.Uint256, error) { obj, _ := b.AtomicSwap() return obj.Value() default: - return nil, errorz.ErrInvalid{}.New("TXOut type not defined in Next") + return nil, errorz.ErrInvalid{}.New("TXOut type not defined in Value") + } +} + +// ValuePlusFee returns the Value of the object plus the associated fee +func (b *TXOut) ValuePlusFee() (*uint256.Uint256, error) { + switch { + case b.HasDataStore(): + obj, _ := b.DataStore() + return obj.ValuePlusFee() + case b.HasValueStore(): + obj, _ := b.ValueStore() + return obj.ValuePlusFee() + case b.HasAtomicSwap(): + obj, _ := b.AtomicSwap() + return obj.ValuePlusFee() + case b.HasTxFee(): + // We return the fee because ValuePlusFee is called to calculate + // the total value out of the Tx; this must include TxFee. + obj, _ := b.TxFee() + return obj.Fee() + default: + return nil, errorz.ErrInvalid{}.New("TXOut type not defined in ValuePlusFee") + } +} + +// ValidateFee validates the Fee of the object +func (b *TXOut) ValidateFee(storage *wrapper.Storage) error { + switch { + case b.HasDataStore(): + obj, _ := b.DataStore() + return obj.ValidateFee(storage) + case b.HasValueStore(): + obj, _ := b.ValueStore() + return obj.ValidateFee(storage) + case b.HasAtomicSwap(): + obj, _ := b.AtomicSwap() + return obj.ValidateFee(storage) + case b.HasTxFee(): + // We cannot validate the total transaction fee here because + // we must look at the *entire* Tx object to ensure at most one TxFee + // UTXO is present + return nil + default: + return errorz.ErrInvalid{}.New("TXOut type not defined in ValidateFee") } } @@ -435,6 +601,8 @@ func (b *TXOut) ValidatePreSignature() error { return nil case b.HasAtomicSwap(): return nil + case b.HasTxFee(): + return nil default: return errorz.ErrInvalid{}.New("TXOut type not defined in ValidatePreSignature") } @@ -452,6 +620,8 @@ func (b *TXOut) ValidateSignature(currentHeight uint32, txIn *TXIn) error { case b.HasAtomicSwap(): obj, _ := b.AtomicSwap() return obj.ValidateSignature(currentHeight, txIn) + case b.HasTxFee(): + return nil default: return errorz.ErrInvalid{}.New("TXOut type not defined in ValidateSignature") } @@ -476,6 +646,8 @@ func (b *TXOut) MustBeMinedBeforeHeight() (uint32, error) { return 0, err } return (iat * constants.EpochLength) - 1, nil + case b.HasTxFee(): + return constants.MaxUint32, nil default: return 0, errorz.ErrInvalid{}.New("TXOut type not defined in MustBeMinedBeforeHeight") } @@ -490,9 +662,6 @@ func (b *TXOut) CannotBeMinedBeforeHeight() (uint32, error) { if err != nil { return 0, err } - if iat == 0 { - return 0, errorz.ErrInvalid{}.New("invalid IssuedAt in utxo") - } return (iat-1)*constants.EpochLength + 1, nil case b.HasValueStore(): return 1, nil @@ -502,10 +671,9 @@ func (b *TXOut) CannotBeMinedBeforeHeight() (uint32, error) { if err != nil { return 0, err } - if iat == 0 { - return 0, errorz.ErrInvalid{}.New("invalid IssuedAt in utxo") - } return (iat-1)*constants.EpochLength + 1, nil + case b.HasTxFee(): + return 1, nil default: return 0, errorz.ErrInvalid{}.New("TXOut type not defined in MustBeMinedBeforeHeight") } diff --git a/application/objs/utxo_test.go b/application/objs/utxo_test.go index 05153d1b..1e083baf 100644 --- a/application/objs/utxo_test.go +++ b/application/objs/utxo_test.go @@ -15,16 +15,20 @@ func TestUTXOCreateValueStore(t *testing.T) { if err != nil { t.Fatal(err) } + fee, err := new(uint256.Uint256).FromUint64(0) + if err != nil { + t.Fatal(err) + } acct := make([]byte, constants.OwnerLen) curveSpec := constants.CurveSecp256k1 txHash := make([]byte, constants.HashLen) utxo := &TXOut{} - err = utxo.CreateValueStore(chainID, value, acct, curveSpec, txHash) + err = utxo.CreateValueStore(chainID, value, fee, acct, curveSpec, txHash) if err == nil { t.Fatal("Should have raised error") } chainID = 1 - err = utxo.CreateValueStore(chainID, value, acct, curveSpec, txHash) + err = utxo.CreateValueStore(chainID, value, fee, acct, curveSpec, txHash) if err != nil { t.Fatal(err) } @@ -83,6 +87,7 @@ func TestUTXODataStoreGood(t *testing.T) { RawData: rawdata, TXOutIdx: txoid, Owner: owner, + Fee: new(uint256.Uint256).SetZero(), } txHash := make([]byte, constants.HashLen) dsl := &DSLinker{ @@ -111,6 +116,9 @@ func TestUTXODataStoreGood(t *testing.T) { if utxo.HasAtomicSwap() { t.Fatal("Should not have AtomicSwap!") } + if utxo.HasTxFee() { + t.Fatal("Should not have TxFee!") + } dsCopy, err := utxo.DataStore() if err != nil { @@ -128,26 +136,12 @@ func TestUTXODataStoreGood(t *testing.T) { t.Fatal("Should raise error for no AtomicSwap!") } - owner2 := &ValueStoreOwner{} - owner2.New(ownerAcct, constants.CurveSecp256k1) - - val, err := new(uint256.Uint256).FromUint64(1) - if err != nil { - t.Fatal(err) - } - utxo2 := &TXOut{} - err = utxo2.NewValueStore(&ValueStore{ - VSPreImage: &VSPreImage{ - ChainID: 1, - Value: val, - TXOutIdx: 0, - Owner: owner2, - }, - }) - if err != nil { - t.Fatal(err) + _, err = utxo.TxFee() + if err == nil { + t.Fatal("Should raise error for no TxFee!") } + utxo2 := &TXOut{} utxoBytes, err := utxo.MarshalBinary() if err != nil { t.Fatal(err) @@ -184,6 +178,7 @@ func TestUTXOValueStoreGood(t *testing.T) { Value: val, TXOutIdx: txoid, Owner: owner, + Fee: new(uint256.Uint256).SetZero(), } txHash := make([]byte, constants.HashLen) vs := &ValueStore{ @@ -206,6 +201,9 @@ func TestUTXOValueStoreGood(t *testing.T) { if utxo.HasAtomicSwap() { t.Fatal("Should not have AtomicSwap!") } + if utxo.HasTxFee() { + t.Fatal("Should not have TxFee!") + } _, err = utxo.DataStore() if err == nil { @@ -222,6 +220,21 @@ func TestUTXOValueStoreGood(t *testing.T) { if err == nil { t.Fatal("Should raise error for no AtomicSwap!") } + + _, err = utxo.TxFee() + if err == nil { + t.Fatal("Should raise error for no TxFee!") + } + + utxo2 := &TXOut{} + utxoBytes, err := utxo.MarshalBinary() + if err != nil { + t.Fatal(err) + } + err = utxo2.UnmarshalBinary(utxoBytes) + if err != nil { + t.Fatal(err) + } } func TestUTXOAtomicSwapGood(t *testing.T) { @@ -281,6 +294,9 @@ func TestUTXOAtomicSwapGood(t *testing.T) { if !utxo.HasAtomicSwap() { t.Fatal("Should have AtomicSwap!") } + if utxo.HasTxFee() { + t.Fatal("Should not have TxFee!") + } _, err = utxo.DataStore() if err == nil { @@ -297,6 +313,78 @@ func TestUTXOAtomicSwapGood(t *testing.T) { t.Fatal(err) } asEqual(t, as, asCopy) + + _, err = utxo.TxFee() + if err == nil { + t.Fatal("Should raise error for TxFee!") + } +} + +func TestUTXOTxFeeGood(t *testing.T) { + cid := uint32(2) + fee, err := new(uint256.Uint256).FromUint64(65537) + if err != nil { + t.Fatal(err) + } + txoid := uint32(17) + + tf := &TxFee{} + tf.TFPreImage = &TFPreImage{ + ChainID: cid, + TXOutIdx: txoid, + Fee: fee.Clone(), + } + tf.TxHash = make([]byte, constants.HashLen) + + utxo := &TXOut{} + err = utxo.NewTxFee(tf) + if err != nil { + t.Fatal(err) + } + + if utxo.HasDataStore() { + t.Fatal("Should not have DataStore!") + } + if utxo.HasValueStore() { + t.Fatal("Should not have ValueStore!") + } + if utxo.HasAtomicSwap() { + t.Fatal("Should not have AtomicSwap!") + } + if !utxo.HasTxFee() { + t.Fatal("Should have TxFee!") + } + + _, err = utxo.DataStore() + if err == nil { + t.Fatal("Should raise error for DataStore!") + } + + _, err = utxo.ValueStore() + if err == nil { + t.Fatal("Should raise error for ValueStore!") + } + + _, err = utxo.AtomicSwap() + if err == nil { + t.Fatal("Should raise error for AtomicSwap!") + } + + tfCopy, err := utxo.TxFee() + if err != nil { + t.Fatal(err) + } + tfEqual(t, tf, tfCopy) + + utxo2 := &TXOut{} + utxoBytes, err := utxo.MarshalBinary() + if err != nil { + t.Fatal(err) + } + err = utxo2.UnmarshalBinary(utxoBytes) + if err != nil { + t.Fatal(err) + } } func TestUTXOMarshalBinary(t *testing.T) { @@ -335,6 +423,16 @@ func TestUTXOMarshalBinary(t *testing.T) { if err == nil { t.Fatal("Should have raised error (4)") } + + tf := &TxFee{} + err = utxo.NewTxFee(tf) + if err != nil { + t.Fatal(err) + } + _, err = utxo.MarshalBinary() + if err == nil { + t.Fatal("Should have raised error (5)") + } } func TestUTXOUnmarshalBinary(t *testing.T) { @@ -382,6 +480,16 @@ func TestUTXOPreHash(t *testing.T) { if err == nil { t.Fatal("Should have raised error (4)") } + + tf := &TxFee{} + err = utxo.NewTxFee(tf) + if err != nil { + t.Fatal(err) + } + _, err = utxo.PreHash() + if err == nil { + t.Fatal("Should have raised error (5)") + } } func TestUTXOUTXOID(t *testing.T) { @@ -420,6 +528,16 @@ func TestUTXOUTXOID(t *testing.T) { if err == nil { t.Fatal("Should have raised error (4)") } + + tf := &TxFee{} + err = utxo.NewTxFee(tf) + if err != nil { + t.Fatal(err) + } + _, err = utxo.UTXOID() + if err == nil { + t.Fatal("Should have raised error (5)") + } } func TestUTXOChainID(t *testing.T) { @@ -458,6 +576,16 @@ func TestUTXOChainID(t *testing.T) { if err == nil { t.Fatal("Should have raised error (4)") } + + tf := &TxFee{} + err = utxo.NewTxFee(tf) + if err != nil { + t.Fatal(err) + } + _, err = utxo.ChainID() + if err == nil { + t.Fatal("Should have raised error (5)") + } } func TestUTXOTXOutIdx(t *testing.T) { @@ -496,6 +624,16 @@ func TestUTXOTXOutIdx(t *testing.T) { if err == nil { t.Fatal("Should have raised error (4)") } + + tf := &TxFee{} + err = utxo.NewTxFee(tf) + if err != nil { + t.Fatal(err) + } + _, err = utxo.TXOutIdx() + if err == nil { + t.Fatal("Should have raised error (5)") + } } func TestUTXOSetTXOutIdx(t *testing.T) { @@ -535,6 +673,16 @@ func TestUTXOSetTXOutIdx(t *testing.T) { if err == nil { t.Fatal("Should have raised error (4)") } + + tf := &TxFee{} + err = utxo.NewTxFee(tf) + if err != nil { + t.Fatal(err) + } + err = utxo.SetTXOutIdx(idx) + if err == nil { + t.Fatal("Should have raised error (5)") + } } func TestUTXOTxHash(t *testing.T) { @@ -601,6 +749,25 @@ func TestUTXOTxHash(t *testing.T) { if !bytes.Equal(txHash, txHashTrue) { t.Fatal("txHash does not match (4)") } + + tf := &TxFee{} + err = utxo.NewTxFee(tf) + if err != nil { + t.Fatal(err) + } + _, err = utxo.TxHash() + if err == nil { + t.Fatal("Should have raised error (5)") + } + tf.TFPreImage = &TFPreImage{} + tf.TxHash = txHashTrue + txHash, err = utxo.TxHash() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(txHash, txHashTrue) { + t.Fatal("txHash does not match (5)") + } } func TestUTXOSetTxHash(t *testing.T) { @@ -646,6 +813,16 @@ func TestUTXOSetTxHash(t *testing.T) { if err == nil { t.Fatal("Should have raised error (5)") } + + tf := &TxFee{} + err = utxo.NewTxFee(tf) + if err != nil { + t.Fatal(err) + } + err = utxo.SetTxHash(txHash) + if err == nil { + t.Fatal("Should have raised error (6)") + } } func TestUTXORemainingValue(t *testing.T) { @@ -685,6 +862,16 @@ func TestUTXORemainingValue(t *testing.T) { if err == nil { t.Fatal("Should have raised error (4)") } + + tf := &TxFee{} + err = utxo.NewTxFee(tf) + if err != nil { + t.Fatal(err) + } + _, err = utxo.RemainingValue(currentHeight) + if err == nil { + t.Fatal("Should have raised error (5)") + } } func TestUTXOMakeTxIn(t *testing.T) { @@ -723,6 +910,16 @@ func TestUTXOMakeTxIn(t *testing.T) { if err == nil { t.Fatal("Should have raised error (4)") } + + tf := &TxFee{} + err = utxo.NewTxFee(tf) + if err != nil { + t.Fatal(err) + } + _, err = utxo.MakeTxIn() + if err == nil { + t.Fatal("Should have raised error (5)") + } } func TestUTXOValue(t *testing.T) { @@ -761,6 +958,64 @@ func TestUTXOValue(t *testing.T) { if err == nil { t.Fatal("Should have raised error (4)") } + + tf := &TxFee{} + err = utxo.NewTxFee(tf) + if err != nil { + t.Fatal(err) + } + _, err = utxo.Value() + if err == nil { + t.Fatal("Should have raised error (5)") + } +} + +func TestUTXOValuePlusFee(t *testing.T) { + utxo := &TXOut{} + _, err := utxo.ValuePlusFee() + if err == nil { + t.Fatal("Should have raised error (1)") + } + + as := &AtomicSwap{} + err = utxo.NewAtomicSwap(as) + if err != nil { + t.Fatal(err) + } + _, err = utxo.ValuePlusFee() + if err == nil { + t.Fatal("Should have raised error (2)") + } + + ds := &DataStore{} + err = utxo.NewDataStore(ds) + if err != nil { + t.Fatal(err) + } + _, err = utxo.ValuePlusFee() + if err == nil { + t.Fatal("Should have raised error (3)") + } + + vs := &ValueStore{} + err = utxo.NewValueStore(vs) + if err != nil { + t.Fatal(err) + } + _, err = utxo.ValuePlusFee() + if err == nil { + t.Fatal("Should have raised error (4)") + } + + tf := &TxFee{} + err = utxo.NewTxFee(tf) + if err != nil { + t.Fatal(err) + } + _, err = utxo.ValuePlusFee() + if err == nil { + t.Fatal("Should have raised error (5)") + } } func TestUTXOValidatePreSignature(t *testing.T) { @@ -799,6 +1054,16 @@ func TestUTXOValidatePreSignature(t *testing.T) { if err != nil { t.Fatal("Should pass (2)") } + + tf := &TxFee{} + err = utxo.NewTxFee(tf) + if err != nil { + t.Fatal(err) + } + err = utxo.ValidatePreSignature() + if err != nil { + t.Fatal("Should pass (3)") + } } func TestUTXOValidateSignature(t *testing.T) { @@ -839,6 +1104,16 @@ func TestUTXOValidateSignature(t *testing.T) { if err == nil { t.Fatal("Should have raised error (4)") } + + tf := &TxFee{} + err = utxo.NewTxFee(tf) + if err != nil { + t.Fatal(err) + } + err = utxo.ValidateSignature(currentHeight, txIn) + if err != nil { + t.Fatal("Should have passed") + } } func TestUTXOMustBeMinedBeforeHeight(t *testing.T) { @@ -899,6 +1174,16 @@ func TestUTXOMustBeMinedBeforeHeight(t *testing.T) { if err != nil { t.Fatal(err) } + + tf := &TxFee{} + err = utxo.NewTxFee(tf) + if err != nil { + t.Fatal(err) + } + _, err = utxo.MustBeMinedBeforeHeight() + if err != nil { + t.Fatal(err) + } } func TestUTXOAccount(t *testing.T) { @@ -996,6 +1281,16 @@ func TestUTXOAccount(t *testing.T) { if err != nil { t.Fatal(err) } + + tf := &TxFee{} + err = utxo.NewTxFee(tf) + if err != nil { + t.Fatal(err) + } + _, err = utxo.Account() + if err == nil { + t.Fatal("Should have raised error (5)") + } } func TestUTXOGenericOwner(t *testing.T) { @@ -1152,6 +1447,16 @@ func TestUTXOGenericOwner(t *testing.T) { if err != nil { t.Fatal(err) } + + tf := &TxFee{} + err = utxo.NewTxFee(tf) + if err != nil { + t.Fatal(err) + } + _, err = utxo.GenericOwner() + if err == nil { + t.Fatal("Should have raised error (12)") + } } func TestUTXOIsDeposit(t *testing.T) { @@ -1190,4 +1495,101 @@ func TestUTXOIsDeposit(t *testing.T) { if val { t.Fatal("Should be false (4)") } + + tf := &TxFee{} + err = utxo.NewTxFee(tf) + if err != nil { + t.Fatal(err) + } + val = utxo.IsDeposit() + if val { + t.Fatal("Should be false (5)") + } +} + +func TestUTXOCannotBeMinedBeforeHeight(t *testing.T) { + utxo := &TXOut{} + _, err := utxo.CannotBeMinedBeforeHeight() + if err == nil { + t.Fatal("Should have raised error (1)") + } + + as := &AtomicSwap{} + err = utxo.NewAtomicSwap(as) + if err != nil { + t.Fatal(err) + } + _, err = utxo.CannotBeMinedBeforeHeight() + if err == nil { + t.Fatal("Should have raised error (2)") + } + as.ASPreImage = &ASPreImage{} + as.ASPreImage.IssuedAt = 0 + _, err = utxo.CannotBeMinedBeforeHeight() + if err == nil { + t.Fatal("Should have raised error (3)") + } + as.ASPreImage.IssuedAt = 2 + heightASTrue := constants.EpochLength + 1 + height, err := utxo.CannotBeMinedBeforeHeight() + if err != nil { + t.Fatal(err) + } + if height != heightASTrue { + t.Fatal("Incorrect height for AtomicSwap in CannotBeMinedBeforeHeight") + } + + ds := &DataStore{} + err = utxo.NewDataStore(ds) + if err != nil { + t.Fatal(err) + } + _, err = utxo.CannotBeMinedBeforeHeight() + if err == nil { + t.Fatal("Should have raised error (4)") + } + ds.DSLinker = &DSLinker{} + ds.DSLinker.DSPreImage = &DSPreImage{} + ds.DSLinker.DSPreImage.IssuedAt = uint32(0) + _, err = utxo.CannotBeMinedBeforeHeight() + if err == nil { + t.Fatal("Should have raised error (5)") + } + ds.DSLinker.DSPreImage.IssuedAt = uint32(3) + heightDSTrue := 2*constants.EpochLength + 1 + height, err = utxo.CannotBeMinedBeforeHeight() + if err != nil { + t.Fatal(err) + } + if height != heightDSTrue { + t.Fatal("Incorrect height for DataStore in CannotBeMinedBeforeHeight") + } + + vs := &ValueStore{} + err = utxo.NewValueStore(vs) + if err != nil { + t.Fatal(err) + } + heightVSTrue := uint32(1) + height, err = utxo.CannotBeMinedBeforeHeight() + if err != nil { + t.Fatal(err) + } + if height != heightVSTrue { + t.Fatal("Incorrect height for ValueStore in CannotBeMinedBeforeHeight") + } + + tf := &TxFee{} + err = utxo.NewTxFee(tf) + if err != nil { + t.Fatal(err) + } + heightTFTrue := uint32(1) + height, err = utxo.CannotBeMinedBeforeHeight() + if err != nil { + t.Fatal(err) + } + if height != heightTFTrue { + t.Fatal("Incorrect height for TxFee in CannotBeMinedBeforeHeight") + } } diff --git a/application/objs/vin.go b/application/objs/vin.go index e9e82a53..a0160816 100644 --- a/application/objs/vin.go +++ b/application/objs/vin.go @@ -39,3 +39,25 @@ func (vin Vin) IsDeposit() []bool { } return ids } + +// IsCleanupVin ensures we have a valid Vin object in Cleanup Tx. +// In this case, the refUTXOs must all be expired DataStores. +func (vin Vin) IsCleanupVin(currentHeight uint32, refUTXOs Vout) bool { + if len(vin) == 0 { + return false + } + // Must ensure that all Vin objects are expired datastores. + for i := 0; i < len(refUTXOs); i++ { + utxo := refUTXOs[i] + if !utxo.HasDataStore() { + // Must have DataStore + return false + } + expired, err := utxo.IsExpired(currentHeight) + if err != nil || !expired { + // DataStore must be expired + return false + } + } + return true +} diff --git a/application/objs/vout.go b/application/objs/vout.go index cb2c6fd5..2bc3edfd 100644 --- a/application/objs/vout.go +++ b/application/objs/vout.go @@ -2,21 +2,23 @@ package objs import ( "github.com/MadBase/MadNet/application/objs/uint256" + "github.com/MadBase/MadNet/application/wrapper" "github.com/MadBase/MadNet/errorz" ) // Vout is a vector of TXOut objects type Vout []*TXOut -// Value sums the total value of the UTXOs without any discount -func (vout Vout) Value() (*uint256.Uint256, error) { +// ValuePlusFee sums the total value of the UTXOs without any discount +// and including associated fees +func (vout Vout) ValuePlusFee() (*uint256.Uint256, error) { sum := uint256.Zero() for i := 0; i < len(vout); i++ { - value, err := vout[i].Value() + value, err := vout[i].ValuePlusFee() if err != nil { return nil, err } - sum, err = sum.Clone().Add(sum.Clone(), value.Clone()) + sum, err = sum.Add(sum, value) if err != nil { return nil, err } @@ -32,7 +34,7 @@ func (vout Vout) RemainingValue(currentHeight uint32) (*uint256.Uint256, error) if err != nil { return nil, err } - sum, err = sum.Clone().Add(sum.Clone(), value.Clone()) + sum, err = sum.Add(sum, value) if err != nil { return nil, err } @@ -79,6 +81,13 @@ func (vout Vout) ValidateTxOutIdx() error { return err } txOutIdx = asTxOutIdx + case utxo.HasTxFee(): + tf, _ := utxo.TxFee() + tfTxOutIdx, err := tf.TXOutIdx() + if err != nil { + return err + } + txOutIdx = tfTxOutIdx default: return errorz.ErrInvalid{}.New("bad txOutIdx: Invalid Type") } @@ -121,6 +130,52 @@ func (vout Vout) PreHash() ([][]byte, error) { return phs, nil } +// ValidateFees validates the Fee from each TXOut in Vout +func (vout Vout) ValidateFees(storage *wrapper.Storage) error { + for i := 0; i < len(vout); i++ { + err := vout[i].ValidateFee(storage) + if err != nil { + return err + } + } + return nil +} + +// ValidateTxFee validates the transaction fee in Vout +// +// There can be at most one TxFee UTXO object in Vout. +// There can be zero TxFee UTXO objects if MinTxFee is zero. +func (vout Vout) ValidateTxFee(storage *wrapper.Storage) error { + maxNumTxFees := 1 + minTxFee, err := storage.GetMinTxFee() + if err != nil { + return err + } + numTxFees := 0 + totalTxFee := new(uint256.Uint256) + for i := 0; i < len(vout); i++ { + if vout[i].HasTxFee() { + numTxFees++ + if numTxFees > maxNumTxFees { + return errorz.ErrInvalid{}.New("invalid Vout: more than 1 TxFee object") + } + txFee, err := vout[i].TxFee() + if err != nil { + return err + } + fee, err := txFee.Fee() + if err != nil { + return err + } + totalTxFee.Add(totalTxFee, fee) + } + } + if totalTxFee.Gte(minTxFee) { + return nil + } + return errorz.ErrInvalid{}.New("invalid Vout: totalTxFee < minTxFee") +} + // ValidatePreSignature validates the PreSignature from each TXOut in Vout func (vout Vout) ValidatePreSignature() error { for i := 0; i < len(vout); i++ { @@ -158,3 +213,28 @@ func (vout Vout) MakeTxIn() (Vin, error) { } return txIns, nil } + +// IsCleanupVout ensures we have a valid Vout object in Cleanup Tx. +// In this case, Vout must be only one ValueStore. +func (vout Vout) IsCleanupVout() bool { + if len(vout) != 1 { + return false + } + // Confirm utxo is ValueStore with no fee + utxo := vout[0] + if !utxo.HasValueStore() { + return false + } + vs, err := utxo.ValueStore() + if err != nil { + return false + } + vsFee, err := vs.Fee() + if err != nil { + return false + } + if !vsFee.IsZero() { + return false + } + return true +} diff --git a/application/objs/vs.go b/application/objs/vs.go index 758a446a..11feded5 100644 --- a/application/objs/vs.go +++ b/application/objs/vs.go @@ -4,6 +4,7 @@ import ( mdefs "github.com/MadBase/MadNet/application/objs/capn" "github.com/MadBase/MadNet/application/objs/uint256" "github.com/MadBase/MadNet/application/objs/valuestore" + "github.com/MadBase/MadNet/application/wrapper" "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/errorz" "github.com/MadBase/MadNet/utils" @@ -19,7 +20,16 @@ type ValueStore struct { } // New creates a new ValueStore -func (b *ValueStore) New(chainID uint32, value *uint256.Uint256, acct []byte, curveSpec constants.CurveSpec, txHash []byte) error { +func (b *ValueStore) New(chainID uint32, value *uint256.Uint256, fee *uint256.Uint256, acct []byte, curveSpec constants.CurveSpec, txHash []byte) error { + if b == nil { + return errorz.ErrInvalid{}.New("not initialized") + } + if value == nil || value.IsZero() { + return errorz.ErrInvalid{}.New("invalue value: nil or zero") + } + if fee == nil { + return errorz.ErrInvalid{}.New("invalue fee: nil") + } vsowner := &ValueStoreOwner{} vsowner.New(acct, curveSpec) if err := vsowner.Validate(); err != nil { @@ -33,9 +43,10 @@ func (b *ValueStore) New(chainID uint32, value *uint256.Uint256, acct []byte, cu } vsp := &VSPreImage{ ChainID: chainID, - Value: value, + Value: value.Clone(), TXOutIdx: constants.MaxUint32, Owner: vsowner, + Fee: fee.Clone(), } b.VSPreImage = vsp b.TxHash = utils.CopySlice(txHash) @@ -201,12 +212,37 @@ func (b *ValueStore) ChainID() (uint32, error) { // Value returns the Value of the object func (b *ValueStore) Value() (*uint256.Uint256, error) { - if b == nil || b.VSPreImage == nil || b.VSPreImage.Value == nil { + if b == nil || b.VSPreImage == nil || b.VSPreImage.Value == nil || b.VSPreImage.Value.IsZero() { return nil, errorz.ErrInvalid{}.New("not initialized") } return b.VSPreImage.Value.Clone(), nil } +// Fee returns the Fee of the object +func (b *ValueStore) Fee() (*uint256.Uint256, error) { + if b == nil || b.VSPreImage == nil || b.VSPreImage.Fee == nil { + return nil, errorz.ErrInvalid{}.New("not initialized") + } + return b.VSPreImage.Fee.Clone(), nil +} + +// ValuePlusFee returns the Value of the object with the associated fee +func (b *ValueStore) ValuePlusFee() (*uint256.Uint256, error) { + value, err := b.Value() + if err != nil { + return nil, err + } + fee, err := b.Fee() + if err != nil { + return nil, err + } + total, err := new(uint256.Uint256).Add(value, fee) + if err != nil { + return nil, err + } + return total, nil +} + // IsDeposit returns true if the object is a deposit func (b *ValueStore) IsDeposit() bool { if b == nil || b.VSPreImage == nil { @@ -261,6 +297,28 @@ func (b *ValueStore) Sign(txIn *TXIn, s Signer) error { return nil } +// ValidateFee validates the fee of the object at the time of creation +func (b *ValueStore) ValidateFee(storage *wrapper.Storage) error { + fee, err := b.Fee() + if err != nil { + return err + } + if b.IsDeposit() { + if !fee.IsZero() { + return errorz.ErrInvalid{}.New("vs: invalid fee; deposits should have fee equal zero") + } + return nil + } + feeTrue, err := storage.GetValueStoreFee() + if err != nil { + return err + } + if fee.Cmp(feeTrue) != 0 { + return errorz.ErrInvalid{}.New("vs: invalid fee") + } + return nil +} + // ValidateSignature validates the signature of the ValueStore at the time of // consumption func (b *ValueStore) ValidateSignature(txIn *TXIn) error { diff --git a/application/objs/vs_test.go b/application/objs/vs_test.go index ce1d2554..876215f1 100644 --- a/application/objs/vs_test.go +++ b/application/objs/vs_test.go @@ -2,6 +2,7 @@ package objs import ( "bytes" + "math/big" "testing" "github.com/MadBase/MadNet/application/objs/uint256" @@ -34,6 +35,7 @@ func TestValueStoreGood(t *testing.T) { Value: val, TXOutIdx: txoid, Owner: owner, + Fee: new(uint256.Uint256).SetZero(), } txHash := make([]byte, constants.HashLen) vs := &ValueStore{ @@ -86,6 +88,7 @@ func TestValueStoreBad1(t *testing.T) { Value: val, TXOutIdx: txoid, Owner: owner, + Fee: new(uint256.Uint256).SetZero(), } txHash := make([]byte, constants.HashLen) vs := &ValueStore{ @@ -128,6 +131,7 @@ func TestValueStoreBad2(t *testing.T) { Value: val, TXOutIdx: txoid, Owner: owner, + Fee: new(uint256.Uint256).SetZero(), } txHash := make([]byte, constants.HashLen+1) // Invalid TxHash vs := &ValueStore{ @@ -152,32 +156,56 @@ func TestValueStoreNew(t *testing.T) { if err != nil { t.Fatal(err) } + fee, err := new(uint256.Uint256).FromUint64(0) + if err != nil { + t.Fatal(err) + } acct := make([]byte, 0) curveSpec := constants.CurveSecp256k1 txHash := make([]byte, 0) - err = utxo.valueStore.New(chainID, value, acct, curveSpec, txHash) + err = utxo.valueStore.New(chainID, value, fee, acct, curveSpec, txHash) if err == nil { t.Fatal("Should raise an error (1)") } vs := &ValueStore{} - acct = make([]byte, constants.OwnerLen) - err = vs.New(chainID, value, acct, curveSpec, txHash) + err = vs.New(chainID, value, fee, acct, curveSpec, txHash) if err == nil { t.Fatal("Should raise an error (2)") } - chainID = 1 - err = vs.New(chainID, value, acct, curveSpec, txHash) + acct = make([]byte, constants.OwnerLen) + err = vs.New(chainID, value, fee, acct, curveSpec, txHash) if err == nil { t.Fatal("Should raise an error (3)") } + chainID = 1 + err = vs.New(chainID, value, fee, acct, curveSpec, txHash) + if err == nil { + t.Fatal("Should raise an error (4)") + } + txHash = make([]byte, constants.HashLen) - err = vs.New(chainID, value, acct, curveSpec, txHash) + err = vs.New(chainID, value, fee, acct, curveSpec, txHash) if err != nil { t.Fatal(err) } + + err = vs.New(chainID, nil, fee, acct, curveSpec, txHash) + if err == nil { + t.Fatal("Should raise an error (5)") + } + + err = vs.New(chainID, uint256.Zero(), fee, acct, curveSpec, txHash) + if err == nil { + t.Fatal("Should raise an error (6)") + } + + err = vs.New(chainID, value, nil, acct, curveSpec, txHash) + if err == nil { + t.Fatal("Should raise an error (7)") + } } func TestValueStoreNewFromDeposit(t *testing.T) { @@ -258,6 +286,7 @@ func TestValueStoreMarshalBinary(t *testing.T) { Value: val, TXOutIdx: txoid, Owner: owner, + Fee: new(uint256.Uint256).SetZero(), } txHash := make([]byte, constants.HashLen) vs = &ValueStore{ @@ -313,6 +342,7 @@ func TestValueStoreUnmarshalBinary(t *testing.T) { Value: val, TXOutIdx: txoid, Owner: owner, + Fee: new(uint256.Uint256).SetZero(), } txHash := make([]byte, constants.HashLen) vs = &ValueStore{ @@ -514,6 +544,83 @@ func TestValueStoreValue(t *testing.T) { } } +func TestValueStoreValuePlusFeeGood(t *testing.T) { + // Prepare ValueStore + vs := &ValueStore{} + vs.VSPreImage = &VSPreImage{} + value32 := uint32(1234567890) + value, err := new(uint256.Uint256).FromUint64(uint64(value32)) + if err != nil { + t.Fatal(err) + } + vs.VSPreImage.Value = value.Clone() + vs.VSPreImage.Fee = new(uint256.Uint256) + + // Check valuePlusFee + valuePlusFee, err := vs.ValuePlusFee() + if err != nil { + t.Fatal(err) + } + if !value.Eq(valuePlusFee) { + t.Fatal("value and valuePlusFee do not match") + } + + // Prepare storage with nonzero fee + valueStoreFee := uint32(1000) + vsFee, err := new(uint256.Uint256).FromUint64(uint64(valueStoreFee)) + if err != nil { + t.Fatal(err) + } + vs.VSPreImage.Fee = vsFee.Clone() + trueVPF, err := new(uint256.Uint256).Add(vsFee, value) + if err != nil { + t.Fatal(err) + } + + // Check valuePlusFee + valuePlusFee, err = vs.ValuePlusFee() + if err != nil { + t.Fatal(err) + } + if !trueVPF.Eq(valuePlusFee) { + t.Fatal("valuePlusFee is not correct") + } + if value.Eq(valuePlusFee) { + t.Fatal("value and valuePlusFee should not be equal") + } +} + +func TestValueStoreValuePlusFeeBad1(t *testing.T) { + vs := &ValueStore{} + _, err := vs.ValuePlusFee() + if err == nil { + t.Fatal("Should raise an error") + } +} + +func TestValueStoreValuePlusFeeBad2(t *testing.T) { + vs := &ValueStore{} + vs.VSPreImage = &VSPreImage{} + + // Cause overflow when computing valuePlusFee + bigString := "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + bigBig, ok := new(big.Int).SetString(bigString, 16) + if !ok { + t.Fatal("Invalid conversion") + } + bigUint256, err := new(uint256.Uint256).FromBigInt(bigBig) + if err != nil { + t.Fatal(err) + } + + // Prep for failure + vs.VSPreImage.Value = bigUint256.Clone() + _, err = vs.ValuePlusFee() + if err == nil { + t.Fatal("Should have raised error") + } +} + func TestValueStoreIsDeposit(t *testing.T) { vs := &ValueStore{} val := vs.IsDeposit() @@ -778,6 +885,51 @@ func TestValueStoreMakeTxIn(t *testing.T) { } } +func TestValueStoreValidateFee(t *testing.T) { + msg := makeMockStorageGetter() + storage := makeStorage(msg) + + utxo := &TXOut{} + err := utxo.valueStore.ValidateFee(storage) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + vs := &ValueStore{} + err = vs.ValidateFee(storage) + if err == nil { + t.Fatal("Should have raised error (2)") + } + + vs.VSPreImage = &VSPreImage{} + vs.VSPreImage.Fee = new(uint256.Uint256).SetZero() + err = vs.ValidateFee(storage) + if err != nil { + t.Fatal(err) + } + + vsFee := big.NewInt(1) + msg.SetValueStoreFee(vsFee) + storage = makeStorage(msg) + err = vs.ValidateFee(storage) + if err == nil { + t.Fatal("Should have raised error (3)") + } + + // Now tests for deposit + vs.VSPreImage.TXOutIdx = constants.MaxUint32 + err = vs.ValidateFee(storage) + if err != nil { + t.Fatal(err) + } + + vs.VSPreImage.Fee.SetOne() + err = vs.ValidateFee(storage) + if err == nil { + t.Fatal("Should have raised error (4)") + } +} + func TestValueStoreOwnerSig(t *testing.T) { cid := uint32(2) val, err := new(uint256.Uint256).FromUint64(65537) @@ -803,6 +955,7 @@ func TestValueStoreOwnerSig(t *testing.T) { Value: val, TXOutIdx: txoid, Owner: owner, + Fee: new(uint256.Uint256).SetZero(), } txHash := make([]byte, constants.HashLen) vs := &ValueStore{ @@ -863,7 +1016,10 @@ func TestValueStoreOwnerSig2(t *testing.T) { txoid := uint32(17) ownerSigner := &crypto.BNSigner{} - ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))) + err = ownerSigner.SetPrivk(crypto.Hasher([]byte("a"))) + if err != nil { + t.Fatal(err) + } ownerPubk, err := ownerSigner.Pubkey() if err != nil { t.Fatal(err) @@ -877,6 +1033,7 @@ func TestValueStoreOwnerSig2(t *testing.T) { Value: val, TXOutIdx: txoid, Owner: owner, + Fee: new(uint256.Uint256).SetZero(), } txHash := make([]byte, constants.HashLen) vs := &ValueStore{ diff --git a/application/objs/vsowner_test.go b/application/objs/vsowner_test.go index 0114183b..e9833e27 100644 --- a/application/objs/vsowner_test.go +++ b/application/objs/vsowner_test.go @@ -218,7 +218,10 @@ func TestVSOwnerValidateSignatureSecp(t *testing.T) { t.Fatal(err) } bnSigner := &crypto.BNSigner{} - bnSigner.SetPrivk(privk) + err = bnSigner.SetPrivk(privk) + if err != nil { + t.Fatal(err) + } vssBN, err := vso.Sign(msg, bnSigner) if err != nil { t.Fatal(err) @@ -280,7 +283,10 @@ func TestVSOwnerValidateSignatureBN(t *testing.T) { privk := make([]byte, 32) privk[0] = 1 privk[31] = 1 - bnSigner.SetPrivk(privk) + err = bnSigner.SetPrivk(privk) + if err != nil { + t.Fatal(err) + } secpSigner := &crypto.Secp256k1Signer{} if err := secpSigner.SetPrivk(privk); err != nil { t.Fatal(err) diff --git a/application/objs/vspi.go b/application/objs/vspi.go index 90780ca0..b7a58207 100644 --- a/application/objs/vspi.go +++ b/application/objs/vspi.go @@ -16,6 +16,7 @@ type VSPreImage struct { Value *uint256.Uint256 TXOutIdx uint32 Owner *ValueStoreOwner + Fee *uint256.Uint256 // preHash []byte } @@ -74,6 +75,20 @@ func (b *VSPreImage) UnmarshalCapn(bc mdefs.VSPreImage) error { return err } b.Owner = owner + fObj := &uint256.Uint256{} + u32array[0] = bc.Fee0() + u32array[1] = bc.Fee1() + u32array[2] = bc.Fee2() + u32array[3] = bc.Fee3() + u32array[4] = bc.Fee4() + u32array[5] = bc.Fee5() + u32array[6] = bc.Fee6() + u32array[7] = bc.Fee7() + err = fObj.FromUint32Array(u32array) + if err != nil { + return err + } + b.Fee = fObj return nil } @@ -120,6 +135,18 @@ func (b *VSPreImage) MarshalCapn(seg *capnp.Segment) (mdefs.VSPreImage, error) { bc.SetValue5(u32array[5]) bc.SetValue6(u32array[6]) bc.SetValue7(u32array[7]) + u32array, err = b.Fee.ToUint32Array() + if err != nil { + return bc, err + } + bc.SetFee0(u32array[0]) + bc.SetFee1(u32array[1]) + bc.SetFee2(u32array[2]) + bc.SetFee3(u32array[3]) + bc.SetFee4(u32array[4]) + bc.SetFee5(u32array[5]) + bc.SetFee6(u32array[6]) + bc.SetFee7(u32array[7]) bc.SetTXOutIdx(b.TXOutIdx) return bc, nil } diff --git a/application/objs/vspi_test.go b/application/objs/vspi_test.go index e09c5f06..ad3d1eac 100644 --- a/application/objs/vspi_test.go +++ b/application/objs/vspi_test.go @@ -34,6 +34,7 @@ func TestVSPreImageGood(t *testing.T) { Value: val, TXOutIdx: txoid, Owner: owner, + Fee: new(uint256.Uint256).SetZero(), } vsp2 := &VSPreImage{} vspBytes, err := vsp.MarshalBinary() @@ -87,6 +88,7 @@ func TestVSPreImageBad1(t *testing.T) { Value: val, TXOutIdx: txoid, Owner: owner, + Fee: new(uint256.Uint256).SetZero(), } vsp2 := &VSPreImage{} vspBytes, err := vsp.MarshalBinary() @@ -177,6 +179,7 @@ func TestVSPreImagePreHash(t *testing.T) { Value: val, TXOutIdx: txoid, Owner: owner, + Fee: new(uint256.Uint256).SetZero(), } out, err := vsp.PreHash() if err != nil { diff --git a/application/pendingtx/pending_test.go b/application/pendingtx/pending_test.go index 7fd774a2..ddfcbcae 100644 --- a/application/pendingtx/pending_test.go +++ b/application/pendingtx/pending_test.go @@ -64,10 +64,12 @@ func makeVS(ownerSigner objs.Signer) *objs.TXOut { owner := &objs.ValueStoreOwner{} owner.New(ownerAcct, constants.CurveSecp256k1) + fee := uint256.One() vsp := &objs.VSPreImage{ ChainID: cid, Value: val, Owner: owner, + Fee: fee, } vs := &objs.ValueStore{ VSPreImage: vsp, @@ -357,7 +359,8 @@ func TestGetProposal(t *testing.T) { mustAddTx(t, hndlr, tx3, 1) tx4 := makeTxConsuming(c2) mustAddTx(t, hndlr, tx4, 1) - txs, err := hndlr.GetTxsForProposal(nil, context.TODO(), 1, constants.MaxUint32, nil) + maxBytes := constants.MaxUint32 + txs, _, err := hndlr.GetTxsForProposal(nil, context.TODO(), 1, maxBytes, nil) if err != nil { t.Fatal(err) } diff --git a/application/pendingtx/pendingtxhandler.go b/application/pendingtx/pendingtxhandler.go index 4e96a616..945d5d80 100644 --- a/application/pendingtx/pendingtxhandler.go +++ b/application/pendingtx/pendingtxhandler.go @@ -193,19 +193,21 @@ func (pt *Handler) DeleteMined(txnState *badger.Txn, currentHeight uint32, txHas // GetTxsForProposal returns an set of txs that are mutually exclusive with // respect to the consumed UTXOs. This is used to genrete new proposals. -func (pt *Handler) GetTxsForProposal(txnState *badger.Txn, ctx context.Context, currentHeight uint32, maxBytes uint32, tx *objs.Tx) (objs.TxVec, error) { - utxos, err := pt.getTxsInternal(txnState, ctx, currentHeight, maxBytes, tx, false) +func (pt *Handler) GetTxsForProposal(txnState *badger.Txn, ctx context.Context, currentHeight uint32, maxBytes uint32, tx *objs.Tx) (objs.TxVec, uint32, error) { + var utxos objs.TxVec + var err error + utxos, maxBytes, err = pt.getTxsInternal(txnState, ctx, currentHeight, maxBytes, tx, false) if err != nil { utils.DebugTrace(pt.logger, err) - return nil, err + return nil, 0, err } - return utxos, nil + return utxos, maxBytes, nil } // GetTxsForGossip returns the oldest non-expired and non-consumed txs from the // tx pool. These txs may be conflicting in terms of consumed UTXOS. func (pt *Handler) GetTxsForGossip(txnState *badger.Txn, ctx context.Context, currentHeight uint32, maxBytes uint32) ([]*objs.Tx, error) { - utxos, err := pt.getTxsInternal(txnState, ctx, currentHeight, maxBytes, nil, true) + utxos, _, err := pt.getTxsInternal(txnState, ctx, currentHeight, maxBytes, nil, true) if err != nil { utils.DebugTrace(pt.logger, err) return nil, err @@ -218,16 +220,16 @@ func (pt *Handler) GetTxsForGossip(txnState *badger.Txn, ctx context.Context, cu /////////PRIVATE METHODS//////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// -func (pt *Handler) getTxsInternal(txnState *badger.Txn, ctx context.Context, currentHeight uint32, maxBytes uint32, tx *objs.Tx, allowConflict bool) ([]*objs.Tx, error) { +func (pt *Handler) getTxsInternal(txnState *badger.Txn, ctx context.Context, currentHeight uint32, maxBytes uint32, tx *objs.Tx, allowConflict bool) ([]*objs.Tx, uint32, error) { txs := objs.TxVec{} if tx != nil { txs = append(txs, tx) } + byteCount := uint32(0) + if len(txs) > 0 { + byteCount += constants.HashLen + } err := pt.db.View(func(txn *badger.Txn) error { - byteCount := uint32(0) - if len(txs) > 0 { - byteCount += constants.HashLen - } it, prefix := pt.indexer.GetOrderedIter(txn) err := func() error { defer it.Close() @@ -309,16 +311,18 @@ func (pt *Handler) getTxsInternal(txnState *badger.Txn, ctx context.Context, cur } return nil }) + if err != nil { + utils.DebugTrace(pt.logger, err) + return nil, 0, err + } out := []*objs.Tx{} for i := 0; i < len(txs); i++ { if txs[i] != nil { out = append(out, txs[i]) } } - if err != nil { - utils.DebugTrace(pt.logger, err) - } - return out, err + remainingBytes := maxBytes - byteCount + return out, remainingBytes, err } func (pt *Handler) checkSize(maxBytes uint32, byteCount uint32) bool { diff --git a/application/txhandler.go b/application/txhandler.go index 0786c5e1..74c654bf 100644 --- a/application/txhandler.go +++ b/application/txhandler.go @@ -13,6 +13,7 @@ import ( "github.com/MadBase/MadNet/application/objs/uint256" "github.com/MadBase/MadNet/application/pendingtx" "github.com/MadBase/MadNet/application/utxohandler" + "github.com/MadBase/MadNet/application/wrapper" trie "github.com/MadBase/MadNet/badgerTrie" consensusdb "github.com/MadBase/MadNet/consensus/db" "github.com/MadBase/MadNet/constants" @@ -31,13 +32,19 @@ type txHandler struct { mTxHdlr *minedtx.MinedTxHandler dHdlr *deposit.Handler uHdlr *utxohandler.UTXOHandler + storage *wrapper.Storage } func (tm *txHandler) GetTxsForGossip(txnState *badger.Txn, currentHeight uint32) ([]*objs.Tx, error) { ctx := context.Background() subCtx, cf := context.WithTimeout(ctx, 100*time.Millisecond) defer cf() - return tm.pTxHdlr.GetTxsForGossip(txnState, subCtx, currentHeight, constants.MaxBytes) + utxos, err := tm.pTxHdlr.GetTxsForGossip(txnState, subCtx, currentHeight, tm.storage.GetMaxBytes()) + if err != nil { + utils.DebugTrace(tm.logger, err) + return nil, err + } + return utxos, nil } func (tm *txHandler) IsValid(txn *badger.Txn, tx []*objs.Tx, currentHeight uint32) (objs.Vout, error) { @@ -77,7 +84,7 @@ func (tm *txHandler) ApplyState(txn *badger.Txn, chainID uint32, height uint32, utils.DebugTrace(tm.logger, err) return nil, err } - if err := txs.Validate(height, vout); err != nil { + if err := txs.Validate(height, vout, tm.storage); err != nil { utils.DebugTrace(tm.logger, err) return nil, err } @@ -106,7 +113,7 @@ func (tm *txHandler) GetTxsForProposal(txn *badger.Txn, chainID uint32, height u ctx := context.Background() subCtx, cf := context.WithTimeout(ctx, 1*time.Second) defer cf() - tx, err := tm.uHdlr.GetExpiredForProposal(txn, subCtx, chainID, height, curveSpec, signer, maxBytes) + tx, maxBytes, err := tm.uHdlr.GetExpiredForProposal(txn, subCtx, chainID, height, curveSpec, signer, maxBytes, tm.storage) if err != nil { utils.DebugTrace(tm.logger, err) return nil, nil, errorz.ErrInvalid{}.New(err.Error()) @@ -133,7 +140,7 @@ func (tm *txHandler) GetTxsForProposal(txn *badger.Txn, chainID uint32, height u return nil, nil, err } } - txs, err := tm.pTxHdlr.GetTxsForProposal(txn, subCtx, height, maxBytes, tx) + txs, _, err := tm.pTxHdlr.GetTxsForProposal(txn, subCtx, height, maxBytes, tx) if err != nil { utils.DebugTrace(tm.logger, err) return nil, nil, errorz.ErrInvalid{}.New(err.Error()) diff --git a/application/utxohandler/utxohandler.go b/application/utxohandler/utxohandler.go index 93422fae..e61f5011 100644 --- a/application/utxohandler/utxohandler.go +++ b/application/utxohandler/utxohandler.go @@ -13,6 +13,7 @@ import ( "github.com/MadBase/MadNet/application/objs" "github.com/MadBase/MadNet/application/objs/uint256" "github.com/MadBase/MadNet/application/utxohandler/utxotrie" + "github.com/MadBase/MadNet/application/wrapper" trie "github.com/MadBase/MadNet/badgerTrie" "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/crypto" @@ -128,7 +129,7 @@ func (ut *UTXOHandler) IsValid(txn *badger.Txn, txs objs.TxVec, currentHeight ui for j := 0; j < len(utxos); j++ { refUTXOs = append(refUTXOs, utxos[j]) } - if err := tx.ValidateEqualVinVout(refUTXOs, currentHeight); err != nil { + if err := tx.ValidateEqualVinVout(currentHeight, refUTXOs); err != nil { utils.DebugTrace(ut.logger, err) return nil, err } @@ -416,22 +417,22 @@ func (ut *UTXOHandler) GetData(txn *badger.Txn, owner *objs.Owner, dataIdx []byt // GetExpiredForProposal returns a list of UTXOs, the IDs of those UTXOs, and // the total byte count of the returned UTXOs. This is used to collect expired // dataStores for deletion. -func (ut *UTXOHandler) GetExpiredForProposal(txn *badger.Txn, ctx context.Context, chainID, height uint32, curveSpec constants.CurveSpec, signer objs.Signer, maxBytes uint32) (*objs.Tx, error) { - utxoIDs, _ := ut.expIndex.GetExpiredObjects(txn, utils.Epoch(height), maxBytes) +func (ut *UTXOHandler) GetExpiredForProposal(txn *badger.Txn, ctx context.Context, chainID, height uint32, curveSpec constants.CurveSpec, signer objs.Signer, maxBytes uint32, storage *wrapper.Storage) (*objs.Tx, uint32, error) { + utxoIDs, remaingBytes := ut.expIndex.GetExpiredObjects(txn, utils.Epoch(height), maxBytes, constants.MaxTxVectorLength) utxos := []*objs.TXOut{} var utxoID []byte for i := 0; i < len(utxoIDs); i++ { utxoID = utils.CopySlice(utxoIDs[i]) select { case <-ctx.Done(): - return nil, nil + return nil, maxBytes, nil default: // this prevents a node from losing a turn to propose due to taking too long } missing, err := ut.trie.Contains(txn, [][]byte{utils.CopySlice(utxoID)}) if err != nil { utils.DebugTrace(ut.logger, err) - return nil, err + return nil, 0, err } if len(missing) > 0 { continue @@ -439,7 +440,7 @@ func (ut *UTXOHandler) GetExpiredForProposal(txn *badger.Txn, ctx context.Contex utxo, err := ut.getInternal(txn, utils.CopySlice(utxoID)) if err != nil { utils.DebugTrace(ut.logger, err) - return nil, err + return nil, 0, err } utxos = append(utxos, utxo) if len(utxos) == constants.MaxTxVectorLength { @@ -451,30 +452,30 @@ func (ut *UTXOHandler) GetExpiredForProposal(txn *badger.Txn, ctx context.Contex txIns, err := utxos.MakeTxIn() if err != nil { utils.DebugTrace(ut.logger, err) - return nil, err + return nil, 0, err } value, err := utxos.RemainingValue(height) if err != nil { utils.DebugTrace(ut.logger, err) - return nil, err + return nil, 0, err } pubk, err := signer.Pubkey() if err != nil { utils.DebugTrace(ut.logger, err) - return nil, err + return nil, 0, err } account := crypto.GetAccount(pubk) - vsf := &objs.ValueStore{} - err = vsf.New(chainID, value, account, curveSpec, make([]byte, constants.HashLen)) + vs := &objs.ValueStore{} + err = vs.New(chainID, value, uint256.Zero(), account, curveSpec, make([]byte, constants.HashLen)) if err != nil { utils.DebugTrace(ut.logger, err) - return nil, err + return nil, 0, err } utxo := &objs.TXOut{} - err = utxo.NewValueStore(vsf) + err = utxo.NewValueStore(vs) if err != nil { utils.DebugTrace(ut.logger, err) - return nil, err + return nil, 0, err } tx := &objs.Tx{ Vin: txIns, @@ -483,23 +484,23 @@ func (ut *UTXOHandler) GetExpiredForProposal(txn *badger.Txn, ctx context.Contex err = tx.SetTxHash() if err != nil { utils.DebugTrace(ut.logger, err) - return nil, err + return nil, 0, err } for i := 0; i < len(utxos); i++ { ds, err := utxos[i].DataStore() if err != nil { utils.DebugTrace(ut.logger, err) - return nil, err + return nil, 0, err } err = ds.Sign(txIns[i], signer) if err != nil { utils.DebugTrace(ut.logger, err) - return nil, err + return nil, 0, err } } - return tx, nil + return tx, remaingBytes, nil } - return nil, nil + return nil, maxBytes, nil } // GetValueForOwner allows a list of utxoIDs to be returned that are equal or diff --git a/application/utxohandler/utxohandler_test.go b/application/utxohandler/utxohandler_test.go index 1a476f31..65dd3590 100644 --- a/application/utxohandler/utxohandler_test.go +++ b/application/utxohandler/utxohandler_test.go @@ -56,8 +56,9 @@ func makeTxs(t *testing.T, s objs.Signer, v *objs.ValueStore) *objs.Tx { Value: value, Owner: &objs.ValueStoreOwner{SVA: objs.ValueStoreSVA, CurveSpec: constants.CurveSecp256k1, Account: crypto.GetAccount(pubkey)}, TXOutIdx: 0, + Fee: new(uint256.Uint256).SetZero(), }, - TxHash: make([]byte, 32), + TxHash: make([]byte, constants.HashLen), } newUTXO := &objs.TXOut{} err = newUTXO.NewValueStore(newValueStore) diff --git a/application/utxohandler/utxotrie/utxotrie.go b/application/utxohandler/utxotrie/utxotrie.go index 66cd7f47..7cf4b5f7 100644 --- a/application/utxohandler/utxotrie/utxotrie.go +++ b/application/utxohandler/utxotrie/utxotrie.go @@ -3,11 +3,10 @@ package utxotrie import ( "bytes" - "github.com/MadBase/MadNet/constants/dbprefix" - - aobjs "github.com/MadBase/MadNet/application/objs" + "github.com/MadBase/MadNet/application/objs" trie "github.com/MadBase/MadNet/badgerTrie" "github.com/MadBase/MadNet/constants" + "github.com/MadBase/MadNet/constants/dbprefix" "github.com/MadBase/MadNet/logging" "github.com/MadBase/MadNet/utils" "github.com/dgraph-io/badger/v2" @@ -164,7 +163,7 @@ func (ut *UTXOTrie) Contains(txn *badger.Txn, utxoIDs [][]byte) ([][]byte, error return missing, nil } -func (ut *UTXOTrie) ApplyState(txn *badger.Txn, txs aobjs.TxVec, height uint32) ([]byte, error) { +func (ut *UTXOTrie) ApplyState(txn *badger.Txn, txs objs.TxVec, height uint32) ([]byte, error) { current, fn, err := ut.session(txn) if err != nil { utils.DebugTrace(ut.logger, err) @@ -251,7 +250,7 @@ func (ut *UTXOTrie) GetCurrentStateRoot(txn *badger.Txn) ([]byte, error) { return rt, nil } -func (ut *UTXOTrie) GetStateRootForProposal(txn *badger.Txn, txs aobjs.TxVec) ([]byte, error) { +func (ut *UTXOTrie) GetStateRootForProposal(txn *badger.Txn, txs objs.TxVec) ([]byte, error) { if len(txs) == 0 { sr, err := GetCurrentStateRoot(txn) if err != nil { @@ -274,7 +273,7 @@ func (ut *UTXOTrie) GetStateRootForProposal(txn *badger.Txn, txs aobjs.TxVec) ([ return sr, nil } -func (ut *UTXOTrie) add(txn *badger.Txn, txs aobjs.TxVec, current *trie.SMT, fn func(txn *badger.Txn, current *trie.SMT, newUTXOIDs [][]byte, newUTXOHashes [][]byte, consumedUTXOIDS [][]byte) ([]byte, error)) ([]byte, error) { +func (ut *UTXOTrie) add(txn *badger.Txn, txs objs.TxVec, current *trie.SMT, fn func(txn *badger.Txn, current *trie.SMT, newUTXOIDs [][]byte, newUTXOHashes [][]byte, consumedUTXOIDS [][]byte) ([]byte, error)) ([]byte, error) { addkeys := [][]byte{} addvalues := [][]byte{} delkeys := [][]byte{} diff --git a/application/wrapper/storage.go b/application/wrapper/storage.go new file mode 100644 index 00000000..b00d6a83 --- /dev/null +++ b/application/wrapper/storage.go @@ -0,0 +1,69 @@ +package wrapper + +import ( + "github.com/MadBase/MadNet/dynamics" + + "github.com/MadBase/MadNet/application/objs/uint256" +) + +// Storage wraps the dynamics.StorageGetter interface to make +// it easier to interact within application logic +type Storage struct { + storage dynamics.StorageGetter +} + +// NewStorage creates a new storage struct which wraps +// the StorageGetter interface +func NewStorage(storageInter dynamics.StorageGetter) *Storage { + storage := &Storage{storage: storageInter} + return storage +} + +// GetMaxBytes returns MaxBytes +func (s *Storage) GetMaxBytes() uint32 { + return s.storage.GetMaxBytes() +} + +// GetAtomicSwapFee returns the fee for AtomicSwap +func (s *Storage) GetAtomicSwapFee() (*uint256.Uint256, error) { + fee := s.storage.GetAtomicSwapFee() + feeUint256 := &uint256.Uint256{} + _, err := feeUint256.FromBigInt(fee) + if err != nil { + return nil, err + } + return feeUint256, nil +} + +// GetDataStoreEpochFee returns the per-epoch fee of DataStore +func (s *Storage) GetDataStoreEpochFee() (*uint256.Uint256, error) { + fee := s.storage.GetDataStoreEpochFee() + feeUint256 := &uint256.Uint256{} + _, err := feeUint256.FromBigInt(fee) + if err != nil { + return nil, err + } + return feeUint256, nil +} + +// GetValueStoreFee returns the fee of ValueStore +func (s *Storage) GetValueStoreFee() (*uint256.Uint256, error) { + fee := s.storage.GetValueStoreFee() + feeUint256 := &uint256.Uint256{} + _, err := feeUint256.FromBigInt(fee) + if err != nil { + return nil, err + } + return feeUint256, nil +} + +// GetMinTxFee returns the minimum TxFee +func (s *Storage) GetMinTxFee() (*uint256.Uint256, error) { + fee := s.storage.GetMinTxFee() + feeUint256 := &uint256.Uint256{} + _, err := feeUint256.FromBigInt(fee) + if err != nil { + return nil, err + } + return feeUint256, nil +} diff --git a/cmd/testutils/inject/main.go b/cmd/testutils/inject/main.go index 14fc085d..c4d7ceb7 100644 --- a/cmd/testutils/inject/main.go +++ b/cmd/testutils/inject/main.go @@ -229,7 +229,10 @@ func (f *funder) setupTestingSigner(i int) (aobjs.Signer, []byte, error) { func (f *funder) setupBNSigner(privk []byte) (*crypto.BNSigner, []byte, error) { signer := &crypto.BNSigner{} - signer.SetPrivk(privk) + err := signer.SetPrivk(privk) + if err != nil { + return nil, nil, err + } pubk, err := signer.Pubkey() if err != nil { return nil, nil, err @@ -279,7 +282,7 @@ func (f *funder) setupTransaction(signer aobjs.Signer, ownerAcct []byte, consume Vin: aobjs.Vin{}, Vout: aobjs.Vout{}, } - chainID := uint32(0) + chainID := uint32(42) for _, utxo := range consumedUtxos { consumedVS, err := utxo.ValueStore() if err != nil { @@ -306,6 +309,7 @@ func (f *funder) setupTransaction(signer aobjs.Signer, ownerAcct []byte, consume Value: uint256.One(), Owner: newOwner, TXOutIdx: 0, + Fee: new(uint256.Uint256).SetZero(), }, TxHash: make([]byte, constants.HashLen), } @@ -327,6 +331,7 @@ func (f *funder) setupTransaction(signer aobjs.Signer, ownerAcct []byte, consume Value: diff, Owner: newOwner, TXOutIdx: 0, + Fee: new(uint256.Uint256).SetZero(), }, TxHash: make([]byte, constants.HashLen), } @@ -479,7 +484,7 @@ func (f *funder) setupDataStoreTransaction(ctx context.Context, signer aobjs.Sig Vin: aobjs.Vin{}, Vout: aobjs.Vout{}, } - chainID := uint32(0) + chainID := uint32(42) for _, utxo := range consumedUtxos { consumedVS, err := utxo.ValueStore() if err != nil { @@ -518,6 +523,7 @@ func (f *funder) setupDataStoreTransaction(ctx context.Context, signer aobjs.Sig RawData: []byte(msg), TXOutIdx: 0, Owner: newOwner, + Fee: new(uint256.Uint256).SetZero(), }, TxHash: make([]byte, constants.HashLen), }, @@ -529,7 +535,10 @@ func (f *funder) setupDataStoreTransaction(ctx context.Context, signer aobjs.Sig fmt.Printf("Consumed Next:%v ValueOut:%v\n", consumedValue, valueOut) fmt.Printf("DS: index:%x deposit:%v EpochOfExpire:%v msg:%s\n", index, deposit, eoe, msg) newUTXO := &aobjs.TXOut{} - newUTXO.NewDataStore(newDataStore) + err = newUTXO.NewDataStore(newDataStore) + if err != nil { + panic(err) + } tx.Vout = append(tx.Vout, newUTXO) } fmt.Printf("Consumed Next:%v ValueOut:%v\n", consumedValue, valueOut) @@ -546,19 +555,29 @@ func (f *funder) setupDataStoreTransaction(ctx context.Context, signer aobjs.Sig Value: diff, Owner: newOwner, TXOutIdx: 0, + Fee: new(uint256.Uint256).SetZero(), }, TxHash: make([]byte, constants.HashLen), } newUTXO := &aobjs.TXOut{} - newUTXO.NewValueStore(newValueStore) + err = newUTXO.NewValueStore(newValueStore) + if err != nil { + panic(err) + } tx.Vout = append(tx.Vout, newUTXO) //valueOut += diff valueOut.Add(valueOut, diff) } fmt.Printf("Consumed Next:%v ValueOut:%v\n", consumedValue, valueOut) - tx.Vout.SetTxOutIdx() + err = tx.Vout.SetTxOutIdx() + if err != nil { + panic(err) + } fmt.Printf("Consumed Next:%v ValueOut:%v\n", consumedValue, valueOut) - tx.SetTxHash() + err = tx.SetTxHash() + if err != nil { + panic(err) + } for _, newUtxo := range tx.Vout { switch { case newUtxo.HasDataStore(): @@ -581,14 +600,20 @@ func (f *funder) setupDataStoreTransaction(ctx context.Context, signer aobjs.Sig return nil, err } txIn := tx.Vin[idx] - consumedVS.Sign(txIn, signer) + err = consumedVS.Sign(txIn, signer) + if err != nil { + panic(err) + } case consumedUtxo.HasDataStore(): consumedDS, err := consumedUtxo.DataStore() if err != nil { return nil, err } txIn := tx.Vin[idx] - consumedDS.Sign(txIn, signer) + err = consumedDS.Sign(txIn, signer) + if err != nil { + panic(err) + } } } fmt.Printf("Consumed Next:%v ValueOut:%v\n", consumedValue, valueOut) @@ -665,7 +690,7 @@ func (f *funder) setupDataStoreTransaction2(ctx context.Context, signer aobjs.Si Vin: aobjs.Vin{}, Vout: aobjs.Vout{}, } - chainID := uint32(0) + chainID := uint32(42) for _, utxo := range consumedUtxos { consumedVS, err := utxo.ValueStore() if err != nil { @@ -713,6 +738,7 @@ func (f *funder) setupDataStoreTransaction2(ctx context.Context, signer aobjs.Si RawData: []byte(msg), TXOutIdx: 0, Owner: newOwner, + Fee: new(uint256.Uint256).SetZero(), }, TxHash: make([]byte, constants.HashLen), }, @@ -741,6 +767,7 @@ func (f *funder) setupDataStoreTransaction2(ctx context.Context, signer aobjs.Si Value: diff, Owner: newOwner, TXOutIdx: 0, + Fee: new(uint256.Uint256).SetZero(), }, TxHash: make([]byte, constants.HashLen), } @@ -864,7 +891,7 @@ func (f *funder) setupDataStoreTransaction3(ctx context.Context, signer aobjs.Si Vin: aobjs.Vin{}, Vout: aobjs.Vout{}, } - chainID := uint32(0) + chainID := uint32(42) for _, utxo := range consumedUtxos { consumedVS, err := utxo.ValueStore() if err != nil { @@ -912,6 +939,7 @@ func (f *funder) setupDataStoreTransaction3(ctx context.Context, signer aobjs.Si RawData: []byte(msg), TXOutIdx: 0, Owner: newOwner, + Fee: new(uint256.Uint256).SetZero(), }, TxHash: make([]byte, constants.HashLen), }, @@ -940,6 +968,7 @@ func (f *funder) setupDataStoreTransaction3(ctx context.Context, signer aobjs.Si Value: diff, Owner: newOwner, TXOutIdx: 0, + Fee: new(uint256.Uint256).SetZero(), }, TxHash: make([]byte, constants.HashLen), } diff --git a/cmd/testutils/many_utxos/main.go b/cmd/testutils/many_utxos/main.go index 6961774b..04181c77 100644 --- a/cmd/testutils/many_utxos/main.go +++ b/cmd/testutils/many_utxos/main.go @@ -117,7 +117,10 @@ func (f *funder) setupTestingSigner(i int) (aobjs.Signer, []byte, error) { func (f *funder) setupBNSigner(privk []byte) (*crypto.BNSigner, []byte, error) { signer := &crypto.BNSigner{} - signer.SetPrivk(privk) + err := signer.SetPrivk(privk) + if err != nil { + return nil, nil, err + } pubk, err := signer.Pubkey() if err != nil { return nil, nil, err diff --git a/cmd/validator/validator.go b/cmd/validator/validator.go index 8f8bdc7f..eaa4d7b4 100644 --- a/cmd/validator/validator.go +++ b/cmd/validator/validator.go @@ -27,6 +27,7 @@ import ( "github.com/MadBase/MadNet/consensus/request" "github.com/MadBase/MadNet/constants" mncrypto "github.com/MadBase/MadNet/crypto" + "github.com/MadBase/MadNet/dynamics" "github.com/MadBase/MadNet/localrpc" "github.com/MadBase/MadNet/logging" "github.com/MadBase/MadNet/peering" @@ -242,6 +243,9 @@ func validatorNode(cmd *cobra.Command, args []string) { // synchronizes execution context, makes sure everything synchronizes with the ctx system - throughout modules consSync := &consensus.Synchronizer{} + // define storage to dynamic values + storage := &dynamics.Storage{} + // account signer for ETH accounts secp256k1Signer := &mncrypto.Secp256k1Signer{} @@ -261,19 +265,24 @@ func validatorNode(cmd *cobra.Command, args []string) { consTxPool.Init(consDB) appDepositHandler.Init() - if err := app.Init(consDB, rawTxPoolDb, appDepositHandler); err != nil { + if err := app.Init(consDB, rawTxPoolDb, appDepositHandler, storage); err != nil { + panic(err) + } + + // Initialize storage + if err := storage.Init(consDB, logger); err != nil { panic(err) } // Initialize consensus - consReqClient.Init(peerManager.P2PClient()) - consReqHandler.Init(consDB, app) + consReqClient.Init(peerManager.P2PClient(), storage) + consReqHandler.Init(consDB, app, storage) consDlManager.Init(consDB, app, consReqClient) consLSHandler.Init(consDB, consDlManager) - consGossipHandlers.Init(consDB, peerManager.P2PClient(), app, consLSHandler) - consGossipClient.Init(consDB, peerManager.P2PClient(), app) - consAdminHandlers.Init(chainID, consDB, mncrypto.Hasher([]byte(config.Configuration.Validator.SymmetricKey)), app, publicKey) - consLSEngine.Init(consDB, consDlManager, app, secp256k1Signer, consAdminHandlers, publicKey, consReqClient) + consGossipHandlers.Init(consDB, peerManager.P2PClient(), app, consLSHandler, storage) + consGossipClient.Init(consDB, peerManager.P2PClient(), app, storage) + consAdminHandlers.Init(chainID, consDB, mncrypto.Hasher([]byte(config.Configuration.Validator.SymmetricKey)), app, publicKey, storage) + consLSEngine.Init(consDB, consDlManager, app, secp256k1Signer, consAdminHandlers, publicKey, consReqClient, storage) // Setup Request Bus svcs := monitor.NewServices(eth, consDB, appDepositHandler, consAdminHandlers, batchSize, chainID) @@ -296,7 +305,7 @@ func validatorNode(cmd *cobra.Command, args []string) { mDB = rawMonitorDb } - consSync.Init(consDB, mDB, tDB, consGossipClient, consGossipHandlers, consTxPool, consLSEngine, app, consAdminHandlers, peerManager) + consSync.Init(consDB, mDB, tDB, consGossipClient, consGossipHandlers, consTxPool, consLSEngine, app, consAdminHandlers, peerManager, storage) localStateHandler.Init(consDB, app, consGossipHandlers, publicKey, consSync.Safe) statusLogger.Init(consLSEngine, peerManager, consAdminHandlers, mon) @@ -306,6 +315,8 @@ func validatorNode(cmd *cobra.Command, args []string) { defer func() { os.Exit(0) }() defer func() { logger.Warning("Graceful unwind of core process complete.") }() + go storage.Start() + go statusLogger.Run() defer statusLogger.Close() diff --git a/consensus/admin/handlers.go b/consensus/admin/handlers.go index 7f148849..8ff4bb08 100644 --- a/consensus/admin/handlers.go +++ b/consensus/admin/handlers.go @@ -11,6 +11,7 @@ import ( "github.com/MadBase/MadNet/consensus/objs" "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/crypto" + "github.com/MadBase/MadNet/dynamics" "github.com/MadBase/MadNet/errorz" "github.com/MadBase/MadNet/interfaces" "github.com/MadBase/MadNet/logging" @@ -41,11 +42,12 @@ type Handlers struct { ethAcct []byte ethPubk []byte appHandler appmock.Application + storage dynamics.StorageGetter ReceiveLock chan interfaces.Lockable } // Init creates all fields and binds external services -func (ah *Handlers) Init(chainID uint32, database *db.Database, secret []byte, appHandler appmock.Application, ethPubk []byte) { +func (ah *Handlers) Init(chainID uint32, database *db.Database, secret []byte, appHandler appmock.Application, ethPubk []byte, storage dynamics.StorageGetter) { ctx := context.Background() subCtx, cancelFunc := context.WithCancel(ctx) ah.ctx = subCtx @@ -58,6 +60,7 @@ func (ah *Handlers) Init(chainID uint32, database *db.Database, secret []byte, a ah.secret = utils.CopySlice(secret) ah.ethAcct = crypto.GetAccount(ethPubk) ah.ReceiveLock = make(chan interfaces.Lockable) + ah.storage = storage } // Close shuts down all workers @@ -260,6 +263,28 @@ func (ah *Handlers) AddSnapshot(bh *objs.BlockHeader, startingEthDKG bool) error }) } +// UpdateDynamicStorage updates dynamic storage values. +func (ah *Handlers) UpdateDynamicStorage(txn *badger.Txn, key, value string, epoch uint32) error { + mutex, ok := ah.getLock() + if !ok { + return nil + } + mutex.Lock() + defer mutex.Unlock() + + update, err := dynamics.NewUpdate(key, value, epoch) + if err != nil { + utils.DebugTrace(ah.logger, err) + return err + } + err = ah.storage.UpdateStorage(txn, update) + if err != nil { + utils.DebugTrace(ah.logger, err) + return err + } + return nil +} + // IsInitialized returns if the database has been initialized yet func (ah *Handlers) IsInitialized() bool { ah.RLock() @@ -369,7 +394,10 @@ func (ah *Handlers) AddPrivateKey(pk []byte, curveSpec constants.CurveSpec) erro privk := utils.CopySlice(pk) // bn key signer := crypto.BNGroupSigner{} - signer.SetPrivk(privk) + err := signer.SetPrivk(privk) + if err != nil { + return err + } pubkey, err := signer.PubkeyShare() if err != nil { return err diff --git a/consensus/db/db.go b/consensus/db/db.go index df23240c..4c6e2d58 100644 --- a/consensus/db/db.go +++ b/consensus/db/db.go @@ -37,11 +37,11 @@ func (db *Database) DB() *badger.DB { return db.rawDB.db } -func (db *Database) View(fn TxnFunc) error { +func (db *Database) View(fn func(txn *badger.Txn) error) error { return db.rawDB.View(fn) } -func (db *Database) Update(fn TxnFunc) error { +func (db *Database) Update(fn func(txn *badger.Txn) error) error { db.Lock() defer db.Unlock() return db.rawDB.Update(fn) @@ -55,6 +55,14 @@ func (db *Database) GarbageCollect() error { return db.rawDB.GarbageCollect() } +func (db *Database) SetValue(txn *badger.Txn, key, value []byte) error { + return db.rawDB.SetValue(txn, key, value) +} + +func (db *Database) GetValue(txn *badger.Txn, key []byte) ([]byte, error) { + return db.rawDB.getValue(txn, key) +} + //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// diff --git a/consensus/db/db_test.go b/consensus/db/db_test.go index 9eba61ea..b9de43bb 100644 --- a/consensus/db/db_test.go +++ b/consensus/db/db_test.go @@ -82,15 +82,21 @@ func newDB(t *testing.T) (*testDB, *Database, *testparams) { func TestRoundState(t *testing.T) { groupSigner := &crypto.BNGroupSigner{} - groupSigner.SetPrivk(crypto.Hasher([]byte("secret"))) + err := groupSigner.SetPrivk(crypto.Hasher([]byte("secret"))) + if err != nil { + t.Fatal(err) + } groupKey, _ := groupSigner.PubkeyShare() bnSigner := &crypto.BNGroupSigner{} - bnSigner.SetPrivk(crypto.Hasher([]byte("secret2"))) + err = bnSigner.SetPrivk(crypto.Hasher([]byte("secret2"))) + if err != nil { + t.Fatal(err) + } bnKey, _ := groupSigner.PubkeyShare() secpSigner := &crypto.Secp256k1Signer{} - err := secpSigner.SetPrivk(crypto.Hasher([]byte("secret3"))) + err = secpSigner.SetPrivk(crypto.Hasher([]byte("secret3"))) if err != nil { t.Fatal(err) } @@ -147,15 +153,21 @@ func TestRoundState(t *testing.T) { func TestBlockHeader(t *testing.T) { groupSigner := &crypto.BNGroupSigner{} - groupSigner.SetPrivk(crypto.Hasher([]byte("secret"))) + err := groupSigner.SetPrivk(crypto.Hasher([]byte("secret"))) + if err != nil { + t.Fatal(err) + } bnSigner := &crypto.BNGroupSigner{} - bnSigner.SetPrivk(crypto.Hasher([]byte("secret2"))) + err = bnSigner.SetPrivk(crypto.Hasher([]byte("secret2"))) + if err != nil { + t.Fatal(err) + } tbd, db, p := newDB(t) defer tbd.Close() badgerD := tbd.db - err := badgerD.Update(func(txn *badger.Txn) error { + err = badgerD.Update(func(txn *badger.Txn) error { sig, err := groupSigner.Sign(p.PrevBlock) if err != nil { t.Fatal(err) @@ -286,15 +298,21 @@ func TestBlockHeader(t *testing.T) { func TestEncryptedStore(t *testing.T) { groupSigner := &crypto.BNGroupSigner{} - groupSigner.SetPrivk(crypto.Hasher([]byte("secret"))) + err := groupSigner.SetPrivk(crypto.Hasher([]byte("secret"))) + if err != nil { + t.Fatal(err) + } bnSigner := &crypto.BNGroupSigner{} - bnSigner.SetPrivk(crypto.Hasher([]byte("secret2"))) + err = bnSigner.SetPrivk(crypto.Hasher([]byte("secret2"))) + if err != nil { + t.Fatal(err) + } tbd, db, _ := newDB(t) defer tbd.Close() badgerD := tbd.db - err := badgerD.Update(func(txn *badger.Txn) error { + err = badgerD.Update(func(txn *badger.Txn) error { name := []byte("foo") ec := &objs.EncryptedStore{ Name: name, @@ -319,18 +337,24 @@ func TestEncryptedStore(t *testing.T) { func TestValidatorSet(t *testing.T) { groupSigner := &crypto.BNGroupSigner{} - groupSigner.SetPrivk(crypto.Hasher([]byte("secret"))) + err := groupSigner.SetPrivk(crypto.Hasher([]byte("secret"))) + if err != nil { + t.Fatal(err) + } groupKey, _ := groupSigner.PubkeyShare() bnSigner := &crypto.BNGroupSigner{} - bnSigner.SetPrivk(crypto.Hasher([]byte("secret2"))) + err = bnSigner.SetPrivk(crypto.Hasher([]byte("secret2"))) + if err != nil { + t.Fatal(err) + } tbd, db, p := newDB(t) _ = p _ = db defer tbd.Close() badgerD := tbd.db - err := badgerD.Update(func(txn *badger.Txn) error { + err = badgerD.Update(func(txn *badger.Txn) error { vkey0 := crypto.Hasher([]byte("s0"))[12:] gShare0 := crypto.Hasher([]byte("g0")) val0 := &objs.Validator{ @@ -402,21 +426,27 @@ func TestValidatorSet(t *testing.T) { func TestSnapShotMany(t *testing.T) { groupSigner := &crypto.BNGroupSigner{} - groupSigner.SetPrivk(crypto.Hasher([]byte("secret"))) + err := groupSigner.SetPrivk(crypto.Hasher([]byte("secret"))) + if err != nil { + t.Fatal(err) + } bnSigner := &crypto.BNGroupSigner{} - bnSigner.SetPrivk(crypto.Hasher([]byte("secret2"))) + err = bnSigner.SetPrivk(crypto.Hasher([]byte("secret2"))) + if err != nil { + t.Fatal(err) + } tbd, db, p := newDB(t) defer tbd.Close() badgerD := tbd.db var bhash []byte - err := badgerD.Update(func(txn *badger.Txn) error { + err = badgerD.Update(func(txn *badger.Txn) error { sig, err := groupSigner.Sign(p.PrevBlock) if err != nil { t.Fatal(err) } - for i := uint32(1); i < 1025; i++ { + for i := uint32(1); i < constants.EpochLength+1; i++ { bh := &objs.BlockHeader{ SigGroup: sig, BClaims: &objs.BClaims{ @@ -467,16 +497,22 @@ func TestSnapShotMany(t *testing.T) { func TestSnapShotOne(t *testing.T) { groupSigner := &crypto.BNGroupSigner{} - groupSigner.SetPrivk(crypto.Hasher([]byte("secret"))) + err := groupSigner.SetPrivk(crypto.Hasher([]byte("secret"))) + if err != nil { + t.Fatal(err) + } bnSigner := &crypto.BNGroupSigner{} - bnSigner.SetPrivk(crypto.Hasher([]byte("secret2"))) + err = bnSigner.SetPrivk(crypto.Hasher([]byte("secret2"))) + if err != nil { + t.Fatal(err) + } tbd, db, p := newDB(t) defer tbd.Close() badgerD := tbd.db var bhash []byte - err := badgerD.Update(func(txn *badger.Txn) error { + err = badgerD.Update(func(txn *badger.Txn) error { sig, err := groupSigner.Sign(p.PrevBlock) if err != nil { t.Fatal(err) @@ -528,21 +564,27 @@ func TestSnapShotOne(t *testing.T) { func TestGetLastCommittedBHFSMany(t *testing.T) { groupSigner := &crypto.BNGroupSigner{} - groupSigner.SetPrivk(crypto.Hasher([]byte("secret"))) + err := groupSigner.SetPrivk(crypto.Hasher([]byte("secret"))) + if err != nil { + t.Fatal(err) + } bnSigner := &crypto.BNGroupSigner{} - bnSigner.SetPrivk(crypto.Hasher([]byte("secret2"))) + err = bnSigner.SetPrivk(crypto.Hasher([]byte("secret2"))) + if err != nil { + t.Fatal(err) + } tbd, db, p := newDB(t) defer tbd.Close() badgerD := tbd.db var bhash []byte - err := badgerD.Update(func(txn *badger.Txn) error { + err = badgerD.Update(func(txn *badger.Txn) error { sig, err := groupSigner.Sign(p.PrevBlock) if err != nil { t.Fatal(err) } - for i := uint32(1); i < 1025; i++ { + for i := uint32(1); i < constants.EpochLength+1; i++ { bh := &objs.BlockHeader{ SigGroup: sig, BClaims: &objs.BClaims{ @@ -591,16 +633,22 @@ func TestGetLastCommittedBHFSMany(t *testing.T) { func TestGetLastCommittedBHFSOne(t *testing.T) { groupSigner := &crypto.BNGroupSigner{} - groupSigner.SetPrivk(crypto.Hasher([]byte("secret"))) + err := groupSigner.SetPrivk(crypto.Hasher([]byte("secret"))) + if err != nil { + t.Fatal(err) + } bnSigner := &crypto.BNGroupSigner{} - bnSigner.SetPrivk(crypto.Hasher([]byte("secret2"))) + err = bnSigner.SetPrivk(crypto.Hasher([]byte("secret2"))) + if err != nil { + t.Fatal(err) + } tbd, db, p := newDB(t) defer tbd.Close() badgerD := tbd.db var bhash []byte - err := badgerD.Update(func(txn *badger.Txn) error { + err = badgerD.Update(func(txn *badger.Txn) error { sig, err := groupSigner.Sign(p.PrevBlock) if err != nil { t.Fatal(err) diff --git a/consensus/db/rawdb.go b/consensus/db/rawdb.go index 489b9c8e..b6cad36e 100644 --- a/consensus/db/rawdb.go +++ b/consensus/db/rawdb.go @@ -34,11 +34,11 @@ type rawDataBase struct { logger *logrus.Logger } -func (db *rawDataBase) View(fn TxnFunc) error { +func (db *rawDataBase) View(fn func(txn *badger.Txn) error) error { return db.db.View(fn) } -func (db *rawDataBase) Update(fn TxnFunc) error { +func (db *rawDataBase) Update(fn func(txn *badger.Txn) error) error { txn := db.db.NewTransaction(true) defer txn.Discard() if err := fn(txn); err != nil { diff --git a/consensus/dman/actors_test.go b/consensus/dman/actors_test.go index d6701126..d976fa60 100644 --- a/consensus/dman/actors_test.go +++ b/consensus/dman/actors_test.go @@ -302,7 +302,10 @@ func makeGoodBlock(t *testing.T) []*objs.BlockHeader { t.Fatal(err) } gk := crypto.BNGroupSigner{} - gk.SetPrivk(crypto.Hasher([]byte("secret"))) + err = gk.SetPrivk(crypto.Hasher([]byte("secret"))) + if err != nil { + t.Fatal(err) + } sig, err := gk.Sign(bhsh) if err != nil { t.Fatal(err) diff --git a/consensus/dman/dman.go b/consensus/dman/dman.go index 896ffc32..71bd4557 100644 --- a/consensus/dman/dman.go +++ b/consensus/dman/dman.go @@ -159,7 +159,7 @@ func (dm *DMan) SyncOneBH(txn *badger.Txn, syncToBH *objs.BlockHeader, maxBHSeen bhCache, inCache := dm.downloadActor.bhc.Get(targetHeight) if !inCache && currentHeight != targetHeight { - for i := currentHeight + 1; i < currentHeight+1024; i++ { + for i := currentHeight + 1; i < currentHeight+constants.EpochLength; i++ { height := i if height > maxBHSeen.BClaims.Height { break @@ -226,7 +226,6 @@ func (dm *DMan) SyncOneBH(txn *badger.Txn, syncToBH *objs.BlockHeader, maxBHSeen } return txs, bhCache, true, nil - } func (dm *DMan) DownloadTxs(height, round uint32, txHshLst [][]byte) { diff --git a/consensus/dman/txcache_test.go b/consensus/dman/txcache_test.go index be7162ad..383da99d 100644 --- a/consensus/dman/txcache_test.go +++ b/consensus/dman/txcache_test.go @@ -76,6 +76,8 @@ func Test_txCache_GetHeight(t *testing.T) { h2t, _ := txs2[0].TxHash() if string(h2t) != string(h2) { + t.Logf("h2: %s", h2) + t.Logf("h2t: %s", h2t) t.Fatal("2: bad hash") } txs3, _ := txc.GetHeight(3) diff --git a/consensus/gossip/client.go b/consensus/gossip/client.go index dbca7e5e..ed67ce9e 100644 --- a/consensus/gossip/client.go +++ b/consensus/gossip/client.go @@ -9,6 +9,7 @@ import ( "github.com/MadBase/MadNet/consensus/lstate" "github.com/MadBase/MadNet/consensus/objs" "github.com/MadBase/MadNet/constants" + "github.com/MadBase/MadNet/dynamics" "github.com/MadBase/MadNet/interfaces" "github.com/MadBase/MadNet/logging" "github.com/MadBase/MadNet/middleware" @@ -77,6 +78,7 @@ type Client struct { lastHeight uint32 lastRound uint32 app appClient + storage dynamics.StorageGetter inSync *mutexBool isValidator *mutexBool @@ -84,7 +86,7 @@ type Client struct { // Init sets ups all subscriptions. This MUST be run at least once. // It has no effect if run more than once. -func (mb *Client) Init(database *db.Database, client pb.P2PClient, app appClient) { +func (mb *Client) Init(database *db.Database, client pb.P2PClient, app appClient, storage dynamics.StorageGetter) { background := context.Background() ctx, cf := context.WithCancel(background) mb.logger = logging.GetLogger(constants.LoggerGossipBus) @@ -97,6 +99,7 @@ func (mb *Client) Init(database *db.Database, client pb.P2PClient, app appClient mb.sstore = &lstate.Store{} mb.inSync = &mutexBool{} mb.isValidator = &mutexBool{} + mb.storage = storage mb.sstore.Init(database) mb.gossipTimeout = constants.MsgTimeout } diff --git a/consensus/gossip/handlers.go b/consensus/gossip/handlers.go index f0311ecb..f5ed5991 100644 --- a/consensus/gossip/handlers.go +++ b/consensus/gossip/handlers.go @@ -5,6 +5,7 @@ import ( "time" "github.com/MadBase/MadNet/constants" + "github.com/MadBase/MadNet/dynamics" "github.com/MadBase/MadNet/errorz" "github.com/MadBase/MadNet/utils" "google.golang.org/grpc/codes" @@ -49,7 +50,8 @@ type Handlers struct { // channels acts as per message queues with validation occurring before // the message is queued up - app appHandler + app appHandler + storage dynamics.StorageGetter height *mutexUint32 chainID *mutexUint32 @@ -72,7 +74,7 @@ func (mb *Handlers) getLock(ctx context.Context) (interfaces.Lockable, bool) { // Init will initialize the gossip consumer // it must be run at least once and will have no // effect if run more than once -func (mb *Handlers) Init(database *db.Database, client pb.P2PClient, app appHandler, handlers *lstate.Handlers) { +func (mb *Handlers) Init(database *db.Database, client pb.P2PClient, app appHandler, handlers *lstate.Handlers, storage dynamics.StorageGetter) { mb.logger = logging.GetLogger(constants.LoggerGossipBus) mb.client = client mb.app = app @@ -82,6 +84,7 @@ func (mb *Handlers) Init(database *db.Database, client pb.P2PClient, app appHand ctx, cf := context.WithCancel(background) mb.cancelCtx = cf mb.ctx = ctx + mb.storage = storage mb.height = &mutexUint32{} mb.chainID = &mutexUint32{} mb.isSync = &mutexBool{} diff --git a/consensus/gossip/state_test.go b/consensus/gossip/state_test.go index 6a621bae..3568d900 100644 --- a/consensus/gossip/state_test.go +++ b/consensus/gossip/state_test.go @@ -483,7 +483,10 @@ func makeSigners(t *testing.T) ([]byte, []*crypto.BNGroupSigner, [][]byte, []*cr gpk1 := new(bn256.G2).ScalarBaseMult(gsk1) groupShares[0] = gpk1.Marshal() s1 := new(crypto.BNGroupSigner) - s1.SetPrivk(gsk1.Bytes()) + err := s1.SetPrivk(gsk1.Bytes()) + if err != nil { + t.Fatal(err) + } sig1, err := s1.Sign(msg) if err != nil { t.Fatal(err) @@ -494,7 +497,10 @@ func makeSigners(t *testing.T) ([]byte, []*crypto.BNGroupSigner, [][]byte, []*cr gpk2 := new(bn256.G2).ScalarBaseMult(gsk2) groupShares[1] = gpk2.Marshal() s2 := new(crypto.BNGroupSigner) - s2.SetPrivk(gsk2.Bytes()) + err = s2.SetPrivk(gsk2.Bytes()) + if err != nil { + t.Fatal(err) + } sig2, err := s2.Sign(msg) if err != nil { t.Fatal(err) @@ -505,7 +511,10 @@ func makeSigners(t *testing.T) ([]byte, []*crypto.BNGroupSigner, [][]byte, []*cr gpk3 := new(bn256.G2).ScalarBaseMult(gsk3) groupShares[2] = gpk3.Marshal() s3 := new(crypto.BNGroupSigner) - s3.SetPrivk(gsk3.Bytes()) + err = s3.SetPrivk(gsk3.Bytes()) + if err != nil { + t.Fatal(err) + } sig3, err := s3.Sign(msg) if err != nil { t.Fatal(err) @@ -516,7 +525,10 @@ func makeSigners(t *testing.T) ([]byte, []*crypto.BNGroupSigner, [][]byte, []*cr gpk4 := new(bn256.G2).ScalarBaseMult(gsk4) groupShares[3] = gpk4.Marshal() s4 := new(crypto.BNGroupSigner) - s4.SetPrivk(gsk4.Bytes()) + err = s4.SetPrivk(gsk4.Bytes()) + if err != nil { + t.Fatal(err) + } sig4, err := s4.Sign(msg) if err != nil { t.Fatal(err) diff --git a/consensus/lstate/appman.go b/consensus/lstate/appman.go index c8b69723..7ad51f0b 100644 --- a/consensus/lstate/appman.go +++ b/consensus/lstate/appman.go @@ -7,9 +7,8 @@ import ( "github.com/MadBase/MadNet/consensus/objs" "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/errorz" - "github.com/MadBase/MadNet/utils" - "github.com/MadBase/MadNet/interfaces" + "github.com/MadBase/MadNet/utils" "github.com/dgraph-io/badger/v2" ) @@ -33,7 +32,7 @@ func (ce *Engine) AddPendingTx(txn *badger.Txn, d []interfaces.Transaction) erro func (ce *Engine) getValidValue(txn *badger.Txn, rs *RoundStates) ([][]byte, []byte, []byte, []byte, error) { chainID := rs.OwnState.SyncToBH.BClaims.ChainID - txs, stateRoot, err := ce.appHandler.GetValidProposal(txn, chainID, rs.OwnState.SyncToBH.BClaims.Height+1, constants.MaxProposalSize) + txs, stateRoot, err := ce.appHandler.GetValidProposal(txn, chainID, rs.OwnState.SyncToBH.BClaims.Height+1, ce.storage.GetMaxProposalSize()) if err != nil { utils.DebugTrace(ce.logger, err) return nil, nil, nil, nil, err @@ -62,7 +61,7 @@ func (ce *Engine) getValidValue(txn *badger.Txn, rs *RoundStates) ([][]byte, []b utils.DebugTrace(ce.logger, err) return nil, nil, nil, nil, err } - headerRoot = make([]byte, 32) + headerRoot = make([]byte, constants.HashLen) } return txHashes, txRootHash, stateRoot, headerRoot, nil } diff --git a/consensus/lstate/engine.go b/consensus/lstate/engine.go index 477f6ddb..b3e2e2f8 100644 --- a/consensus/lstate/engine.go +++ b/consensus/lstate/engine.go @@ -6,9 +6,6 @@ import ( "errors" "fmt" - "github.com/MadBase/MadNet/errorz" - "github.com/MadBase/MadNet/utils" - "github.com/MadBase/MadNet/consensus/admin" "github.com/MadBase/MadNet/consensus/appmock" "github.com/MadBase/MadNet/consensus/db" @@ -17,7 +14,10 @@ import ( "github.com/MadBase/MadNet/consensus/request" "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/crypto" + "github.com/MadBase/MadNet/dynamics" + "github.com/MadBase/MadNet/errorz" "github.com/MadBase/MadNet/logging" + "github.com/MadBase/MadNet/utils" "github.com/dgraph-io/badger/v2" "github.com/sirupsen/logrus" ) @@ -44,11 +44,13 @@ type Engine struct { ethAcct []byte EthPubk []byte + storage dynamics.StorageGetter + dm *dman.DMan } // Init will initialize the Consensus Engine and all sub modules -func (ce *Engine) Init(database *db.Database, dm *dman.DMan, app appmock.Application, signer *crypto.Secp256k1Signer, adminHandlers *admin.Handlers, publicKey []byte, rbusClient *request.Client) { +func (ce *Engine) Init(database *db.Database, dm *dman.DMan, app appmock.Application, signer *crypto.Secp256k1Signer, adminHandlers *admin.Handlers, publicKey []byte, rbusClient *request.Client, storage dynamics.StorageGetter) { background := context.Background() ctx, cf := context.WithCancel(background) ce.cancelCtx = cf @@ -70,9 +72,11 @@ func (ce *Engine) Init(database *db.Database, dm *dman.DMan, app appmock.Applica appHandler: app, requestBus: ce.RequestBus, } - ce.fastSync.Init(database) + ce.storage = storage + ce.fastSync.Init(database, storage) } +// Status updates the status of the consensus engine func (ce *Engine) Status(status map[string]interface{}) (map[string]interface{}, error) { var rs *RoundStates err := ce.database.View(func(txn *badger.Txn) error { @@ -102,6 +106,7 @@ func (ce *Engine) Status(status map[string]interface{}) (map[string]interface{}, return status, nil } +// UpdateLocalState updates the local state of the consensus engine func (ce *Engine) UpdateLocalState() (bool, error) { var isSync bool updateLocalState := true @@ -152,6 +157,12 @@ func (ce *Engine) UpdateLocalState() (bool, error) { if err != nil { return err } + // Load storage + err = ce.storage.LoadStorage(txn, utils.Epoch(roundState.OwnState.SyncToBH.BClaims.Height)) + if err != nil { + utils.DebugTrace(ce.logger, err) + return err + } if roundState.OwnState.SyncToBH.BClaims.Height%constants.EpochLength == 0 { safe, err := ce.database.GetSafeToProceed(txn, roundState.OwnState.SyncToBH.BClaims.Height) if err != nil { @@ -376,6 +387,11 @@ func (ce *Engine) updateLocalStateInternal(txn *badger.Txn, rs *RoundStates) (bo return true, nil } + // Ensure that storage has updated values + proposalStepTO := ce.storage.GetProposalStepTimeout() + preVoteStepTO := ce.storage.GetPreVoteStepTimeout() + preCommitStepTO := ce.storage.GetPreCommitStepTimeout() + // iterate all possibles from nextRound down to proposal // and take that action ISProposer := rs.LocalIsProposer() @@ -385,9 +401,9 @@ func (ce *Engine) updateLocalStateInternal(txn *badger.Txn, rs *RoundStates) (bo PCCurrent := os.PCCurrent(rcert) PCNCurrent := os.PCNCurrent(rcert) NRCurrent := os.NRCurrent(rcert) - PTOExpired := rs.OwnValidatingState.PTOExpired() - PVTOExpired := rs.OwnValidatingState.PVTOExpired() - PCTOExpired := rs.OwnValidatingState.PCTOExpired() + PTOExpired := rs.OwnValidatingState.PTOExpired(proposalStepTO) + PVTOExpired := rs.OwnValidatingState.PVTOExpired(preVoteStepTO) + PCTOExpired := rs.OwnValidatingState.PCTOExpired(preCommitStepTO) // dispatch to handlers if NRCurrent { @@ -482,6 +498,7 @@ func (ce *Engine) updateLocalStateInternal(txn *badger.Txn, rs *RoundStates) (bo return true, nil } +// Sync attempts to synchronize the local state of consensus engine func (ce *Engine) Sync() (bool, error) { // see if sync is done // if yes exit @@ -495,6 +512,11 @@ func (ce *Engine) Sync() (bool, error) { } return nil } + err = ce.storage.LoadStorage(txn, utils.Epoch(rs.OwnState.SyncToBH.BClaims.Height)) + if err != nil { + utils.DebugTrace(ce.logger, err) + return err + } // begin handling logic if rs.OwnState.MaxBHSeen.BClaims.Height == rs.OwnState.SyncToBH.BClaims.Height { syncDone = true @@ -599,7 +621,11 @@ func (ce *Engine) loadValidationKey(rs *RoundStates) error { return nil } signer := &crypto.BNGroupSigner{} - signer.SetPrivk(pk) + err = signer.SetPrivk(pk) + if err != nil { + utils.DebugTrace(ce.logger, err) + return nil + } err = signer.SetGroupPubk(rs.ValidatorSet.GroupKey) if err != nil { utils.DebugTrace(ce.logger, err) diff --git a/consensus/lstate/fastsync.go b/consensus/lstate/fastsync.go index 7d22aad9..c71dd748 100644 --- a/consensus/lstate/fastsync.go +++ b/consensus/lstate/fastsync.go @@ -13,6 +13,7 @@ import ( "github.com/MadBase/MadNet/consensus/objs" "github.com/MadBase/MadNet/consensus/request" "github.com/MadBase/MadNet/constants" + "github.com/MadBase/MadNet/dynamics" "github.com/MadBase/MadNet/errorz" "github.com/MadBase/MadNet/logging" "github.com/MadBase/MadNet/middleware" @@ -243,15 +244,15 @@ type bhCache struct { minHeight uint32 } -func (sc *bhCache) Init() { - sc.objs = make(map[nodeKey]*stateResponse) +func (bhc *bhCache) Init() { + bhc.objs = make(map[nodeKey]*stateResponse) } -func (sc *bhCache) getLeafKeys(maxNumber int) []nodeKey { - sc.RLock() - defer sc.RUnlock() +func (bhc *bhCache) getLeafKeys(maxNumber int) []nodeKey { + bhc.RLock() + defer bhc.RUnlock() nodeKeys := []nodeKey{} - for k := range sc.objs { + for k := range bhc.objs { nodeKeys = append(nodeKeys, k) if len(nodeKeys) >= maxNumber { break @@ -260,38 +261,38 @@ func (sc *bhCache) getLeafKeys(maxNumber int) []nodeKey { return nodeKeys } -func (sc *bhCache) contains(nk nodeKey) bool { - sc.RLock() - defer sc.RUnlock() - if sc.objs[nk] == nil { +func (bhc *bhCache) contains(nk nodeKey) bool { + bhc.RLock() + defer bhc.RUnlock() + if bhc.objs[nk] == nil { return false } return true } -func (sc *bhCache) insert(sr *stateResponse) error { - sc.Lock() - defer sc.Unlock() +func (bhc *bhCache) insert(sr *stateResponse) error { + bhc.Lock() + defer bhc.Unlock() nk, err := newNodeKey(sr.key) if err != nil { return err } - sc.objs[nk] = sr + bhc.objs[nk] = sr return nil } -func (sc *bhCache) pop(key []byte) (*stateResponse, error) { - sc.Lock() - defer sc.Unlock() +func (bhc *bhCache) pop(key []byte) (*stateResponse, error) { + bhc.Lock() + defer bhc.Unlock() nk, err := newNodeKey(key) if err != nil { return nil, err } - if sc.objs[nk] == nil { + if bhc.objs[nk] == nil { return nil, errorz.ErrInvalid{}.New("Error in bhCache.pop: missing key in pop request") } - result := sc.objs[nk] - delete(sc.objs, nk) + result := bhc.objs[nk] + delete(bhc.objs, nk) return result, nil } @@ -301,15 +302,15 @@ type bhNodeCache struct { minHeight uint32 } -func (sc *bhNodeCache) Init() { - sc.objs = make(map[nodeKey]*nodeResponse) +func (bhnc *bhNodeCache) Init() { + bhnc.objs = make(map[nodeKey]*nodeResponse) } -func (sc *bhNodeCache) getNodeKeys(maxNumber int) []nodeKey { - sc.RLock() - defer sc.RUnlock() +func (bhnc *bhNodeCache) getNodeKeys(maxNumber int) []nodeKey { + bhnc.RLock() + defer bhnc.RUnlock() nodeKeys := []nodeKey{} - for k := range sc.objs { + for k := range bhnc.objs { nodeKeys = append(nodeKeys, k) if len(nodeKeys) >= maxNumber { break @@ -318,38 +319,38 @@ func (sc *bhNodeCache) getNodeKeys(maxNumber int) []nodeKey { return nodeKeys } -func (sc *bhNodeCache) contains(nk nodeKey) bool { - sc.RLock() - defer sc.RUnlock() - if sc.objs[nk] == nil { +func (bhnc *bhNodeCache) contains(nk nodeKey) bool { + bhnc.RLock() + defer bhnc.RUnlock() + if bhnc.objs[nk] == nil { return false } return true } -func (sc *bhNodeCache) insert(sr *nodeResponse) error { - sc.Lock() - defer sc.Unlock() +func (bhnc *bhNodeCache) insert(sr *nodeResponse) error { + bhnc.Lock() + defer bhnc.Unlock() nk, err := newNodeKey(sr.root) if err != nil { return err } - sc.objs[nk] = sr + bhnc.objs[nk] = sr return nil } -func (sc *bhNodeCache) pop(key []byte) (*nodeResponse, error) { - sc.Lock() - defer sc.Unlock() +func (bhnc *bhNodeCache) pop(key []byte) (*nodeResponse, error) { + bhnc.Lock() + defer bhnc.Unlock() nk, err := newNodeKey(key) if err != nil { return nil, err } - if sc.objs[nk] == nil { + if bhnc.objs[nk] == nil { return nil, errorz.ErrInvalid{}.New("Error in bhNodeCache.pop: missing key in pop request") } - result := sc.objs[nk] - delete(sc.objs, nk) + result := bhnc.objs[nk] + delete(bhnc.objs, nk) return result, nil } @@ -406,12 +407,12 @@ func (a *atomicU32) Get() uint32 { type workFunc func() type SnapShotManager struct { - appHandler appmock.Application - requestBus *request.Client - + appHandler appmock.Application + requestBus *request.Client database *db.Database logger *logrus.Logger snapShotHeight *atomicU32 + storage dynamics.StorageGetter hdrNodeCache *bhNodeCache hdrLeafCache *bhCache @@ -443,161 +444,162 @@ type SnapShotManager struct { } // Init initializes the SnapShotManager -func (ndm *SnapShotManager) Init(database *db.Database) { - ndm.snapShotHeight = new(atomicU32) - ndm.logger = logging.GetLogger(constants.LoggerConsensus) - ndm.database = database - ndm.hdrNodeCache = &bhNodeCache{} - ndm.hdrNodeCache.Init() - ndm.hdrLeafCache = &bhCache{} - ndm.hdrLeafCache.Init() - ndm.stateNodeCache = &nodeCache{} - ndm.stateNodeCache.Init() - ndm.stateLeafCache = &stateCache{} - ndm.stateLeafCache.Init() - ndm.hdrNodeDLs = &downloadTracker{ +func (ssm *SnapShotManager) Init(database *db.Database, storage dynamics.StorageGetter) { + ssm.storage = storage + ssm.snapShotHeight = new(atomicU32) + ssm.logger = logging.GetLogger(constants.LoggerConsensus) + ssm.database = database + ssm.hdrNodeCache = &bhNodeCache{} + ssm.hdrNodeCache.Init() + ssm.hdrLeafCache = &bhCache{} + ssm.hdrLeafCache.Init() + ssm.stateNodeCache = &nodeCache{} + ssm.stateNodeCache.Init() + ssm.stateLeafCache = &stateCache{} + ssm.stateLeafCache.Init() + ssm.hdrNodeDLs = &downloadTracker{ sync.RWMutex{}, make(map[nodeKey]bool), } - ndm.hdrLeafDLs = &downloadTracker{ + ssm.hdrLeafDLs = &downloadTracker{ sync.RWMutex{}, make(map[nodeKey]bool), } - ndm.stateLeafDLs = &downloadTracker{ + ssm.stateLeafDLs = &downloadTracker{ sync.RWMutex{}, make(map[nodeKey]bool), } - ndm.stateNodeDLs = &downloadTracker{ + ssm.stateNodeDLs = &downloadTracker{ sync.RWMutex{}, make(map[nodeKey]bool), } - ndm.statusChan = make(chan string) - ndm.hdrLeafDlChan = make(chan *dlReq, chanBuffering) - ndm.hdrNodeDlChan = make(chan *dlReq, chanBuffering) - ndm.stateNodeDlChan = make(chan *dlReq, chanBuffering) - ndm.stateLeafDlChan = make(chan *dlReq, chanBuffering) - ndm.workChan = make(chan workFunc, chanBuffering*2) - ndm.closeChan = make(chan struct{}) - ndm.closeOnce = sync.Once{} - - go ndm.downloadWithRetryHdrLeafWorker() - go ndm.downloadWithRetryHdrNodeWorker() - go ndm.downloadWithRetryStateLeafWorker() - go ndm.downloadWithRetryStateNodeWorker() - go ndm.loggingDelayer() -} - -func (ndm *SnapShotManager) close() { - ndm.closeOnce.Do(func() { - close(ndm.closeChan) + ssm.statusChan = make(chan string) + ssm.hdrLeafDlChan = make(chan *dlReq, chanBuffering) + ssm.hdrNodeDlChan = make(chan *dlReq, chanBuffering) + ssm.stateNodeDlChan = make(chan *dlReq, chanBuffering) + ssm.stateLeafDlChan = make(chan *dlReq, chanBuffering) + ssm.workChan = make(chan workFunc, chanBuffering*2) + ssm.closeChan = make(chan struct{}) + ssm.closeOnce = sync.Once{} + + go ssm.downloadWithRetryHdrLeafWorker() + go ssm.downloadWithRetryHdrNodeWorker() + go ssm.downloadWithRetryStateLeafWorker() + go ssm.downloadWithRetryStateNodeWorker() + go ssm.loggingDelayer() +} + +func (ssm *SnapShotManager) close() { + ssm.closeOnce.Do(func() { + close(ssm.closeChan) }) } -func (ndm *SnapShotManager) startFastSync(txn *badger.Txn, snapShotBlockHeader *objs.BlockHeader) error { - if ndm.finalizeFastSyncChan == nil { - ndm.finalizeOnce = sync.Once{} - ndm.finalizeFastSyncChan = make(chan struct{}) +func (ssm *SnapShotManager) startFastSync(txn *badger.Txn, snapShotBlockHeader *objs.BlockHeader) error { + if ssm.finalizeFastSyncChan == nil { + ssm.finalizeOnce = sync.Once{} + ssm.finalizeFastSyncChan = make(chan struct{}) for i := 0; i < minWorkers; i++ { - go ndm.worker(ndm.finalizeFastSyncChan) + go ssm.worker(ssm.finalizeFastSyncChan) } } - ndm.tailSyncHeight = snapShotBlockHeader.BClaims.Height - if err := ndm.database.SetCommittedBlockHeaderFastSync(txn, snapShotBlockHeader); err != nil { - utils.DebugTrace(ndm.logger, err) + ssm.tailSyncHeight = snapShotBlockHeader.BClaims.Height + if err := ssm.database.SetCommittedBlockHeaderFastSync(txn, snapShotBlockHeader); err != nil { + utils.DebugTrace(ssm.logger, err) return err } - ndm.snapShotHeight.Set(snapShotBlockHeader.BClaims.Height) + ssm.snapShotHeight.Set(snapShotBlockHeader.BClaims.Height) // call dropBefore on the caches - ndm.stateNodeCache.dropBefore(snapShotBlockHeader.BClaims.Height) - ndm.stateLeafCache.dropBefore(snapShotBlockHeader.BClaims.Height) + ssm.stateNodeCache.dropBefore(snapShotBlockHeader.BClaims.Height) + ssm.stateLeafCache.dropBefore(snapShotBlockHeader.BClaims.Height) // cleanup the db of any previous data - if err := ndm.cleanupDatabase(txn); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.cleanupDatabase(txn); err != nil { + utils.DebugTrace(ssm.logger, err) return err } // insert the request for the root node into the database if !bytes.Equal(utils.CopySlice(snapShotBlockHeader.BClaims.StateRoot), make([]byte, constants.HashLen)) { // Do NOT request all-zero byte slice stateRoot - if err := ndm.database.SetPendingNodeKey(txn, utils.CopySlice(snapShotBlockHeader.BClaims.StateRoot), 0); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.database.SetPendingNodeKey(txn, utils.CopySlice(snapShotBlockHeader.BClaims.StateRoot), 0); err != nil { + utils.DebugTrace(ssm.logger, err) return err } } - if err := ndm.database.SetPendingHdrNodeKey(txn, utils.CopySlice(snapShotBlockHeader.BClaims.HeaderRoot), 0); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.database.SetPendingHdrNodeKey(txn, utils.CopySlice(snapShotBlockHeader.BClaims.HeaderRoot), 0); err != nil { + utils.DebugTrace(ssm.logger, err) return err } - canonicalBHTrieKey := ndm.database.MakeHeaderTrieKeyFromHeight(snapShotBlockHeader.BClaims.Height) + canonicalBHTrieKey := ssm.database.MakeHeaderTrieKeyFromHeight(snapShotBlockHeader.BClaims.Height) bHash, err := snapShotBlockHeader.BlockHash() if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return err } - if err := ndm.database.SetPendingHdrLeafKey(txn, canonicalBHTrieKey, bHash); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.database.SetPendingHdrLeafKey(txn, canonicalBHTrieKey, bHash); err != nil { + utils.DebugTrace(ssm.logger, err) return err } return nil } -func (ndm *SnapShotManager) cleanupDatabase(txn *badger.Txn) error { - if err := ndm.database.DropPendingLeafKeys(txn); err != nil { - utils.DebugTrace(ndm.logger, err) +func (ssm *SnapShotManager) cleanupDatabase(txn *badger.Txn) error { + if err := ssm.database.DropPendingLeafKeys(txn); err != nil { + utils.DebugTrace(ssm.logger, err) return err } - if err := ndm.database.DropPendingNodeKeys(txn); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.database.DropPendingNodeKeys(txn); err != nil { + utils.DebugTrace(ssm.logger, err) return err } - if err := ndm.appHandler.BeginSnapShotSync(txn); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.appHandler.BeginSnapShotSync(txn); err != nil { + utils.DebugTrace(ssm.logger, err) return err } return nil } -func (ndm *SnapShotManager) Update(txn *badger.Txn, snapShotBlockHeader *objs.BlockHeader) (bool, error) { +func (ssm *SnapShotManager) Update(txn *badger.Txn, snapShotBlockHeader *objs.BlockHeader) (bool, error) { // a difference in height implies the target has changed for the canonical // state, thus re-init the object and drop all stale data // return after the drop so the next iteration sees the dropped data is in the // db transaction - if ndm.snapShotHeight.Get() != snapShotBlockHeader.BClaims.Height { - err := ndm.startFastSync(txn, snapShotBlockHeader) + if ssm.snapShotHeight.Get() != snapShotBlockHeader.BClaims.Height { + err := ssm.startFastSync(txn, snapShotBlockHeader) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return false, err } return false, nil } - if err := ndm.updateSync(txn, snapShotBlockHeader.BClaims.Height); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.updateSync(txn, snapShotBlockHeader.BClaims.Height); err != nil { + utils.DebugTrace(ssm.logger, err) return false, err } - hnCount, snCount, slCount, hlCount, bhCount, err := ndm.getKeyCounts(txn) + hnCount, snCount, slCount, hlCount, bhCount, err := ssm.getKeyCounts(txn) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return false, err } logMsg := fmt.Sprintf("FastSyncing@%v |HN:%v HL:%v CBH:%v |SN:%v SL:%v |Prct:%v", snapShotBlockHeader.BClaims.Height, hnCount, hlCount, bhCount, snCount, slCount, (bhCount*100)/int(snapShotBlockHeader.BClaims.Height)) - ndm.status(logMsg) - if err := ndm.updateDls(txn, snapShotBlockHeader.BClaims.Height, bhCount, hlCount); err != nil { - utils.DebugTrace(ndm.logger, err) + ssm.status(logMsg) + if err := ssm.updateDls(txn, snapShotBlockHeader.BClaims.Height, bhCount, hlCount); err != nil { + utils.DebugTrace(ssm.logger, err) return false, err } pCount := (int(snapShotBlockHeader.BClaims.Height) - bhCount) if pCount < 0 { pCount = 0 } - pCount += ndm.hdrLeafDLs.Size() + ndm.hdrNodeDLs.Size() - pCount += ndm.stateNodeDLs.Size() + ndm.stateLeafDLs.Size() + pCount += ssm.hdrLeafDLs.Size() + ssm.hdrNodeDLs.Size() + pCount += ssm.stateNodeDLs.Size() + ssm.stateLeafDLs.Size() pCount += snCount + slCount + hnCount + hlCount if pCount == 0 { - if err := ndm.finalizeSync(txn, snapShotBlockHeader); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.finalizeSync(txn, snapShotBlockHeader); err != nil { + utils.DebugTrace(ssm.logger, err) return false, err } return true, nil @@ -605,164 +607,164 @@ func (ndm *SnapShotManager) Update(txn *badger.Txn, snapShotBlockHeader *objs.Bl return false, nil } -func (ndm *SnapShotManager) status(msg string) { +func (ssm *SnapShotManager) status(msg string) { select { - case ndm.statusChan <- msg: + case ssm.statusChan <- msg: return default: return } } -func (ndm *SnapShotManager) loggingDelayer() { +func (ssm *SnapShotManager) loggingDelayer() { for { select { - case msg := <-ndm.statusChan: - ndm.logger.Info(msg) - case <-ndm.closeChan: + case msg := <-ssm.statusChan: + ssm.logger.Info(msg) + case <-ssm.closeChan: return } time.Sleep(5 * time.Second) } } -func (ndm *SnapShotManager) getKeyCounts(txn *badger.Txn) (int, int, int, int, int, error) { - hnCount, err := ndm.database.CountPendingHdrNodeKeys(txn) +func (ssm *SnapShotManager) getKeyCounts(txn *badger.Txn) (int, int, int, int, int, error) { + hnCount, err := ssm.database.CountPendingHdrNodeKeys(txn) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return 0, 0, 0, 0, 0, err } - snCount, err := ndm.database.CountPendingNodeKeys(txn) + snCount, err := ssm.database.CountPendingNodeKeys(txn) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return 0, 0, 0, 0, 0, err } - slCount, err := ndm.database.CountPendingLeafKeys(txn) + slCount, err := ssm.database.CountPendingLeafKeys(txn) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return 0, 0, 0, 0, 0, err } - hlCount, err := ndm.database.CountPendingHdrLeafKeys(txn) + hlCount, err := ssm.database.CountPendingHdrLeafKeys(txn) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return 0, 0, 0, 0, 0, err } - bhCount, err := ndm.database.CountCommittedBlockHeaders(txn) + bhCount, err := ssm.database.CountCommittedBlockHeaders(txn) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return 0, 0, 0, 0, 0, err } return hnCount, snCount, slCount, hlCount, bhCount, nil } -func (ndm *SnapShotManager) finalizeSync(txn *badger.Txn, snapShotBlockHeader *objs.BlockHeader) error { - ndm.finalizeOnce.Do(func() { close(ndm.finalizeFastSyncChan) }) - if err := ndm.database.UpdateHeaderTrieRootFastSync(txn, snapShotBlockHeader); err != nil { - utils.DebugTrace(ndm.logger, err) +func (ssm *SnapShotManager) finalizeSync(txn *badger.Txn, snapShotBlockHeader *objs.BlockHeader) error { + ssm.finalizeOnce.Do(func() { close(ssm.finalizeFastSyncChan) }) + if err := ssm.database.UpdateHeaderTrieRootFastSync(txn, snapShotBlockHeader); err != nil { + utils.DebugTrace(ssm.logger, err) return err } - if err := ndm.appHandler.FinalizeSnapShotRoot(txn, snapShotBlockHeader.BClaims.StateRoot, snapShotBlockHeader.BClaims.Height); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.appHandler.FinalizeSnapShotRoot(txn, snapShotBlockHeader.BClaims.StateRoot, snapShotBlockHeader.BClaims.Height); err != nil { + utils.DebugTrace(ssm.logger, err) return err } return nil } -func (ndm *SnapShotManager) updateDls(txn *badger.Txn, snapShotHeight uint32, bhCount int, hlCount int) error { - if err := ndm.dlHdrNodes(txn, snapShotHeight); err != nil { - utils.DebugTrace(ndm.logger, err) +func (ssm *SnapShotManager) updateDls(txn *badger.Txn, snapShotHeight uint32, bhCount int, hlCount int) error { + if err := ssm.dlHdrNodes(txn, snapShotHeight); err != nil { + utils.DebugTrace(ssm.logger, err) return err } - if err := ndm.dlHdrLeaves(txn, snapShotHeight); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.dlHdrLeaves(txn, snapShotHeight); err != nil { + utils.DebugTrace(ssm.logger, err) return err } if hlCount == 0 && bhCount >= int(snapShotHeight)-int(constants.EpochLength) { - if err := ndm.dlStateNodes(txn, snapShotHeight); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.dlStateNodes(txn, snapShotHeight); err != nil { + utils.DebugTrace(ssm.logger, err) return err } - if err := ndm.dlStateLeaves(txn, snapShotHeight); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.dlStateLeaves(txn, snapShotHeight); err != nil { + utils.DebugTrace(ssm.logger, err) return err } } return nil } -func (ndm *SnapShotManager) updateSync(txn *badger.Txn, snapShotHeight uint32) error { - if err := ndm.syncHdrNodes(txn, snapShotHeight); err != nil { - utils.DebugTrace(ndm.logger, err) +func (ssm *SnapShotManager) updateSync(txn *badger.Txn, snapShotHeight uint32) error { + if err := ssm.syncHdrNodes(txn, snapShotHeight); err != nil { + utils.DebugTrace(ssm.logger, err) return err } - if err := ndm.syncHdrLeaves(txn, snapShotHeight); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.syncHdrLeaves(txn, snapShotHeight); err != nil { + utils.DebugTrace(ssm.logger, err) return err } - if err := ndm.syncTailingBlockHeaders(txn, snapShotHeight); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.syncTailingBlockHeaders(txn, snapShotHeight); err != nil { + utils.DebugTrace(ssm.logger, err) return err } - if err := ndm.syncStateNodes(txn, snapShotHeight); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.syncStateNodes(txn, snapShotHeight); err != nil { + utils.DebugTrace(ssm.logger, err) return err } - if err := ndm.syncStateLeaves(txn, snapShotHeight); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.syncStateLeaves(txn, snapShotHeight); err != nil { + utils.DebugTrace(ssm.logger, err) return err } return nil } -func (ndm *SnapShotManager) syncHdrNodes(txn *badger.Txn, snapShotHeight uint32) error { +func (ssm *SnapShotManager) syncHdrNodes(txn *badger.Txn, snapShotHeight uint32) error { // get a set of node header keys and sync the header trie based on those // node keys - nodeHdrKeys := ndm.hdrNodeCache.getNodeKeys(maxNumber) + nodeHdrKeys := ssm.hdrNodeCache.getNodeKeys(maxNumber) for i := 0; i < len(nodeHdrKeys); i++ { - resp, err := ndm.hdrNodeCache.pop(utils.CopySlice(nodeHdrKeys[i].key[:])) + resp, err := ssm.hdrNodeCache.pop(utils.CopySlice(nodeHdrKeys[i].key[:])) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) continue } // remove the keys from the pending set in the database - err = ndm.database.DeletePendingHdrNodeKey(txn, utils.CopySlice(nodeHdrKeys[i].key[:])) + err = ssm.database.DeletePendingHdrNodeKey(txn, utils.CopySlice(nodeHdrKeys[i].key[:])) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) } // store all of those nodes into the database and get new pending keys - pendingBatch, newLayer, lvs, err := ndm.database.SetSnapShotHdrNode(txn, resp.batch, resp.root, resp.layer) + pendingBatch, newLayer, lvs, err := ssm.database.SetSnapShotHdrNode(txn, resp.batch, resp.root, resp.layer) if err != nil { // should not return if err invalid - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) continue } // store new pending keys to db for j := 0; j < len(pendingBatch); j++ { - ok, err := ndm.database.ContainsSnapShotHdrNode(txn, utils.CopySlice(pendingBatch[j])) + ok, err := ssm.database.ContainsSnapShotHdrNode(txn, utils.CopySlice(pendingBatch[j])) if err != nil { return err } if ok { continue } - if err := ndm.database.SetPendingHdrNodeKey(txn, utils.CopySlice(pendingBatch[j]), newLayer); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.database.SetPendingHdrNodeKey(txn, utils.CopySlice(pendingBatch[j]), newLayer); err != nil { + utils.DebugTrace(ssm.logger, err) return err } } for j := 0; j < len(lvs); j++ { nk, _ := newNodeKey(lvs[j].Key) - if ndm.hdrLeafDLs.Contains(nk) { + if ssm.hdrLeafDLs.Contains(nk) { continue } - if ndm.hdrLeafCache.contains(nk) { + if ssm.hdrLeafCache.contains(nk) { continue } exists := true - _, err = ndm.database.GetCommittedBlockHeaderByHash(txn, utils.CopySlice(lvs[j].Value)) + _, err = ssm.database.GetCommittedBlockHeaderByHash(txn, utils.CopySlice(lvs[j].Value)) if err != nil { if err != badger.ErrKeyNotFound { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return err } exists = false @@ -770,8 +772,8 @@ func (ndm *SnapShotManager) syncHdrNodes(txn *badger.Txn, snapShotHeight uint32) if exists { continue } - if err := ndm.database.SetPendingHdrLeafKey(txn, utils.CopySlice(lvs[j].Key), utils.CopySlice(lvs[j].Value)); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.database.SetPendingHdrLeafKey(txn, utils.CopySlice(lvs[j].Key), utils.CopySlice(lvs[j].Value)); err != nil { + utils.DebugTrace(ssm.logger, err) return err } } @@ -779,14 +781,14 @@ func (ndm *SnapShotManager) syncHdrNodes(txn *badger.Txn, snapShotHeight uint32) return nil } -func (ndm *SnapShotManager) findTailSyncHeight(txn *badger.Txn, thisHeight int, lastHeight int) (*objs.BlockHeader, error) { +func (ssm *SnapShotManager) findTailSyncHeight(txn *badger.Txn, thisHeight int, lastHeight int) (*objs.BlockHeader, error) { var lastKnown *objs.BlockHeader for i := thisHeight; lastHeight < i; i-- { if i <= 2 { break } if lastKnown == nil && i%int(constants.EpochLength) == 0 { - bh, err := ndm.database.GetCommittedBlockHeader(txn, uint32(i)) + bh, err := ssm.database.GetCommittedBlockHeader(txn, uint32(i)) if err != nil { if err != badger.ErrKeyNotFound { return nil, err @@ -796,23 +798,23 @@ func (ndm *SnapShotManager) findTailSyncHeight(txn *badger.Txn, thisHeight int, lastKnown = bh } if lastKnown == nil { - ssbh, err := ndm.database.GetSnapshotBlockHeader(txn, uint32(i)) + ssbh, err := ssm.database.GetSnapshotBlockHeader(txn, uint32(i)) if err != nil { return nil, err } if ssbh != nil { - if err := ndm.database.SetCommittedBlockHeaderFastSync(txn, ssbh); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.database.SetCommittedBlockHeaderFastSync(txn, ssbh); err != nil { + utils.DebugTrace(ssm.logger, err) return nil, err } lastKnown = ssbh } } } - bh, err := ndm.database.GetCommittedBlockHeader(txn, uint32(i)) + bh, err := ssm.database.GetCommittedBlockHeader(txn, uint32(i)) if err != nil { if err != badger.ErrKeyNotFound { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return nil, err } continue @@ -825,54 +827,54 @@ func (ndm *SnapShotManager) findTailSyncHeight(txn *badger.Txn, thisHeight int, return lastKnown, nil } -func (ndm *SnapShotManager) syncTailingBlockHeaders(txn *badger.Txn, snapShotHeight uint32) error { +func (ssm *SnapShotManager) syncTailingBlockHeaders(txn *badger.Txn, snapShotHeight uint32) error { count := 0 { - if ndm.tailSyncHeight == 2 { + if ssm.tailSyncHeight == 2 { return nil } - lastKnown, err := ndm.findTailSyncHeight(txn, int(ndm.tailSyncHeight), 1) + lastKnown, err := ssm.findTailSyncHeight(txn, int(ssm.tailSyncHeight), 1) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return err } - if lastKnown.BClaims.Height != ndm.tailSyncHeight { - ndm.tailSyncHeight = lastKnown.BClaims.Height - key := ndm.database.MakeHeaderTrieKeyFromHeight(lastKnown.BClaims.Height - 1) + if lastKnown.BClaims.Height != ssm.tailSyncHeight { + ssm.tailSyncHeight = lastKnown.BClaims.Height + key := ssm.database.MakeHeaderTrieKeyFromHeight(lastKnown.BClaims.Height - 1) exists := true - _, err = ndm.database.GetPendingHdrLeafKey(txn, utils.CopySlice(key)) + _, err = ssm.database.GetPendingHdrLeafKey(txn, utils.CopySlice(key)) if err != nil { if err != badger.ErrKeyNotFound { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return err } exists = false } nk, err := newNodeKey(utils.CopySlice(key)) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return err } - if ndm.hdrLeafDLs.Contains(nk) { + if ssm.hdrLeafDLs.Contains(nk) { exists = true } - if ndm.hdrLeafCache.contains(nk) { + if ssm.hdrLeafCache.contains(nk) { exists = true } if !exists { value := utils.CopySlice(lastKnown.BClaims.PrevBlock) - if err := ndm.database.SetPendingHdrLeafKey(txn, utils.CopySlice(key), utils.CopySlice(value)); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.database.SetPendingHdrLeafKey(txn, utils.CopySlice(key), utils.CopySlice(value)); err != nil { + utils.DebugTrace(ssm.logger, err) return err } count++ } } } - if ndm.tailSyncHeight <= constants.EpochLength { + if ssm.tailSyncHeight <= constants.EpochLength { return nil } - start := int(ndm.tailSyncHeight) - int(constants.EpochLength)%int(constants.EpochLength) + start := int(ssm.tailSyncHeight) - int(constants.EpochLength)%int(constants.EpochLength) start = int(start) * int(constants.EpochLength) if start <= int(constants.EpochLength) { return nil @@ -882,10 +884,10 @@ func (ndm *SnapShotManager) syncTailingBlockHeaders(txn *badger.Txn, snapShotHei return nil } count++ - known, err := ndm.findTailSyncHeight(txn, i, i-int(constants.EpochLength)) + known, err := ssm.findTailSyncHeight(txn, i, i-int(constants.EpochLength)) if err != nil { if err != badger.ErrKeyNotFound { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return err } continue @@ -893,39 +895,39 @@ func (ndm *SnapShotManager) syncTailingBlockHeaders(txn *badger.Txn, snapShotHei if known.BClaims.Height == 1 { return nil } - key := ndm.database.MakeHeaderTrieKeyFromHeight(known.BClaims.Height - 1) + key := ssm.database.MakeHeaderTrieKeyFromHeight(known.BClaims.Height - 1) nk, err := newNodeKey(utils.CopySlice(key)) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return err } - if ndm.hdrLeafDLs.Contains(nk) { + if ssm.hdrLeafDLs.Contains(nk) { continue } - if ndm.hdrLeafCache.contains(nk) { + if ssm.hdrLeafCache.contains(nk) { continue } - _, err = ndm.database.GetPendingHdrLeafKey(txn, utils.CopySlice(key)) + _, err = ssm.database.GetPendingHdrLeafKey(txn, utils.CopySlice(key)) if err != nil { if err != badger.ErrKeyNotFound { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return err } continue } value := utils.CopySlice(known.BClaims.PrevBlock) - if err := ndm.database.SetPendingHdrLeafKey(txn, utils.CopySlice(key), utils.CopySlice(value)); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.database.SetPendingHdrLeafKey(txn, utils.CopySlice(key), utils.CopySlice(value)); err != nil { + utils.DebugTrace(ssm.logger, err) return err } } return nil } -func (ndm *SnapShotManager) dlHdrNodes(txn *badger.Txn, snapShotHeight uint32) error { +func (ssm *SnapShotManager) dlHdrNodes(txn *badger.Txn, snapShotHeight uint32) error { count := 0 // iterate the pending keys in database and start downloads for each pending until the limit is reached - iter := ndm.database.GetPendingHdrNodeKeysIter(txn) + iter := ssm.database.GetPendingHdrNodeKeysIter(txn) defer iter.Close() for { if count >= maxNumber { @@ -933,7 +935,7 @@ func (ndm *SnapShotManager) dlHdrNodes(txn *badger.Txn, snapShotHeight uint32) e } dlroot, dllayer, isDone, err := iter.Next() if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return err } if isDone { @@ -941,25 +943,25 @@ func (ndm *SnapShotManager) dlHdrNodes(txn *badger.Txn, snapShotHeight uint32) e } nk, err := newNodeKey(utils.CopySlice(dlroot)) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return err } - ok, err := ndm.database.ContainsSnapShotHdrNode(txn, utils.CopySlice(dlroot)) + ok, err := ssm.database.ContainsSnapShotHdrNode(txn, utils.CopySlice(dlroot)) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return err } if ok { - if err := ndm.database.DeletePendingHdrNodeKey(txn, dlroot); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.database.DeletePendingHdrNodeKey(txn, dlroot); err != nil { + utils.DebugTrace(ssm.logger, err) return nil } continue } - if ndm.hdrNodeDLs.Contains(nk) { + if ssm.hdrNodeDLs.Contains(nk) { continue } - if ndm.hdrNodeCache.contains(nk) { + if ssm.hdrNodeCache.contains(nk) { continue } r := &dlReq{ @@ -967,48 +969,48 @@ func (ndm *SnapShotManager) dlHdrNodes(txn *badger.Txn, snapShotHeight uint32) e key: utils.CopySlice(dlroot), layer: dllayer, } - ndm.hdrNodeDLs.Push(nk) + ssm.hdrNodeDLs.Push(nk) select { - case ndm.hdrNodeDlChan <- r: + case ssm.hdrNodeDlChan <- r: count++ default: - ndm.hdrNodeDLs.Pop(nk) + ssm.hdrNodeDLs.Pop(nk) return nil } } } -func (ndm *SnapShotManager) syncStateNodes(txn *badger.Txn, snapShotHeight uint32) error { +func (ssm *SnapShotManager) syncStateNodes(txn *badger.Txn, snapShotHeight uint32) error { // get keys from node cache and use those keys to store elements from the // node cache into the database as well as to get the leaf keys and store // those into the database as well - nodeKeys := ndm.stateNodeCache.getNodeKeys(snapShotHeight, maxNumber) + nodeKeys := ssm.stateNodeCache.getNodeKeys(snapShotHeight, maxNumber) //for each key for i := 0; i < len(nodeKeys); i++ { - resp, err := ndm.stateNodeCache.pop(snapShotHeight, utils.CopySlice(nodeKeys[i].key[:])) + resp, err := ssm.stateNodeCache.pop(snapShotHeight, utils.CopySlice(nodeKeys[i].key[:])) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) continue } // remove the keys from the pending set in the database - err = ndm.database.DeletePendingNodeKey(txn, utils.CopySlice(nodeKeys[i].key[:])) + err = ssm.database.DeletePendingNodeKey(txn, utils.CopySlice(nodeKeys[i].key[:])) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return err } // store all of those nodes into the database and get new pending keys - pendingBatch, newLayer, lvs, err := ndm.appHandler.StoreSnapShotNode(txn, utils.CopySlice(resp.batch), utils.CopySlice(resp.root), resp.layer) + pendingBatch, newLayer, lvs, err := ssm.appHandler.StoreSnapShotNode(txn, utils.CopySlice(resp.batch), utils.CopySlice(resp.root), resp.layer) if err != nil { // should not return if err invalid - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) continue } // store pending leaves ( blockheader height/hashes) for j := 0; j < len(lvs); j++ { exists := true - if _, err := ndm.appHandler.GetSnapShotStateData(txn, utils.CopySlice(lvs[j].Key)); err != nil { + if _, err := ssm.appHandler.GetSnapShotStateData(txn, utils.CopySlice(lvs[j].Key)); err != nil { if err != badger.ErrKeyNotFound { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return err } exists = false @@ -1016,15 +1018,15 @@ func (ndm *SnapShotManager) syncStateNodes(txn *badger.Txn, snapShotHeight uint3 if exists { continue } - if err := ndm.database.SetPendingLeafKey(txn, utils.CopySlice(lvs[j].Key), utils.CopySlice(lvs[j].Value)); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.database.SetPendingLeafKey(txn, utils.CopySlice(lvs[j].Key), utils.CopySlice(lvs[j].Value)); err != nil { + utils.DebugTrace(ssm.logger, err) return err } } // store new pending keys to db for j := 0; j < len(pendingBatch); j++ { - if err := ndm.database.SetPendingNodeKey(txn, utils.CopySlice(pendingBatch[j]), newLayer); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.database.SetPendingNodeKey(txn, utils.CopySlice(pendingBatch[j]), newLayer); err != nil { + utils.DebugTrace(ssm.logger, err) return err } } @@ -1032,14 +1034,14 @@ func (ndm *SnapShotManager) syncStateNodes(txn *badger.Txn, snapShotHeight uint3 return nil } -func (ndm *SnapShotManager) dlStateNodes(txn *badger.Txn, snapShotHeight uint32) error { +func (ssm *SnapShotManager) dlStateNodes(txn *badger.Txn, snapShotHeight uint32) error { // iterate the pending keys in database and start downloads for each pending until the limit is reached - iter := ndm.database.GetPendingNodeKeysIter(txn) + iter := ssm.database.GetPendingNodeKeysIter(txn) defer iter.Close() for { dlroot, dllayer, isDone, err := iter.Next() if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return err } if isDone { @@ -1047,13 +1049,13 @@ func (ndm *SnapShotManager) dlStateNodes(txn *badger.Txn, snapShotHeight uint32) } nk, err := newNodeKey(dlroot) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return err } - if ndm.stateNodeDLs.Contains(nk) { + if ssm.stateNodeDLs.Contains(nk) { continue } - if ndm.stateNodeCache.contains(snapShotHeight, nk) { + if ssm.stateNodeCache.contains(snapShotHeight, nk) { continue } r := &dlReq{ @@ -1061,51 +1063,51 @@ func (ndm *SnapShotManager) dlStateNodes(txn *badger.Txn, snapShotHeight uint32) layer: dllayer, key: dlroot, } - ndm.stateNodeDLs.Push(nk) + ssm.stateNodeDLs.Push(nk) select { - case ndm.stateNodeDlChan <- r: + case ssm.stateNodeDlChan <- r: default: - ndm.stateNodeDLs.Pop(nk) + ssm.stateNodeDLs.Pop(nk) return nil } } } -func (ndm *SnapShotManager) syncStateLeaves(txn *badger.Txn, snapShotHeight uint32) error { +func (ssm *SnapShotManager) syncStateLeaves(txn *badger.Txn, snapShotHeight uint32) error { // get keys from state cache use those to store the state data into the db - leafKeys := ndm.stateLeafCache.getLeafKeys(snapShotHeight, maxNumber) + leafKeys := ssm.stateLeafCache.getLeafKeys(snapShotHeight, maxNumber) // loop through LeafNode keys and retrieve from stateCache; // store data before deleting from database. for i := 0; i < len(leafKeys); i++ { - resp, err := ndm.stateLeafCache.pop(snapShotHeight, utils.CopySlice(leafKeys[i].key[:])) + resp, err := ssm.stateLeafCache.pop(snapShotHeight, utils.CopySlice(leafKeys[i].key[:])) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) continue } // remove the keys from the pending set in the database - err = ndm.database.DeletePendingLeafKey(txn, utils.CopySlice(leafKeys[i].key[:])) + err = ssm.database.DeletePendingLeafKey(txn, utils.CopySlice(leafKeys[i].key[:])) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) } // store key-value state data - err = ndm.appHandler.StoreSnapShotStateData(txn, utils.CopySlice(resp.key), utils.CopySlice(resp.value), utils.CopySlice(resp.data)) + err = ssm.appHandler.StoreSnapShotStateData(txn, utils.CopySlice(resp.key), utils.CopySlice(resp.value), utils.CopySlice(resp.data)) if err != nil { // should not return if err invalid - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) continue } } return nil } -func (ndm *SnapShotManager) dlStateLeaves(txn *badger.Txn, snapShotHeight uint32) error { +func (ssm *SnapShotManager) dlStateLeaves(txn *badger.Txn, snapShotHeight uint32) error { // iterate the pending keys in database and start downloads for each pending until the limit is reached - iter := ndm.database.GetPendingLeafKeysIter(txn) + iter := ssm.database.GetPendingLeafKeysIter(txn) defer iter.Close() for { dlkey, dlvalue, isDone, err := iter.Next() if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return err } if isDone { @@ -1113,13 +1115,13 @@ func (ndm *SnapShotManager) dlStateLeaves(txn *badger.Txn, snapShotHeight uint32 } nk, err := newNodeKey(dlkey) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return err } - if ndm.stateLeafDLs.Contains(nk) { + if ssm.stateLeafDLs.Contains(nk) { continue } - if ndm.stateLeafCache.contains(snapShotHeight, nk) { + if ssm.stateLeafCache.contains(snapShotHeight, nk) { continue } r := &dlReq{ @@ -1127,55 +1129,55 @@ func (ndm *SnapShotManager) dlStateLeaves(txn *badger.Txn, snapShotHeight uint32 key: dlkey, value: dlvalue, } - ndm.stateLeafDLs.Push(nk) + ssm.stateLeafDLs.Push(nk) select { - case ndm.stateLeafDlChan <- r: + case ssm.stateLeafDlChan <- r: default: - ndm.stateLeafDLs.Pop(nk) + ssm.stateLeafDLs.Pop(nk) return nil } } } -func (ndm *SnapShotManager) syncHdrLeaves(txn *badger.Txn, snapShotHeight uint32) error { +func (ssm *SnapShotManager) syncHdrLeaves(txn *badger.Txn, snapShotHeight uint32) error { // get keys from state cache use those to store the state data into the db - leafKeys := ndm.hdrLeafCache.getLeafKeys(maxNumber) + leafKeys := ssm.hdrLeafCache.getLeafKeys(maxNumber) // loop through LeafNode keys and retrieve from stateCache; // store data before deleting from database. for i := 0; i < len(leafKeys); i++ { - resp, err := ndm.hdrLeafCache.pop(leafKeys[i].key[:]) + resp, err := ssm.hdrLeafCache.pop(leafKeys[i].key[:]) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) continue } - err = ndm.database.DeletePendingHdrLeafKey(txn, leafKeys[i].key[:]) + err = ssm.database.DeletePendingHdrLeafKey(txn, leafKeys[i].key[:]) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return err } bh := &objs.BlockHeader{} err = bh.UnmarshalBinary(resp.data) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return err } - err = ndm.database.SetCommittedBlockHeaderFastSync(txn, bh) + err = ssm.database.SetCommittedBlockHeaderFastSync(txn, bh) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return err } } return nil } -func (ndm *SnapShotManager) dlHdrLeaves(txn *badger.Txn, snapShotHeight uint32) error { +func (ssm *SnapShotManager) dlHdrLeaves(txn *badger.Txn, snapShotHeight uint32) error { // iterate the pending keys in database and start downloads for each pending until the limit is reached - iter := ndm.database.GetPendingHdrLeafKeysIter(txn) + iter := ssm.database.GetPendingHdrLeafKeysIter(txn) defer iter.Close() for { dlkey, dlvalue, isDone, err := iter.Next() if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return err } if isDone { @@ -1183,13 +1185,13 @@ func (ndm *SnapShotManager) dlHdrLeaves(txn *badger.Txn, snapShotHeight uint32) } nk, err := newNodeKey(dlkey) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return err } - if ndm.hdrLeafDLs.Contains(nk) { + if ssm.hdrLeafDLs.Contains(nk) { continue } - if ndm.hdrLeafCache.contains(nk) { + if ssm.hdrLeafCache.contains(nk) { continue } r := &dlReq{ @@ -1197,54 +1199,54 @@ func (ndm *SnapShotManager) dlHdrLeaves(txn *badger.Txn, snapShotHeight uint32) key: dlkey, value: dlvalue, } - ndm.hdrLeafDLs.Push(nk) + ssm.hdrLeafDLs.Push(nk) select { - case ndm.hdrLeafDlChan <- r: + case ssm.hdrLeafDlChan <- r: default: - ndm.hdrLeafDLs.Pop(nk) + ssm.hdrLeafDLs.Pop(nk) break } } return nil } -func (ndm *SnapShotManager) worker(killChan <-chan struct{}) { +func (ssm *SnapShotManager) worker(killChan <-chan struct{}) { for { select { case <-killChan: return - case <-ndm.closeChan: + case <-ssm.closeChan: return - case w := <-ndm.workChan: + case w := <-ssm.workChan: w() } } } -func (ndm *SnapShotManager) sendWork(w func()) { +func (ssm *SnapShotManager) sendWork(w func()) { select { - case <-ndm.closeChan: + case <-ssm.closeChan: return - case ndm.workChan <- w: + case ssm.workChan <- w: return } } -func (ndm *SnapShotManager) downloadWithRetryStateNodeWorker() { +func (ssm *SnapShotManager) downloadWithRetryStateNodeWorker() { for { select { - case <-ndm.closeChan: + case <-ssm.closeChan: return - case dl := <-ndm.stateNodeDlChan: - ndm.sendWork(ndm.downloadWithRetryStateNodeClosure(dl)) + case dl := <-ssm.stateNodeDlChan: + ssm.sendWork(ssm.downloadWithRetryStateNodeClosure(dl)) } } } -func (ndm *SnapShotManager) downloadWithRetryHdrLeafWorker() { +func (ssm *SnapShotManager) downloadWithRetryHdrLeafWorker() { for { select { - case <-ndm.closeChan: + case <-ssm.closeChan: return default: var stop <-chan time.Time @@ -1252,11 +1254,11 @@ func (ndm *SnapShotManager) downloadWithRetryHdrLeafWorker() { func() { for { select { - case <-ndm.closeChan: + case <-ssm.closeChan: return case <-stop: return - case dl := <-ndm.hdrLeafDlChan: + case dl := <-ssm.hdrLeafDlChan: if stop == nil { stop = time.After(50 * time.Millisecond) } @@ -1267,50 +1269,50 @@ func (ndm *SnapShotManager) downloadWithRetryHdrLeafWorker() { } } }() - ndm.sendWork(ndm.downloadWithRetryHdrLeafClosure(cache)) + ssm.sendWork(ssm.downloadWithRetryHdrLeafClosure(cache)) } } } -func (ndm *SnapShotManager) downloadWithRetryHdrNodeWorker() { +func (ssm *SnapShotManager) downloadWithRetryHdrNodeWorker() { for { select { - case <-ndm.closeChan: + case <-ssm.closeChan: return - case dl := <-ndm.hdrNodeDlChan: - ndm.sendWork(ndm.downloadWithRetryHdrNodeClosure(dl)) + case dl := <-ssm.hdrNodeDlChan: + ssm.sendWork(ssm.downloadWithRetryHdrNodeClosure(dl)) } } } -func (ndm *SnapShotManager) downloadWithRetryStateLeafWorker() { +func (ssm *SnapShotManager) downloadWithRetryStateLeafWorker() { for { select { - case <-ndm.closeChan: + case <-ssm.closeChan: return - case dl := <-ndm.stateLeafDlChan: - ndm.sendWork(ndm.downloadWithRetryStateLeafClosure(dl)) + case dl := <-ssm.stateLeafDlChan: + ssm.sendWork(ssm.downloadWithRetryStateLeafClosure(dl)) } } } -func (ndm *SnapShotManager) downloadWithRetryStateNodeClosure(dl *dlReq) workFunc { +func (ssm *SnapShotManager) downloadWithRetryStateNodeClosure(dl *dlReq) workFunc { snapShotHeight := dl.snapShotHeight root := dl.key layer := dl.layer nk, _ := newNodeKey(root) return func() { - defer ndm.stateNodeDLs.Pop(nk) - if snapShotHeight < ndm.snapShotHeight.Get() { + defer ssm.stateNodeDLs.Pop(nk) + if snapShotHeight < ssm.snapShotHeight.Get() { return } opts := []grpc.CallOption{ grpc_retry.WithBackoff(grpc_retry.BackoffExponentialWithJitter(backOffAmount*time.Millisecond, backOffJitter)), grpc_retry.WithMax(maxRetryCount), } - resp, err := ndm.requestBus.RequestP2PGetSnapShotNode(context.Background(), snapShotHeight, root, opts...) + resp, err := ssm.requestBus.RequestP2PGetSnapShotNode(context.Background(), snapShotHeight, root, opts...) if err != nil { - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return } if len(resp) == 0 { @@ -1323,11 +1325,11 @@ func (ndm *SnapShotManager) downloadWithRetryStateNodeClosure(dl *dlReq) workFun batch: resp, } // store to the cache - ndm.stateNodeCache.insert(snapShotHeight, nr) + ssm.stateNodeCache.insert(snapShotHeight, nr) } } -func (ndm *SnapShotManager) downloadWithRetryHdrLeafClosure(dl []*dlReq) workFunc { +func (ssm *SnapShotManager) downloadWithRetryHdrLeafClosure(dl []*dlReq) workFunc { return func() { heightList := make([]uint32, len(dl)) hashMap := make(map[uint32][]byte) @@ -1340,7 +1342,7 @@ func (ndm *SnapShotManager) downloadWithRetryHdrLeafClosure(dl []*dlReq) workFun keyMap[blockHeight] = nk heightList[i] = blockHeight hashMap[blockHeight] = utils.CopySlice(value) - defer ndm.hdrLeafDLs.Pop(nk) + defer ssm.hdrLeafDLs.Pop(nk) } opts := []grpc.CallOption{ grpc_retry.WithBackoff(grpc_retry.BackoffExponentialWithJitter(backOffAmount*time.Millisecond, backOffJitter)), @@ -1348,7 +1350,7 @@ func (ndm *SnapShotManager) downloadWithRetryHdrLeafClosure(dl []*dlReq) workFun } peerOpt := middleware.NewPeerInterceptor() newOpts := append(opts, peerOpt) - resp, err := ndm.requestBus.RequestP2PGetBlockHeaders(context.Background(), heightList, newOpts...) + resp, err := ssm.requestBus.RequestP2PGetBlockHeaders(context.Background(), heightList, newOpts...) if err != nil { return } @@ -1367,18 +1369,18 @@ func (ndm *SnapShotManager) downloadWithRetryHdrLeafClosure(dl []*dlReq) workFun bhashResp, err := resp[i].BlockHash() if err != nil { peer.Feedback(-2) - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) continue } if !bytes.Equal(bhash, bhashResp) { peer.Feedback(-2) - utils.DebugTrace(ndm.logger, errors.New("Bad block hash")) + utils.DebugTrace(ssm.logger, errors.New("Bad block hash")) continue } bhBytes, err := resp[i].MarshalBinary() if err != nil { peer.Feedback(-2) - utils.DebugTrace(ndm.logger, err) + utils.DebugTrace(ssm.logger, err) return } nk := keyMap[height] @@ -1390,19 +1392,19 @@ func (ndm *SnapShotManager) downloadWithRetryHdrLeafClosure(dl []*dlReq) workFun } // store to the cache peer.Feedback(1) - ndm.hdrLeafCache.insert(sr) + ssm.hdrLeafCache.insert(sr) } } } -func (ndm *SnapShotManager) downloadWithRetryStateLeafClosure(dl *dlReq) workFunc { +func (ssm *SnapShotManager) downloadWithRetryStateLeafClosure(dl *dlReq) workFunc { snapShotHeight := dl.snapShotHeight key := dl.key value := dl.value nk, _ := newNodeKey(key) return func() { - defer ndm.stateLeafDLs.Pop(nk) - if snapShotHeight < ndm.snapShotHeight.Get() { + defer ssm.stateLeafDLs.Pop(nk) + if snapShotHeight < ssm.snapShotHeight.Get() { return } opts := []grpc.CallOption{ @@ -1411,7 +1413,7 @@ func (ndm *SnapShotManager) downloadWithRetryStateLeafClosure(dl *dlReq) workFun } peerOpt := middleware.NewPeerInterceptor() newOpts := append(opts, peerOpt) - resp, err := ndm.requestBus.RequestP2PGetSnapShotStateData(context.Background(), key, newOpts...) + resp, err := ssm.requestBus.RequestP2PGetSnapShotStateData(context.Background(), key, newOpts...) if err != nil { return @@ -1428,11 +1430,11 @@ func (ndm *SnapShotManager) downloadWithRetryStateLeafClosure(dl *dlReq) workFun data: utils.CopySlice(resp), } // store to the cache - ndm.stateLeafCache.insert(snapShotHeight, sr) + ssm.stateLeafCache.insert(snapShotHeight, sr) } } -func (ndm *SnapShotManager) downloadWithRetryHdrNodeClosure(dl *dlReq) workFunc { +func (ssm *SnapShotManager) downloadWithRetryHdrNodeClosure(dl *dlReq) workFunc { snapShotHeight := dl.snapShotHeight root := dl.key layer := dl.layer @@ -1444,8 +1446,8 @@ func (ndm *SnapShotManager) downloadWithRetryHdrNodeClosure(dl *dlReq) workFunc } peerOpt := middleware.NewPeerInterceptor() newOpts := append(opts, peerOpt) - defer ndm.hdrNodeDLs.Pop(nk) - resp, err := ndm.requestBus.RequestP2PGetSnapShotHdrNode(context.Background(), root, newOpts...) + defer ssm.hdrNodeDLs.Pop(nk) + resp, err := ssm.requestBus.RequestP2PGetSnapShotHdrNode(context.Background(), root, newOpts...) if err != nil { return } @@ -1461,8 +1463,8 @@ func (ndm *SnapShotManager) downloadWithRetryHdrNodeClosure(dl *dlReq) workFunc batch: resp, } // store to the cache - if err := ndm.hdrNodeCache.insert(nr); err != nil { - utils.DebugTrace(ndm.logger, err) + if err := ssm.hdrNodeCache.insert(nr); err != nil { + utils.DebugTrace(ssm.logger, err) } } } diff --git a/consensus/lstate/handlers.go b/consensus/lstate/handlers.go index 6dfc0d90..f378ae4b 100644 --- a/consensus/lstate/handlers.go +++ b/consensus/lstate/handlers.go @@ -4,18 +4,16 @@ import ( "bytes" "fmt" - "github.com/MadBase/MadNet/constants" - "github.com/MadBase/MadNet/errorz" - "github.com/MadBase/MadNet/utils" - "github.com/sirupsen/logrus" - "github.com/MadBase/MadNet/consensus/db" "github.com/MadBase/MadNet/consensus/dman" "github.com/MadBase/MadNet/consensus/objs" + "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/crypto" + "github.com/MadBase/MadNet/errorz" "github.com/MadBase/MadNet/logging" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" "github.com/dgraph-io/badger/v2" + "github.com/sirupsen/logrus" ) type Handlers struct { @@ -347,7 +345,7 @@ func (mb *Handlers) PreValidate(v interface{}) error { if err != nil { return err } - GroupKey = gUtils.CopySlice(vSet.GroupKey) + GroupKey = utils.CopySlice(vSet.GroupKey) } vSet, err := mb.database.GetValidatorSet(txn, height) if err != nil { @@ -391,7 +389,7 @@ func (mb *Handlers) PreValidate(v interface{}) error { } } for _, cs := range CoSigners { - if !vSet.IsValidTuple(gUtils.CopySlice(cs), GroupKey) { + if !vSet.IsValidTuple(utils.CopySlice(cs), GroupKey) { return errorz.ErrInvalid{}.New("bad co signer") } } diff --git a/consensus/lstate/rstate.go b/consensus/lstate/rstate.go index 406a4071..adc2deb0 100644 --- a/consensus/lstate/rstate.go +++ b/consensus/lstate/rstate.go @@ -4,11 +4,10 @@ import ( "bytes" "errors" - "github.com/MadBase/MadNet/errorz" - "github.com/MadBase/MadNet/consensus/objs" "github.com/MadBase/MadNet/crypto" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/errorz" + "github.com/MadBase/MadNet/utils" ) type RoundStates struct { @@ -287,7 +286,7 @@ func (r *RoundStates) RCert() *objs.RCert { } func (r *RoundStates) PrevBlock() []byte { - prevBlock := gUtils.CopySlice(r.OwnRoundState().RCert.RClaims.PrevBlock) + prevBlock := utils.CopySlice(r.OwnRoundState().RCert.RClaims.PrevBlock) return prevBlock } diff --git a/consensus/lstate/statecastlocal.go b/consensus/lstate/statecastlocal.go index bc465990..360bd9fa 100644 --- a/consensus/lstate/statecastlocal.go +++ b/consensus/lstate/statecastlocal.go @@ -2,6 +2,7 @@ package lstate import ( "github.com/MadBase/MadNet/consensus/objs" + "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/crypto" "github.com/MadBase/MadNet/utils" "github.com/dgraph-io/badger/v2" @@ -21,7 +22,7 @@ func (ce *Engine) castNewProposalValue(txn *badger.Txn, rs *RoundStates) error { return err } if stateRoot == nil { - stateRoot = make([]byte, 32) + stateRoot = make([]byte, constants.HashLen) } p := &objs.Proposal{ PClaims: &objs.PClaims{ diff --git a/consensus/lstate/statechnglocal.go b/consensus/lstate/statechnglocal.go index d0d43885..d62d1dab 100644 --- a/consensus/lstate/statechnglocal.go +++ b/consensus/lstate/statechnglocal.go @@ -4,14 +4,12 @@ import ( "bytes" "errors" + "github.com/MadBase/MadNet/consensus/objs" "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/crypto" "github.com/MadBase/MadNet/errorz" "github.com/MadBase/MadNet/interfaces" "github.com/MadBase/MadNet/utils" - - "github.com/MadBase/MadNet/consensus/objs" - gUtils "github.com/MadBase/MadNet/utils" "github.com/dgraph-io/badger/v2" ) @@ -75,13 +73,13 @@ func (ce *Engine) doPendingPreVoteStep(txn *badger.Txn, rs *RoundStates) error { return err } bclaims := rs.OwnState.SyncToBH.BClaims - PrevBlock := gUtils.CopySlice(rcert.RClaims.PrevBlock) + PrevBlock := utils.CopySlice(rcert.RClaims.PrevBlock) headerRoot, err := ce.database.GetHeaderTrieRoot(txn, rs.OwnState.SyncToBH.BClaims.Height) if err != nil { utils.DebugTrace(ce.logger, err) return err } - StateRoot := gUtils.CopySlice(bclaims.StateRoot) + StateRoot := utils.CopySlice(bclaims.StateRoot) p := &objs.Proposal{ PClaims: &objs.PClaims{ BClaims: &objs.BClaims{ @@ -432,7 +430,8 @@ func (ce *Engine) doPendingNext(txn *badger.Txn, rs *RoundStates) error { // cast a next round if rcert.RClaims.Round != constants.DEADBLOCKROUND { if rcert.RClaims.Round == constants.DEADBLOCKROUNDNR { - if rs.OwnValidatingState.DBRNRExpired() { + dbrnrTO := ce.storage.GetDeadBlockRoundNextRoundTimeout() + if rs.OwnValidatingState.DBRNRExpired(dbrnrTO) { // Wait a long time before moving into Dead Block Round if len(pcl)+len(pcnl) >= rs.GetCurrentThreshold() { if err := ce.castNextRound(txn, rs); err != nil { @@ -557,6 +556,8 @@ func (ce *Engine) doRoundJump(txn *badger.Txn, rs *RoundStates, rc *objs.RCert) return nil } +// doCheckValidValue is called by non-validating nodes to update ValidValue +// and perform other related tasks. func (ce *Engine) doCheckValidValue(txn *badger.Txn, rs *RoundStates) error { ce.logger.Debugf("doCheckValidValue: MAXBH:%v STBH:%v RH:%v RN:%v", rs.OwnState.MaxBHSeen.BClaims.Height, rs.OwnState.SyncToBH.BClaims.Height, rs.OwnRoundState().RCert.RClaims.Height, rs.OwnRoundState().RCert.RClaims.Round) @@ -714,6 +715,8 @@ func (ce *Engine) doHeightJumpStep(txn *badger.Txn, rs *RoundStates, rcert *objs rs.OwnValidatingState.LockedValue = nil return true, nil } + // TODO: handle case (else case) in which the ValidValue does not match + // with local ValidValue; may or may not be possible. } // could not use valid value - only option left is to check if the block // had no tx's in it - if so we can build it with no additional information @@ -728,13 +731,13 @@ func (ce *Engine) doHeightJumpStep(txn *badger.Txn, rs *RoundStates, rcert *objs return false, err } bclaims := rs.OwnState.SyncToBH.BClaims - PrevBlock := gUtils.CopySlice(ownRcert.RClaims.PrevBlock) + PrevBlock := utils.CopySlice(ownRcert.RClaims.PrevBlock) headerRoot, err := ce.database.GetHeaderTrieRoot(txn, rs.OwnState.SyncToBH.BClaims.Height) if err != nil { utils.DebugTrace(ce.logger, err) return false, err } - StateRoot := gUtils.CopySlice(bclaims.StateRoot) + StateRoot := utils.CopySlice(bclaims.StateRoot) bh := &objs.BlockHeader{ BClaims: &objs.BClaims{ PrevBlock: PrevBlock, @@ -745,7 +748,7 @@ func (ce *Engine) doHeightJumpStep(txn *badger.Txn, rs *RoundStates, rcert *objs Height: ownRcert.RClaims.Height, }, TxHshLst: txs, - SigGroup: gUtils.CopySlice(rcert.SigGroup), + SigGroup: utils.CopySlice(rcert.SigGroup), } bhash, err := bh.BlockHash() if err != nil { diff --git a/consensus/objs/bclaims_test.go b/consensus/objs/bclaims_test.go index 84408b11..a871d014 100644 --- a/consensus/objs/bclaims_test.go +++ b/consensus/objs/bclaims_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/MadBase/MadNet/crypto" + "github.com/MadBase/MadNet/utils" ) func generateChain(length int) ([]*BClaims, [][][]byte, error) { @@ -129,3 +130,124 @@ func bclaimsEqual(t *testing.T, bclaims, bclaims2 *BClaims) { t.Fatal("fail") } } + +func TestBClaimsMarshal(t *testing.T) { + bh := &BlockHeader{} + _, err := bh.BClaims.MarshalBinary() + if err == nil { + t.Fatal("Should have raised error (0)") + } + + bclaims := &BClaims{} + _, err = bclaims.MarshalBinary() + if err == nil { + t.Fatal("Should have raised error (1)") + } + + bclaims = &BClaims{ + ChainID: 1, + } + _, err = bclaims.MarshalBinary() + if err == nil { + t.Fatal("Should have raised error (2)") + } + + bclaims = &BClaims{ + ChainID: 1, + Height: 1, + TxCount: 0, + } + data, err := bclaims.MarshalBinary() + if err != nil { + t.Fatal(err) + } + bc2 := &BClaims{} + err = bc2.UnmarshalBinary(data) + if err == nil { + t.Fatal("Should have raised error (3)") + } + + bclaims = &BClaims{ + ChainID: 1, + Height: 1, + TxCount: 0, + PrevBlock: crypto.Hasher([]byte("Genesis")), + } + data, err = bclaims.MarshalBinary() + if err != nil { + t.Fatal(err) + } + err = bc2.UnmarshalBinary(data) + if err == nil { + t.Fatal("Should have raised error (4)") + } + + bclaims = &BClaims{ + ChainID: 1, + Height: 1, + TxCount: 0, + PrevBlock: crypto.Hasher([]byte("Genesis")), + TxRoot: crypto.Hasher([]byte("")), + } + data, err = bclaims.MarshalBinary() + if err != nil { + t.Fatal(err) + } + err = bc2.UnmarshalBinary(data) + if err == nil { + t.Fatal("Should have raised error (5)") + } + + bclaims = &BClaims{ + ChainID: 1, + Height: 1, + TxCount: 0, + PrevBlock: crypto.Hasher([]byte("Genesis")), + TxRoot: crypto.Hasher([]byte("")), + StateRoot: crypto.Hasher([]byte("")), + } + data, err = bclaims.MarshalBinary() + if err != nil { + t.Fatal(err) + } + err = bc2.UnmarshalBinary(data) + if err == nil { + t.Fatal("Should have raised error (6)") + } + + bclaims = &BClaims{ + ChainID: 223, + Height: 225, + TxCount: 0, + PrevBlock: crypto.Hasher([]byte("Genesis")), + TxRoot: crypto.Hasher([]byte("")), + StateRoot: crypto.Hasher([]byte("")), + HeaderRoot: crypto.Hasher([]byte("")), + } + data, err = bclaims.MarshalBinary() + if err != nil { + t.Fatal(err) + } + err = bc2.UnmarshalBinary(data) + if err != nil { + t.Fatal(err) + } + + // Take valid marshaled data and raise an error for invalid ChainID + dataBad1 := utils.CopySlice(data) + dataBad1[8] = 0 + bc3 := &BClaims{} + err = bc3.UnmarshalBinary(dataBad1) + if err == nil { + t.Fatal("Should have raised error (7)") + } + + // Take valid marshaled data and raise an error for invalid Height + dataBad2 := utils.CopySlice(data) + dataBad2[12] = 0 + bc4 := &BClaims{} + err = bc4.UnmarshalBinary(dataBad2) + if err == nil { + t.Fatal("Should have raised error (8)") + } +} diff --git a/consensus/objs/bclms.go b/consensus/objs/bclms.go index d4e2c1fc..8d0e4e9a 100644 --- a/consensus/objs/bclms.go +++ b/consensus/objs/bclms.go @@ -3,7 +3,6 @@ package objs import ( "github.com/MadBase/MadNet/consensus/objs/bclaims" mdefs "github.com/MadBase/MadNet/consensus/objs/capn" - "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/crypto" "github.com/MadBase/MadNet/errorz" capnp "zombiezen.com/go/capnproto2" @@ -58,9 +57,6 @@ func (b *BClaims) UnmarshalCapn(bc mdefs.BClaims) error { b.HeaderRoot = bc.HeaderRoot() b.StateRoot = bc.StateRoot() b.TxRoot = bc.TxRoot() - if len(b.PrevBlock) != constants.HashLen { - return errorz.ErrInvalid{}.New("capn bclaims prevblock bad len") - } if b.Height < 1 { return errorz.ErrInvalid{}.New("capn bclaims bad height") } diff --git a/consensus/objs/bhIndKey.go b/consensus/objs/bhIndKey.go index a287a5d5..3b64f8d0 100644 --- a/consensus/objs/bhIndKey.go +++ b/consensus/objs/bhIndKey.go @@ -3,7 +3,7 @@ package objs import ( "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/errorz" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" ) // BlockHeaderHashIndexKey ... @@ -21,8 +21,8 @@ func (b *BlockHeaderHashIndexKey) UnmarshalBinary(data []byte) error { if len(data) != (constants.HashLen + 2) { return errorz.ErrInvalid{}.New("Invalid BlockHeaderHashIndexKey") } - b.Prefix = gUtils.CopySlice(data[0:2]) - b.BlockHash = gUtils.CopySlice(data[2:]) + b.Prefix = utils.CopySlice(data[0:2]) + b.BlockHash = utils.CopySlice(data[2:]) return nil } @@ -39,8 +39,8 @@ func (b *BlockHeaderHashIndexKey) MarshalBinary() ([]byte, error) { return nil, errorz.ErrInvalid{}.New("BlockHeaderHashIndexKey: invalid Prefix") } key := []byte{} - Prefix := gUtils.CopySlice(b.Prefix) - BlockHash := gUtils.CopySlice(b.BlockHash) + Prefix := utils.CopySlice(b.Prefix) + BlockHash := utils.CopySlice(b.BlockHash) key = append(key, Prefix...) key = append(key, BlockHash...) return key, nil diff --git a/consensus/objs/bhdr.go b/consensus/objs/bhdr.go index 2089c9bf..5e4683a6 100644 --- a/consensus/objs/bhdr.go +++ b/consensus/objs/bhdr.go @@ -3,13 +3,12 @@ package objs import ( "bytes" - "github.com/MadBase/MadNet/errorz" - "github.com/MadBase/MadNet/consensus/objs/blockheader" mdefs "github.com/MadBase/MadNet/consensus/objs/capn" "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/crypto" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/errorz" + "github.com/MadBase/MadNet/utils" capnp "zombiezen.com/go/capnproto2" ) @@ -35,29 +34,6 @@ func (b *BlockHeader) UnmarshalBinary(data []byte) error { // UnmarshalCapn unmarshals the capnproto definition of the object func (b *BlockHeader) UnmarshalCapn(bh mdefs.BlockHeader) error { - if err := b.unmarshalCapnUnsafe(bh); err != nil { - return err - } - if len(b.TxHshLst) != int(b.BClaims.TxCount) { - return errorz.ErrInvalid{}.New("cap bclaims txhsh lst len mismatch") - } - return nil -} - -// UnmarshalBinaryUnsafe unmarshals a BlockHeader in an unsafe manner; -// that is, we do not look at the TxHshLst. This is necessary during -// fast synchronization, as transactions are not synced. -func (b *BlockHeader) UnmarshalBinaryUnsafe(data []byte) error { - bh, err := blockheader.Unmarshal(data) - if err != nil { - return err - } - defer bh.Struct.Segment().Message().Reset(nil) - return b.unmarshalCapnUnsafe(bh) -} - -func (b *BlockHeader) unmarshalCapnUnsafe(bh mdefs.BlockHeader) error { - b.BClaims = &BClaims{} err := blockheader.Validate(bh) if err != nil { return err @@ -68,11 +44,19 @@ func (b *BlockHeader) unmarshalCapnUnsafe(bh mdefs.BlockHeader) error { return err } b.TxHshLst = lst + b.BClaims = &BClaims{} err = b.BClaims.UnmarshalCapn(bh.BClaims()) if err != nil { return err } - b.SigGroup = bh.SigGroup() + sigGroup := bh.SigGroup() + if len(sigGroup) != constants.CurveBN256EthSigLen { + return errorz.ErrInvalid{}.New("cap bclaims sigGroup incorrect length") + } + b.SigGroup = sigGroup + if len(b.TxHshLst) != int(b.BClaims.TxCount) { + return errorz.ErrInvalid{}.New("cap bclaims txhsh lst len mismatch") + } return nil } @@ -176,7 +160,7 @@ func (b *BlockHeader) GetRCert() (*RCert, error) { return nil, err } rc := &RCert{ - SigGroup: b.SigGroup, + SigGroup: utils.CopySlice(b.SigGroup), RClaims: &RClaims{ ChainID: b.BClaims.ChainID, Height: b.BClaims.Height + 1, @@ -193,8 +177,8 @@ func (b *BlockHeader) MakeDeadRoundProposal(rcert *RCert, headerRoot []byte) (*P return nil, errorz.ErrInvalid{}.New("not initialized") } txRoot, err := MakeTxRoot([][]byte{}) - StateRoot := gUtils.CopySlice(b.BClaims.StateRoot) - prevBlock := gUtils.CopySlice(rcert.RClaims.PrevBlock) + StateRoot := utils.CopySlice(b.BClaims.StateRoot) + prevBlock := utils.CopySlice(rcert.RClaims.PrevBlock) if err != nil { return nil, err } diff --git a/consensus/objs/bhdr_test.go b/consensus/objs/bhdr_test.go index 7e3e3b56..c3302e1c 100644 --- a/consensus/objs/bhdr_test.go +++ b/consensus/objs/bhdr_test.go @@ -18,7 +18,10 @@ func TestBlockHeader(t *testing.T) { t.Fatal(err) } gk := crypto.BNGroupSigner{} - gk.SetPrivk(crypto.Hasher([]byte("secret"))) + err = gk.SetPrivk(crypto.Hasher([]byte("secret"))) + if err != nil { + t.Fatal(err) + } sig, err := gk.Sign(bhsh) if err != nil { t.Fatal(err) @@ -82,7 +85,10 @@ func TestBlockHeaderBad(t *testing.T) { t.Fatal(err) } gk := crypto.BNGroupSigner{} - gk.SetPrivk(crypto.Hasher([]byte("secret"))) + err = gk.SetPrivk(crypto.Hasher([]byte("secret"))) + if err != nil { + t.Fatal(err) + } sig, err := gk.Sign(bhsh) if err != nil { t.Fatal(err) @@ -109,12 +115,7 @@ func TestBlockHeaderBad(t *testing.T) { t.Fatal(err) } bh2 := &BlockHeader{} - err = bh2.UnmarshalBinaryUnsafe(bhdrBytes) - if err != nil { - t.Fatal(err) - } - bh3 := &BlockHeader{} - err = bh3.UnmarshalBinary(bhdrBytes) + err = bh2.UnmarshalBinary(bhdrBytes) if err == nil { t.Fatal("Should have raised error (5)") } diff --git a/consensus/objs/capn/gen.go b/consensus/objs/capn/gen.go index 0bcd304a..df805f89 100644 --- a/consensus/objs/capn/gen.go +++ b/consensus/objs/capn/gen.go @@ -7,4 +7,4 @@ import ( // Import check to ensure capnp is installed. var _ = capnp.Tag -//go:generate capnp compile -I /home/et3p/go/src/zombiezen.com/go/capnproto2/std -ogo consensus.capnp +//go:generate capnp compile -I $GOPATH/src/zombiezen.com/go/capnproto2/std -ogo consensus.capnp diff --git a/consensus/objs/cbkey.go b/consensus/objs/cbkey.go index d5137e62..c8d9ebfd 100644 --- a/consensus/objs/cbkey.go +++ b/consensus/objs/cbkey.go @@ -2,7 +2,7 @@ package objs import ( "github.com/MadBase/MadNet/errorz" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" ) // BlockHeaderHeightKey ... @@ -20,8 +20,8 @@ func (b *BlockHeaderHeightKey) UnmarshalBinary(data []byte) error { if len(data) != 6 { return errorz.ErrInvalid{}.New("Invalid data for BlockHeaderHeightKey unmarshalling") } - b.Prefix = gUtils.CopySlice(data[0:2]) - nb, err := gUtils.UnmarshalUint32(data[2:6]) + b.Prefix = utils.CopySlice(data[0:2]) + nb, err := utils.UnmarshalUint32(data[2:6]) if err != nil { return err } @@ -39,8 +39,8 @@ func (b *BlockHeaderHeightKey) MarshalBinary() ([]byte, error) { return nil, errorz.ErrInvalid{}.New("not initialized") } key := []byte{} - Prefix := gUtils.CopySlice(b.Prefix) - nb := gUtils.MarshalUint32(b.Height) + Prefix := utils.CopySlice(b.Prefix) + nb := utils.MarshalUint32(b.Height) key = append(key, Prefix...) key = append(key, nb...) return key, nil diff --git a/consensus/objs/estore.go b/consensus/objs/estore.go index 27d64fa8..dad7b05c 100644 --- a/consensus/objs/estore.go +++ b/consensus/objs/estore.go @@ -6,12 +6,11 @@ import ( "crypto/rand" "io" - "github.com/MadBase/MadNet/errorz" - mdefs "github.com/MadBase/MadNet/consensus/objs/capn" "github.com/MadBase/MadNet/consensus/objs/estore" + "github.com/MadBase/MadNet/errorz" "github.com/MadBase/MadNet/interfaces" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" capnp "zombiezen.com/go/capnproto2" ) @@ -41,10 +40,10 @@ func (b *EncryptedStore) UnmarshalCapn(bh mdefs.EncryptedStore) error { if err != nil { return err } - b.Name = gUtils.CopySlice(bh.Name()) - b.cypherText = gUtils.CopySlice(bh.CypherText()) - b.nonce = gUtils.CopySlice(bh.Nonce()) - b.Kid = gUtils.CopySlice(bh.Kid()) + b.Name = utils.CopySlice(bh.Name()) + b.cypherText = utils.CopySlice(bh.CypherText()) + b.nonce = utils.CopySlice(bh.Nonce()) + b.Kid = utils.CopySlice(bh.Kid()) return nil } @@ -85,7 +84,7 @@ func (b *EncryptedStore) MarshalCapn(seg *capnp.Segment) (mdefs.EncryptedStore, } bh = tmp } - name := gUtils.CopySlice(b.Name) + name := utils.CopySlice(b.Name) err := bh.SetName(name) if err != nil { return mdefs.EncryptedStore{}, err diff --git a/consensus/objs/nh.go b/consensus/objs/nh.go index 551d3dd6..7e685ffb 100644 --- a/consensus/objs/nh.go +++ b/consensus/objs/nh.go @@ -3,12 +3,11 @@ package objs import ( "bytes" - "github.com/MadBase/MadNet/errorz" - mdefs "github.com/MadBase/MadNet/consensus/objs/capn" "github.com/MadBase/MadNet/consensus/objs/nextheight" "github.com/MadBase/MadNet/crypto" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/errorz" + "github.com/MadBase/MadNet/utils" capnp "zombiezen.com/go/capnproto2" ) @@ -52,7 +51,7 @@ func (b *NextHeight) UnmarshalCapn(bh mdefs.NextHeight) error { if err != nil { return err } - b.Signature = gUtils.CopySlice(bh.Signature()) + b.Signature = utils.CopySlice(bh.Signature()) return nil } @@ -135,7 +134,7 @@ func (b *NextHeight) ValidateSignatures(secpVal *crypto.Secp256k1Validator, bnVa PreCommitCE := []byte{} PreCommitCE = append(PreCommitCE, PreCommitSigDesignator()...) PreCommitCE = append(PreCommitCE, canonicalEncoding...) - pubkey, err := secpVal.Validate(PreCommitCE, gUtils.CopySlice(sig)) + pubkey, err := secpVal.Validate(PreCommitCE, utils.CopySlice(sig)) if err != nil { return err } diff --git a/consensus/objs/nh_test.go b/consensus/objs/nh_test.go index f7670c9e..b763afde 100644 --- a/consensus/objs/nh_test.go +++ b/consensus/objs/nh_test.go @@ -19,7 +19,10 @@ func TestNextHeight(t *testing.T) { t.Fatal(err) } gk := &crypto.BNGroupSigner{} - gk.SetPrivk(crypto.Hasher([]byte("secret"))) + err = gk.SetPrivk(crypto.Hasher([]byte("secret"))) + if err != nil { + t.Fatal(err) + } sig, err := gk.Sign(bhsh) if err != nil { t.Fatal(err) diff --git a/consensus/objs/nhl.go b/consensus/objs/nhl.go index e982e896..a504e7b6 100644 --- a/consensus/objs/nhl.go +++ b/consensus/objs/nhl.go @@ -2,7 +2,7 @@ package objs import ( "github.com/MadBase/MadNet/crypto" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" ) // NextHeightList ... @@ -11,7 +11,7 @@ type NextHeightList []*NextHeight func (nhl NextHeightList) MakeBlockHeader(bns *crypto.BNGroupSigner, groupShares [][]byte) (*BlockHeader, *RCert, error) { sigs := [][]byte{} for _, nh := range nhl { - sigs = append(sigs, gUtils.CopySlice(nh.NHClaims.SigShare)) + sigs = append(sigs, utils.CopySlice(nh.NHClaims.SigShare)) } SigGroup, err := bns.Aggregate(sigs, groupShares) if err != nil { @@ -28,7 +28,7 @@ func (nhl NextHeightList) MakeBlockHeader(bns *crypto.BNGroupSigner, groupShares } txHshlst := [][]byte{} for _, hsh := range nhl[0].NHClaims.Proposal.TxHshLst { - chsh := gUtils.CopySlice(hsh) + chsh := utils.CopySlice(hsh) txHshlst = append(txHshlst, chsh) } @@ -41,8 +41,8 @@ func (nhl NextHeightList) MakeBlockHeader(bns *crypto.BNGroupSigner, groupShares if err != nil { return nil, nil, err } - PrevBlockCopy := gUtils.CopySlice(PrevBlock) - SigGroupCopy := gUtils.CopySlice(SigGroup) + PrevBlockCopy := utils.CopySlice(PrevBlock) + SigGroupCopy := utils.CopySlice(SigGroup) rc := &RCert{ RClaims: &RClaims{ ChainID: bclaims.ChainID, diff --git a/consensus/objs/nr_test.go b/consensus/objs/nr_test.go index 573a2068..a1e6fa56 100644 --- a/consensus/objs/nr_test.go +++ b/consensus/objs/nr_test.go @@ -19,7 +19,10 @@ func TestNextRound(t *testing.T) { t.Fatal(err) } gk := &crypto.BNGroupSigner{} - gk.SetPrivk(crypto.Hasher([]byte("secret"))) + err = gk.SetPrivk(crypto.Hasher([]byte("secret"))) + if err != nil { + t.Fatal(err) + } sig, err := gk.Sign(bhsh) if err != nil { t.Fatal(err) diff --git a/consensus/objs/nrc.go b/consensus/objs/nrc.go index 62ed3796..e985c4ab 100644 --- a/consensus/objs/nrc.go +++ b/consensus/objs/nrc.go @@ -3,11 +3,10 @@ package objs import ( "bytes" - "github.com/MadBase/MadNet/errorz" - mdefs "github.com/MadBase/MadNet/consensus/objs/capn" "github.com/MadBase/MadNet/consensus/objs/nrclaims" "github.com/MadBase/MadNet/crypto" + "github.com/MadBase/MadNet/errorz" capnp "zombiezen.com/go/capnproto2" ) diff --git a/consensus/objs/nrl.go b/consensus/objs/nrl.go index 591c5d9b..c6f90d61 100644 --- a/consensus/objs/nrl.go +++ b/consensus/objs/nrl.go @@ -2,7 +2,7 @@ package objs import ( "github.com/MadBase/MadNet/crypto" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" ) // NextRoundList ... @@ -11,13 +11,13 @@ type NextRoundList []*NextRound func (nrl NextRoundList) MakeRoundCert(bns *crypto.BNGroupSigner, groupShares [][]byte) (*RCert, error) { sigs := [][]byte{} for _, nr := range nrl { - sigs = append(sigs, gUtils.CopySlice(nr.NRClaims.SigShare)) + sigs = append(sigs, utils.CopySlice(nr.NRClaims.SigShare)) } SigGroup, err := bns.Aggregate(sigs, groupShares) if err != nil { return nil, err } - PrevBlock := gUtils.CopySlice(nrl[0].NRClaims.RClaims.PrevBlock) + PrevBlock := utils.CopySlice(nrl[0].NRClaims.RClaims.PrevBlock) rc := &RCert{ RClaims: &RClaims{ ChainID: nrl[0].NRClaims.RClaims.ChainID, diff --git a/consensus/objs/ostate/ostate.go b/consensus/objs/ostate/ostate.go index 73a6dedb..ff77bcde 100644 --- a/consensus/objs/ostate/ostate.go +++ b/consensus/objs/ostate/ostate.go @@ -3,7 +3,7 @@ package ostate import ( mdefs "github.com/MadBase/MadNet/consensus/objs/capn" "github.com/MadBase/MadNet/errorz" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" capnp "zombiezen.com/go/capnproto2" ) @@ -14,7 +14,7 @@ func Marshal(v mdefs.OwnState) ([]byte, error) { return nil, err } defer v.Struct.Segment().Message().Reset(nil) - out := gUtils.CopySlice(raw) + out := utils.CopySlice(raw) return out, nil } diff --git a/consensus/objs/ovs.go b/consensus/objs/ovs.go index c269ebfb..fa15ad86 100644 --- a/consensus/objs/ovs.go +++ b/consensus/objs/ovs.go @@ -3,11 +3,10 @@ package objs import ( "time" - "github.com/MadBase/MadNet/errorz" - mdefs "github.com/MadBase/MadNet/consensus/objs/capn" "github.com/MadBase/MadNet/consensus/objs/ovstate" "github.com/MadBase/MadNet/constants" + "github.com/MadBase/MadNet/errorz" capnp "zombiezen.com/go/capnproto2" ) @@ -132,24 +131,24 @@ func (b *OwnValidatingState) MarshalCapn(seg *capnp.Segment) (mdefs.OwnValidatin return bh, nil } -func (b *OwnValidatingState) PTOExpired() bool { +func (b *OwnValidatingState) PTOExpired(proposalStepTO time.Duration) bool { rs := b.RoundStarted - return rs+int64(constants.ProposalStepTO)/constants.OneBillion < time.Now().Unix() + return rs+int64(proposalStepTO)/constants.OneBillion < time.Now().Unix() } -func (b *OwnValidatingState) PVTOExpired() bool { +func (b *OwnValidatingState) PVTOExpired(preVoteStepTO time.Duration) bool { rs := b.PreVoteStepStarted - return rs+int64(constants.PreVoteStepTO)/constants.OneBillion < time.Now().Unix() + return rs+int64(preVoteStepTO)/constants.OneBillion < time.Now().Unix() } -func (b *OwnValidatingState) PCTOExpired() bool { +func (b *OwnValidatingState) PCTOExpired(preCommitStepTO time.Duration) bool { rs := b.PreCommitStepStarted - return rs+int64(constants.PreCommitStepTO)/constants.OneBillion < time.Now().Unix() + return rs+int64(preCommitStepTO)/constants.OneBillion < time.Now().Unix() } -func (b *OwnValidatingState) DBRNRExpired() bool { +func (b *OwnValidatingState) DBRNRExpired(dbrnrTO time.Duration) bool { rs := b.PreCommitStepStarted - return rs+int64(constants.DBRNRTO)/constants.OneBillion < time.Now().Unix() + return rs+int64(dbrnrTO)/constants.OneBillion < time.Now().Unix() } func (b *OwnValidatingState) SetRoundStarted() { diff --git a/consensus/objs/pc.go b/consensus/objs/pc.go index d7f75cba..cf9111a9 100644 --- a/consensus/objs/pc.go +++ b/consensus/objs/pc.go @@ -3,12 +3,11 @@ package objs import ( "bytes" - "github.com/MadBase/MadNet/errorz" - mdefs "github.com/MadBase/MadNet/consensus/objs/capn" "github.com/MadBase/MadNet/consensus/objs/precommit" "github.com/MadBase/MadNet/crypto" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/errorz" + "github.com/MadBase/MadNet/utils" capnp "zombiezen.com/go/capnproto2" ) @@ -145,7 +144,7 @@ func (b *PreCommit) ValidateSignatures(secpVal *crypto.Secp256k1Validator, bnVal CE = append(CE, PreVoteSigDesignator()...) CE = append(CE, canonicalEncoding...) for _, sig := range b.PreVotes { - pubkey, err := secpVal.Validate(CE, gUtils.CopySlice(sig)) + pubkey, err := secpVal.Validate(CE, utils.CopySlice(sig)) if err != nil { return err } @@ -167,9 +166,9 @@ func (b *PreCommit) MakeImplPreVotes() (PreVoteList, error) { if err != nil { return nil, err } - groupKey := gUtils.CopySlice(b.GroupKey) - voter := gUtils.CopySlice(b.Signers[idx]) - sig := gUtils.CopySlice(pv) + groupKey := utils.CopySlice(b.GroupKey) + voter := utils.CopySlice(b.Signers[idx]) + sig := utils.CopySlice(pv) pV := &PreVote{ Signature: sig, Proposal: pc.Proposal, diff --git a/consensus/objs/pc_test.go b/consensus/objs/pc_test.go index f2d49b78..461e854d 100644 --- a/consensus/objs/pc_test.go +++ b/consensus/objs/pc_test.go @@ -19,7 +19,10 @@ func TestPreCommit(t *testing.T) { t.Fatal(err) } gk := crypto.BNGroupSigner{} - gk.SetPrivk(crypto.Hasher([]byte("secret"))) + err = gk.SetPrivk(crypto.Hasher([]byte("secret"))) + if err != nil { + t.Fatal(err) + } sig, err := gk.Sign(bhsh) if err != nil { t.Fatal(err) diff --git a/consensus/objs/pcl.go b/consensus/objs/pcl.go index 6e60679a..8eee7dc2 100644 --- a/consensus/objs/pcl.go +++ b/consensus/objs/pcl.go @@ -2,7 +2,7 @@ package objs import ( "github.com/MadBase/MadNet/crypto" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" ) type PreCommitList []*PreCommit @@ -20,7 +20,7 @@ func (pcl PreCommitList) MakeNextHeight(secpSigner *crypto.Secp256k1Signer, bnSi } sigs := [][]byte{} for _, pc := range pcl { - s := gUtils.CopySlice(pc.Signature) + s := utils.CopySlice(pc.Signature) sigs = append(sigs, s) } nh := &NextHeight{ diff --git a/consensus/objs/pclms.go b/consensus/objs/pclms.go index 385fa64f..51516f84 100644 --- a/consensus/objs/pclms.go +++ b/consensus/objs/pclms.go @@ -3,10 +3,9 @@ package objs import ( "bytes" - "github.com/MadBase/MadNet/errorz" - mdefs "github.com/MadBase/MadNet/consensus/objs/capn" "github.com/MadBase/MadNet/consensus/objs/pclaims" + "github.com/MadBase/MadNet/errorz" capnp "zombiezen.com/go/capnproto2" ) diff --git a/consensus/objs/pclms_test.go b/consensus/objs/pclms_test.go index 667fb530..da9e6e0f 100644 --- a/consensus/objs/pclms_test.go +++ b/consensus/objs/pclms_test.go @@ -18,7 +18,10 @@ func TestPClaims(t *testing.T) { t.Fatal(err) } gk := crypto.BNGroupSigner{} - gk.SetPrivk(crypto.Hasher([]byte("secret"))) + err = gk.SetPrivk(crypto.Hasher([]byte("secret"))) + if err != nil { + t.Fatal(err) + } sig, err := gk.Sign(bhsh) if err != nil { t.Fatal(err) diff --git a/consensus/objs/pcn.go b/consensus/objs/pcn.go index adf48b96..59105203 100644 --- a/consensus/objs/pcn.go +++ b/consensus/objs/pcn.go @@ -5,7 +5,7 @@ import ( "github.com/MadBase/MadNet/consensus/objs/precommitnil" "github.com/MadBase/MadNet/crypto" "github.com/MadBase/MadNet/errorz" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" capnp "zombiezen.com/go/capnproto2" ) @@ -40,7 +40,7 @@ func (b *PreCommitNil) UnmarshalCapn(bh mdefs.PreCommitNil) error { if err != nil { return err } - b.Signature = gUtils.CopySlice(bh.Signature()) + b.Signature = utils.CopySlice(bh.Signature()) return nil } diff --git a/consensus/objs/pcn_test.go b/consensus/objs/pcn_test.go index 48b1e0c7..25bca425 100644 --- a/consensus/objs/pcn_test.go +++ b/consensus/objs/pcn_test.go @@ -19,7 +19,10 @@ func TestPreCommitNil(t *testing.T) { t.Fatal(err) } gk := &crypto.BNGroupSigner{} - gk.SetPrivk(crypto.Hasher([]byte("secret"))) + err = gk.SetPrivk(crypto.Hasher([]byte("secret"))) + if err != nil { + t.Fatal(err) + } sig, err := gk.Sign(bhsh) if err != nil { t.Fatal(err) diff --git a/consensus/objs/phlkey.go b/consensus/objs/phlkey.go index 95edc4cb..e3eac0ab 100644 --- a/consensus/objs/phlkey.go +++ b/consensus/objs/phlkey.go @@ -2,7 +2,7 @@ package objs import ( "github.com/MadBase/MadNet/errorz" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" ) // PendingHdrLeafKey ... @@ -20,8 +20,8 @@ func (b *PendingHdrLeafKey) UnmarshalBinary(data []byte) error { if len(data) != 34 { return errorz.ErrInvalid{}.New("Invalid data for PendingHdrLeafKey unmarshalling") } - b.Prefix = gUtils.CopySlice(data[0:2]) - b.Key = gUtils.CopySlice(data[2:]) + b.Prefix = utils.CopySlice(data[0:2]) + b.Key = utils.CopySlice(data[2:]) return nil } @@ -32,7 +32,7 @@ func (b *PendingHdrLeafKey) MarshalBinary() ([]byte, error) { return nil, errorz.ErrInvalid{}.New("not initialized") } key := []byte{} - key = append(key, gUtils.CopySlice(b.Prefix)...) - key = append(key, gUtils.CopySlice(b.Key)...) + key = append(key, utils.CopySlice(b.Prefix)...) + key = append(key, utils.CopySlice(b.Key)...) return key, nil } diff --git a/consensus/objs/plkey.go b/consensus/objs/plkey.go index 84947943..d6890ebc 100644 --- a/consensus/objs/plkey.go +++ b/consensus/objs/plkey.go @@ -2,7 +2,7 @@ package objs import ( "github.com/MadBase/MadNet/errorz" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" ) // PendingLeafKey ... @@ -20,8 +20,8 @@ func (b *PendingLeafKey) UnmarshalBinary(data []byte) error { if len(data) != 34 { return errorz.ErrInvalid{}.New("Invalid data for BlockHeaderHeightKey unmarshalling") } - b.Prefix = gUtils.CopySlice(data[0:2]) - b.Key = gUtils.CopySlice(data[2:]) + b.Prefix = utils.CopySlice(data[0:2]) + b.Key = utils.CopySlice(data[2:]) return nil } @@ -32,7 +32,7 @@ func (b *PendingLeafKey) MarshalBinary() ([]byte, error) { return nil, errorz.ErrInvalid{}.New("not initialized") } key := []byte{} - key = append(key, gUtils.CopySlice(b.Prefix)...) - key = append(key, gUtils.CopySlice(b.Key)...) + key = append(key, utils.CopySlice(b.Prefix)...) + key = append(key, utils.CopySlice(b.Key)...) return key, nil } diff --git a/consensus/objs/pnkey.go b/consensus/objs/pnkey.go index 1f7f9ad4..7546ca99 100644 --- a/consensus/objs/pnkey.go +++ b/consensus/objs/pnkey.go @@ -2,7 +2,7 @@ package objs import ( "github.com/MadBase/MadNet/errorz" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" ) // PendingNodeKey ... @@ -20,8 +20,8 @@ func (b *PendingNodeKey) UnmarshalBinary(data []byte) error { if len(data) != 34 { return errorz.ErrInvalid{}.New("Invalid data for PendingNodeKey unmarshalling") } - b.Prefix = gUtils.CopySlice(data[0:2]) - b.Key = gUtils.CopySlice(data[2:]) + b.Prefix = utils.CopySlice(data[0:2]) + b.Key = utils.CopySlice(data[2:]) return nil } @@ -32,7 +32,7 @@ func (b *PendingNodeKey) MarshalBinary() ([]byte, error) { return nil, errorz.ErrInvalid{}.New("not initialized") } key := []byte{} - key = append(key, gUtils.CopySlice(b.Prefix)...) - key = append(key, gUtils.CopySlice(b.Key)...) + key = append(key, utils.CopySlice(b.Prefix)...) + key = append(key, utils.CopySlice(b.Key)...) return key, nil } diff --git a/consensus/objs/prop.go b/consensus/objs/prop.go index 477934b0..e5288678 100644 --- a/consensus/objs/prop.go +++ b/consensus/objs/prop.go @@ -3,13 +3,12 @@ package objs import ( "bytes" - "github.com/MadBase/MadNet/constants" - "github.com/MadBase/MadNet/errorz" - mdefs "github.com/MadBase/MadNet/consensus/objs/capn" "github.com/MadBase/MadNet/consensus/objs/proposal" + "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/crypto" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/errorz" + "github.com/MadBase/MadNet/utils" capnp "zombiezen.com/go/capnproto2" ) @@ -51,7 +50,7 @@ func (b *Proposal) UnmarshalCapn(bh mdefs.Proposal) error { return err } b.TxHshLst = lst - b.Signature = gUtils.CopySlice(bh.Signature()) + b.Signature = utils.CopySlice(bh.Signature()) if b.PClaims.RCert.RClaims.Round == constants.DEADBLOCKROUND { if len(b.TxHshLst) != 0 { return errorz.ErrInvalid{}.New("non empty tx hash lst in deadblockround") diff --git a/consensus/objs/prop_test.go b/consensus/objs/prop_test.go index ba79f3b2..f47268f5 100644 --- a/consensus/objs/prop_test.go +++ b/consensus/objs/prop_test.go @@ -19,7 +19,10 @@ func TestProposal(t *testing.T) { t.Fatal(err) } gk := &crypto.BNGroupSigner{} - gk.SetPrivk(crypto.Hasher([]byte("secret"))) + err = gk.SetPrivk(crypto.Hasher([]byte("secret"))) + if err != nil { + t.Fatal(err) + } sig, err := gk.Sign(bhsh) if err != nil { t.Fatal(err) @@ -27,7 +30,7 @@ func TestProposal(t *testing.T) { secpSigner := &crypto.Secp256k1Signer{} err = secpSigner.SetPrivk(crypto.Hasher([]byte("secret"))) if err != nil { - t.Fatal(err) + t.Fatal(err) } bh := &BlockHeader{ BClaims: bclaims, diff --git a/consensus/objs/pv.go b/consensus/objs/pv.go index 5941f632..1173c5e8 100644 --- a/consensus/objs/pv.go +++ b/consensus/objs/pv.go @@ -5,7 +5,7 @@ import ( "github.com/MadBase/MadNet/consensus/objs/prevote" "github.com/MadBase/MadNet/crypto" "github.com/MadBase/MadNet/errorz" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" capnp "zombiezen.com/go/capnproto2" ) @@ -40,7 +40,7 @@ func (b *PreVote) UnmarshalCapn(bh mdefs.PreVote) error { if err != nil { return err } - b.Signature = gUtils.CopySlice(bh.Signature()) + b.Signature = utils.CopySlice(bh.Signature()) return nil } diff --git a/consensus/objs/pv_test.go b/consensus/objs/pv_test.go index 59febd91..c73a2418 100644 --- a/consensus/objs/pv_test.go +++ b/consensus/objs/pv_test.go @@ -19,7 +19,10 @@ func TestPreVote(t *testing.T) { t.Fatal(err) } gk := crypto.BNGroupSigner{} - gk.SetPrivk(crypto.Hasher([]byte("secret"))) + err = gk.SetPrivk(crypto.Hasher([]byte("secret"))) + if err != nil { + t.Fatal(err) + } sig, err := gk.Sign(bhsh) if err != nil { t.Fatal(err) diff --git a/consensus/objs/pvl.go b/consensus/objs/pvl.go index a9004cbb..5e170068 100644 --- a/consensus/objs/pvl.go +++ b/consensus/objs/pvl.go @@ -2,7 +2,7 @@ package objs import ( "github.com/MadBase/MadNet/crypto" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" ) type PreVoteList []*PreVote @@ -11,7 +11,7 @@ type PreVoteNilList []bool func (pvl PreVoteList) MakePreCommit(secpSigner *crypto.Secp256k1Signer) (*PreCommit, error) { sigs := [][]byte{} for _, pv := range pvl { - s := gUtils.CopySlice(pv.Signature) + s := utils.CopySlice(pv.Signature) sigs = append(sigs, s) } propBytes, err := pvl[0].Proposal.MarshalBinary() diff --git a/consensus/objs/pvn.go b/consensus/objs/pvn.go index a05ded6e..1b53cbe1 100644 --- a/consensus/objs/pvn.go +++ b/consensus/objs/pvn.go @@ -5,7 +5,7 @@ import ( "github.com/MadBase/MadNet/consensus/objs/prevotenil" "github.com/MadBase/MadNet/crypto" "github.com/MadBase/MadNet/errorz" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" capnp "zombiezen.com/go/capnproto2" ) @@ -40,7 +40,7 @@ func (b *PreVoteNil) UnmarshalCapn(bh mdefs.PreVoteNil) error { if err != nil { return err } - b.Signature = gUtils.CopySlice(bh.Signature()) + b.Signature = utils.CopySlice(bh.Signature()) return nil } diff --git a/consensus/objs/pvn_test.go b/consensus/objs/pvn_test.go index cd19ac5e..73f17085 100644 --- a/consensus/objs/pvn_test.go +++ b/consensus/objs/pvn_test.go @@ -19,7 +19,10 @@ func TestPreVoteNil(t *testing.T) { t.Fatal(err) } gk := &crypto.BNGroupSigner{} - gk.SetPrivk(crypto.Hasher([]byte("secret"))) + err = gk.SetPrivk(crypto.Hasher([]byte("secret"))) + if err != nil { + t.Fatal(err) + } sig, err := gk.Sign(bhsh) if err != nil { t.Fatal(err) diff --git a/consensus/objs/rc.go b/consensus/objs/rc.go index 534355f1..6217600c 100644 --- a/consensus/objs/rc.go +++ b/consensus/objs/rc.go @@ -6,7 +6,7 @@ import ( "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/crypto" "github.com/MadBase/MadNet/errorz" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" capnp "zombiezen.com/go/capnproto2" ) @@ -40,7 +40,7 @@ func (b *RCert) UnmarshalCapn(bh mdefs.RCert) error { if err != nil { return err } - b.SigGroup = gUtils.CopySlice(bh.SigGroup()) + b.SigGroup = utils.CopySlice(bh.SigGroup()) return nil } @@ -98,7 +98,7 @@ func (b *RCert) MarshalCapn(seg *capnp.Segment) (mdefs.RCert, error) { // ValidateSignature validates the group signature on the RCert func (b *RCert) ValidateSignature(bnVal *crypto.BNGroupValidator) error { - if b == nil || b.RClaims == nil { + if b == nil || b.RClaims == nil || b.RClaims.Height == 0 || b.RClaims.ChainID == 0 || b.RClaims.Round == 0 || b.RClaims.Round > constants.DEADBLOCKROUND { return errorz.ErrInvalid{}.New("not initialized") } if b.RClaims.Height == 1 && b.RClaims.Round == 1 { @@ -113,6 +113,9 @@ func (b *RCert) ValidateSignature(bnVal *crypto.BNGroupValidator) error { // There is nothing we can check because there is no group signature return nil } + if len(b.RClaims.PrevBlock) != constants.HashLen { + return errorz.ErrInvalid{}.New("invalid PrevBlock") + } if b.RClaims.Round > 1 { canonicalEncoding, err := b.RClaims.MarshalBinary() if err != nil { @@ -192,11 +195,11 @@ func (b *RCert) NextRound(secpSigner *crypto.Secp256k1Signer, bnSigner *crypto.B if b == nil { return nil, errorz.ErrInvalid{}.New("not initialized") } - nrrClaims := &RClaims{} rcClaims, err := b.RClaims.MarshalBinary() if err != nil { return nil, err } + nrrClaims := &RClaims{} err = nrrClaims.UnmarshalBinary(rcClaims) if err != nil { return nil, err diff --git a/consensus/objs/rc_test.go b/consensus/objs/rc_test.go index bf0b5bd6..b9380045 100644 --- a/consensus/objs/rc_test.go +++ b/consensus/objs/rc_test.go @@ -1,8 +1,10 @@ package objs import ( + "bytes" "testing" + "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/crypto" ) @@ -19,7 +21,10 @@ func TestRCert(t *testing.T) { t.Fatal(err) } gk := &crypto.BNGroupSigner{} - gk.SetPrivk(crypto.Hasher([]byte("secret"))) + err = gk.SetPrivk(crypto.Hasher([]byte("secret"))) + if err != nil { + t.Fatal(err) + } sig, err := gk.Sign(bhsh) if err != nil { t.Fatal(err) @@ -59,3 +64,159 @@ func TestRCert(t *testing.T) { t.Fatal(err) } } + +func TestRCertMarshal(t *testing.T) { + pvn := &PreVoteNil{} + _, err := pvn.RCert.MarshalBinary() + if err == nil { + t.Fatal("Should have raised error (0)") + } + + rc := &RCert{} + _, err = rc.MarshalBinary() + if err == nil { + t.Fatal("Should have raised error (1)") + } +} + +func TestRCertValidateSignature(t *testing.T) { + bnVal := &crypto.BNGroupValidator{} + pvn := &PreVoteNil{} + err := pvn.RCert.ValidateSignature(bnVal) + if err == nil { + t.Fatal("Should have raised error (0)") + } + + // Invalid RClaims object + rc := &RCert{} + err = rc.ValidateSignature(bnVal) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + // Everything is good + rc.RClaims = &RClaims{} + rc.RClaims.ChainID = 1 + rc.RClaims.Height = 1 + rc.RClaims.Round = 1 + err = rc.ValidateSignature(bnVal) + if err != nil { + t.Fatal(err) + } + groupKey := make([]byte, constants.CurveBN256EthPubkeyLen) + if !bytes.Equal(rc.GroupKey, groupKey) { + t.Fatal("Invalid GroupKey") + } + + // Invalid Height/Round combination; not possible to be Height 1, Round 2 + rc.GroupKey = nil + rc.RClaims.Height = 1 + rc.RClaims.Round = 2 + err = rc.ValidateSignature(bnVal) + if err == nil { + t.Fatal("Should have raised error (2)") + } + + // No error is raised + rc.RClaims.Height = 2 + rc.RClaims.Round = 1 + err = rc.ValidateSignature(bnVal) + if err != nil { + t.Fatal(err) + } + + // Should raise an error for invalid RClaims object + rc.RClaims.Height = 2 + rc.RClaims.Round = constants.DEADBLOCKROUND + 1 + err = rc.ValidateSignature(bnVal) + if err == nil { + t.Fatal("Should have raised error (3)") + } + + // Should raise an error for invalid PrevBlock + rc.RClaims.Height = 2 + rc.RClaims.Round = 2 + rc.RClaims.PrevBlock = make([]byte, constants.HashLen+1) + err = rc.ValidateSignature(bnVal) + if err == nil { + t.Fatal("Should have raised error (4)") + } + + // Should raise an error for invalid PrevBlock + rc.RClaims.Height = 2 + rc.RClaims.Round = 2 + rc.RClaims.PrevBlock = make([]byte, constants.HashLen) + err = rc.ValidateSignature(bnVal) + if err == nil { + t.Fatal("Should have raised error (5)") + } + + // Should raise an error for invalid PrevBlock + rc.RClaims.Height = 3 + rc.RClaims.Round = 1 + rc.RClaims.PrevBlock = make([]byte, constants.HashLen) + err = rc.ValidateSignature(bnVal) + if err == nil { + t.Fatal("Should have raised error (6)") + } +} + +func TestRCertPreVoteNil(t *testing.T) { + rc := &RCert{} + _, err := rc.PreVoteNil(nil) + if err == nil { + t.Fatal("Should have raised error (1)") + } + rc.RClaims = &RClaims{ + ChainID: 1, + Height: 1, + Round: 1, + PrevBlock: make([]byte, constants.HashLen), + } + _, err = rc.PreVoteNil(nil) + if err == nil { + t.Fatal("Should have raised error (2)") + } +} + +func TestRCertPreCommitNil(t *testing.T) { + rc := &RCert{} + _, err := rc.PreCommitNil(nil) + if err == nil { + t.Fatal("Should have raised error (1)") + } + rc.RClaims = &RClaims{ + ChainID: 1, + Height: 1, + Round: 1, + PrevBlock: make([]byte, constants.HashLen), + } + _, err = rc.PreCommitNil(nil) + if err == nil { + t.Fatal("Should have raised error (2)") + } +} + +func TestRCertNextRound(t *testing.T) { + nrc := &NRClaims{} + _, err := nrc.RCert.NextRound(nil, nil) + if err == nil { + t.Fatal("Should have raised error (0)") + } + + rc := &RCert{} + _, err = rc.NextRound(nil, nil) + if err == nil { + t.Fatal("Should have raised error (1)") + } + rc.RClaims = &RClaims{ + ChainID: 1, + Height: 1, + Round: 1, + PrevBlock: make([]byte, constants.HashLen), + } + _, err = rc.NextRound(nil, nil) + if err == nil { + t.Fatal("Should have raised error (2)") + } +} diff --git a/consensus/objs/rclms.go b/consensus/objs/rclms.go index 9e990ece..d1de1813 100644 --- a/consensus/objs/rclms.go +++ b/consensus/objs/rclms.go @@ -5,7 +5,7 @@ import ( "github.com/MadBase/MadNet/consensus/objs/rclaims" "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/errorz" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" capnp "zombiezen.com/go/capnproto2" ) @@ -37,10 +37,7 @@ func (b *RClaims) UnmarshalCapn(bh mdefs.RClaims) error { b.ChainID = bh.ChainID() b.Height = bh.Height() b.Round = bh.Round() - b.PrevBlock = gUtils.CopySlice(bh.PrevBlock()) - if len(b.PrevBlock) != constants.HashLen { - return errorz.ErrInvalid{}.New("rclaims bad prevb len") - } + b.PrevBlock = utils.CopySlice(bh.PrevBlock()) if b.Height < 1 { return errorz.ErrInvalid{}.New("rclaims bad height") } diff --git a/consensus/objs/rclms_test.go b/consensus/objs/rclms_test.go index d0afb169..844b7d68 100644 --- a/consensus/objs/rclms_test.go +++ b/consensus/objs/rclms_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/MadBase/MadNet/constants" + "github.com/MadBase/MadNet/utils" ) func rclaimsEqual(t *testing.T, rclaims, rclaims2 *RClaims) { @@ -116,3 +117,46 @@ func TestRClaimsBad(t *testing.T) { t.Fatal("Should have raised error (5)") } } + +func TestRClaimsBad2(t *testing.T) { + cid := uint32(66) + height := uint32(113) + round := uint32(175) + prevHash := make([]byte, constants.HashLen) + + rcl := &RClaims{ + ChainID: cid, + Height: height, + Round: round, + PrevBlock: prevHash, + } + data, err := rcl.MarshalBinary() + if err != nil { + t.Fatal(err) + } + + rcl2 := &RClaims{} + // Raise error for bad ChainID + dataBad1 := utils.CopySlice(data) + dataBad1[8] = 0 + err = rcl2.UnmarshalBinary(dataBad1) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + // Raise error for bad Height + dataBad2 := utils.CopySlice(data) + dataBad2[12] = 0 + err = rcl2.UnmarshalBinary(dataBad2) + if err == nil { + t.Fatal("Should have raised error (2)") + } + + // Raise error for bad Round + dataBad3 := utils.CopySlice(data) + dataBad3[16] = 0 + err = rcl2.UnmarshalBinary(dataBad3) + if err == nil { + t.Fatal("Should have raised error (3)") + } +} diff --git a/consensus/objs/rs.go b/consensus/objs/rs.go index d5c3a4f2..5915e127 100644 --- a/consensus/objs/rs.go +++ b/consensus/objs/rs.go @@ -3,12 +3,11 @@ package objs import ( "errors" - "github.com/MadBase/MadNet/constants" - "github.com/MadBase/MadNet/errorz" - mdefs "github.com/MadBase/MadNet/consensus/objs/capn" "github.com/MadBase/MadNet/consensus/objs/rstate" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/constants" + "github.com/MadBase/MadNet/errorz" + "github.com/MadBase/MadNet/utils" capnp "zombiezen.com/go/capnproto2" ) @@ -54,9 +53,9 @@ func (b *RoundState) UnmarshalCapn(bh mdefs.RoundState) error { if err != nil { return err } - b.VAddr = gUtils.CopySlice(bh.VAddr()) - b.GroupKey = gUtils.CopySlice(bh.GroupKey()) - b.GroupShare = gUtils.CopySlice(bh.GroupShare()) + b.VAddr = utils.CopySlice(bh.VAddr()) + b.GroupKey = utils.CopySlice(bh.GroupKey()) + b.GroupShare = utils.CopySlice(bh.GroupShare()) b.GroupIdx = bh.GroupIdx() b.ImplicitPVN = bh.ImplicitPVN() b.ImplicitPCN = bh.ImplicitPCN() diff --git a/consensus/objs/rs_test.go b/consensus/objs/rs_test.go index a4581df0..2cdcbbf8 100644 --- a/consensus/objs/rs_test.go +++ b/consensus/objs/rs_test.go @@ -158,7 +158,10 @@ func makeSigners(t *testing.T, num int) ([]*crypto.Secp256k1Signer, []*crypto.BN } secpSigners = append(secpSigners, secpSigner) bnSigner := &crypto.BNGroupSigner{} - bnSigner.SetPrivk(crypto.Hasher([]byte("secret" + strconv.Itoa(i)))) + err = bnSigner.SetPrivk(crypto.Hasher([]byte("secret" + strconv.Itoa(i)))) + if err != nil { + t.Fatal(err) + } bnSigners = append(bnSigners, bnSigner) } return secpSigners, bnSigners diff --git a/consensus/objs/rskeycurr.go b/consensus/objs/rskeycurr.go index 01db5433..839be7a6 100644 --- a/consensus/objs/rskeycurr.go +++ b/consensus/objs/rskeycurr.go @@ -5,8 +5,7 @@ import ( "encoding/hex" "github.com/MadBase/MadNet/errorz" - - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" ) //# index historic by by groupKey|height|round|vAddr @@ -26,7 +25,7 @@ func (b *RoundStateCurrentKey) MarshalBinary() ([]byte, error) { return nil, errorz.ErrInvalid{}.New("not initialized") } key := []byte{} - Prefix := gUtils.CopySlice(b.Prefix) + Prefix := utils.CopySlice(b.Prefix) GroupKey := make([]byte, hex.EncodedLen(len(b.GroupKey))) VAddr := make([]byte, hex.EncodedLen(len(b.VAddr))) _ = hex.Encode(GroupKey, b.GroupKey) diff --git a/consensus/objs/rskeyhist.go b/consensus/objs/rskeyhist.go index 8c7fd3cc..0b30e2f3 100644 --- a/consensus/objs/rskeyhist.go +++ b/consensus/objs/rskeyhist.go @@ -5,8 +5,7 @@ import ( "encoding/hex" "github.com/MadBase/MadNet/errorz" - - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" ) // RoundStateHistoricKey ... @@ -24,11 +23,11 @@ func (b *RoundStateHistoricKey) MarshalBinary() ([]byte, error) { return nil, errorz.ErrInvalid{}.New("not initialized") } key := []byte{} - Prefix := gUtils.CopySlice(b.Prefix) + Prefix := utils.CopySlice(b.Prefix) VAddr := make([]byte, hex.EncodedLen(len(b.VAddr))) _ = hex.Encode(VAddr, b.VAddr) - Height := gUtils.MarshalUint32(b.Height) - Round := gUtils.MarshalUint32(b.Round) + Height := utils.MarshalUint32(b.Height) + Round := utils.MarshalUint32(b.Round) key = append(key, Prefix...) key = append(key, []byte("|")...) key = append(key, Height...) @@ -50,7 +49,7 @@ func (b *RoundStateHistoricKey) UnmarshalBinary(data []byte) error { return errorz.ErrCorrupt } b.Prefix = splitData[0] - Height, err := gUtils.UnmarshalUint32(splitData[1]) + Height, err := utils.UnmarshalUint32(splitData[1]) if err != nil { return err } @@ -58,7 +57,7 @@ func (b *RoundStateHistoricKey) UnmarshalBinary(data []byte) error { return errorz.ErrInvalid{}.New("invalid height in unmarshalling") } b.Height = Height - Round, err := gUtils.UnmarshalUint32(splitData[2]) + Round, err := utils.UnmarshalUint32(splitData[2]) if err != nil { return err } @@ -81,8 +80,8 @@ func (b *RoundStateHistoricKey) MakeIterKey() ([]byte, error) { return nil, errorz.ErrInvalid{}.New("not initialized") } key := []byte{} - Prefix := gUtils.CopySlice(b.Prefix) - Height := gUtils.MarshalUint32(b.Height) + Prefix := utils.CopySlice(b.Prefix) + Height := utils.MarshalUint32(b.Height) key = append(key, Prefix...) key = append(key, []byte("|")...) key = append(key, Height...) diff --git a/consensus/objs/safetoproceedkey.go b/consensus/objs/safetoproceedkey.go index 3e97fd56..6d1aabce 100644 --- a/consensus/objs/safetoproceedkey.go +++ b/consensus/objs/safetoproceedkey.go @@ -4,8 +4,7 @@ import ( "bytes" "github.com/MadBase/MadNet/errorz" - - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" ) // SafeToProceedKey ... @@ -21,8 +20,8 @@ func (b *SafeToProceedKey) MarshalBinary() ([]byte, error) { return nil, errorz.ErrInvalid{}.New("not initialized") } key := []byte{} - Prefix := gUtils.CopySlice(b.Prefix) - Height := gUtils.MarshalUint32(b.Height) + Prefix := utils.CopySlice(b.Prefix) + Height := utils.MarshalUint32(b.Height) key = append(key, Prefix...) key = append(key, []byte("|")...) key = append(key, Height...) @@ -41,7 +40,7 @@ func (b *SafeToProceedKey) UnmarshalBinary(data []byte) error { return errorz.ErrCorrupt } b.Prefix = splitData[0] - Height, err := gUtils.UnmarshalUint32(splitData[1]) + Height, err := utils.UnmarshalUint32(splitData[1]) if err != nil { return err } diff --git a/consensus/objs/sbhkey.go b/consensus/objs/sbhkey.go index 51c4804d..ff374115 100644 --- a/consensus/objs/sbhkey.go +++ b/consensus/objs/sbhkey.go @@ -2,7 +2,7 @@ package objs import ( "github.com/MadBase/MadNet/errorz" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" ) // StagedBlockHeaderKey ... @@ -20,8 +20,8 @@ func (b *StagedBlockHeaderKey) UnmarshalBinary(data []byte) error { if len(data) != 6 { return errorz.ErrInvalid{}.New("Invalid data for StagedBlockHeaderKey unmarshalling") } - b.Prefix = gUtils.CopySlice(data[0:2]) - b.Key = gUtils.CopySlice(data[2:]) + b.Prefix = utils.CopySlice(data[0:2]) + b.Key = utils.CopySlice(data[2:]) return nil } @@ -32,7 +32,7 @@ func (b *StagedBlockHeaderKey) MarshalBinary() ([]byte, error) { return nil, errorz.ErrInvalid{}.New("not initialized") } key := []byte{} - Prefix := gUtils.CopySlice(b.Prefix) + Prefix := utils.CopySlice(b.Prefix) key = append(key, Prefix...) key = append(key, b.Key...) return key, nil diff --git a/consensus/objs/state_test.go b/consensus/objs/state_test.go index 4a1348a7..32738ce7 100644 --- a/consensus/objs/state_test.go +++ b/consensus/objs/state_test.go @@ -248,7 +248,10 @@ func makeSigners2(t *testing.T) ([]byte, []*crypto.BNGroupSigner, [][]byte, []*c gpk1 := new(bn256.G2).ScalarBaseMult(gsk1) groupShares[0] = gpk1.Marshal() s1 := new(crypto.BNGroupSigner) - s1.SetPrivk(gsk1.Bytes()) + err := s1.SetPrivk(gsk1.Bytes()) + if err != nil { + t.Fatal(err) + } sig1, err := s1.Sign(msg) if err != nil { t.Fatal(err) @@ -259,7 +262,10 @@ func makeSigners2(t *testing.T) ([]byte, []*crypto.BNGroupSigner, [][]byte, []*c gpk2 := new(bn256.G2).ScalarBaseMult(gsk2) groupShares[1] = gpk2.Marshal() s2 := new(crypto.BNGroupSigner) - s2.SetPrivk(gsk2.Bytes()) + err = s2.SetPrivk(gsk2.Bytes()) + if err != nil { + t.Fatal(err) + } sig2, err := s2.Sign(msg) if err != nil { t.Fatal(err) @@ -270,7 +276,10 @@ func makeSigners2(t *testing.T) ([]byte, []*crypto.BNGroupSigner, [][]byte, []*c gpk3 := new(bn256.G2).ScalarBaseMult(gsk3) groupShares[2] = gpk3.Marshal() s3 := new(crypto.BNGroupSigner) - s3.SetPrivk(gsk3.Bytes()) + err = s3.SetPrivk(gsk3.Bytes()) + if err != nil { + t.Fatal(err) + } sig3, err := s3.Sign(msg) if err != nil { t.Fatal(err) @@ -281,7 +290,10 @@ func makeSigners2(t *testing.T) ([]byte, []*crypto.BNGroupSigner, [][]byte, []*c gpk4 := new(bn256.G2).ScalarBaseMult(gsk4) groupShares[3] = gpk4.Marshal() s4 := new(crypto.BNGroupSigner) - s4.SetPrivk(gsk4.Bytes()) + err = s4.SetPrivk(gsk4.Bytes()) + if err != nil { + t.Fatal(err) + } sig4, err := s4.Sign(msg) if err != nil { t.Fatal(err) diff --git a/consensus/objs/txcachekey.go b/consensus/objs/txcachekey.go index 4ec1f8cf..c03efeb0 100644 --- a/consensus/objs/txcachekey.go +++ b/consensus/objs/txcachekey.go @@ -3,10 +3,9 @@ package objs import ( "bytes" - "github.com/MadBase/MadNet/errorz" - "github.com/MadBase/MadNet/constants" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/errorz" + "github.com/MadBase/MadNet/utils" ) // TxCacheKey ... @@ -23,9 +22,9 @@ func (b *TxCacheKey) MarshalBinary() ([]byte, error) { return nil, errorz.ErrInvalid{}.New("not initialized") } key := []byte{} - Prefix := gUtils.CopySlice(b.Prefix) - TxHash := gUtils.CopySlice(b.TxHash) - Height := gUtils.MarshalUint32(b.Height) + Prefix := utils.CopySlice(b.Prefix) + TxHash := utils.CopySlice(b.TxHash) + Height := utils.MarshalUint32(b.Height) key = append(key, Prefix...) key = append(key, []byte("|")...) key = append(key, Height...) @@ -45,7 +44,7 @@ func (b *TxCacheKey) UnmarshalBinary(data []byte) error { return errorz.ErrCorrupt } b.Prefix = splitData[0] - Height, err := gUtils.UnmarshalUint32(splitData[1]) + Height, err := utils.UnmarshalUint32(splitData[1]) if err != nil { return err } @@ -53,7 +52,7 @@ func (b *TxCacheKey) UnmarshalBinary(data []byte) error { return errorz.ErrInvalid{}.New("invalid height for unmarshalling") } b.Height = Height - TxHash := gUtils.CopySlice(splitData[2]) + TxHash := utils.CopySlice(splitData[2]) if len(TxHash) != constants.HashLen { return errorz.ErrInvalid{}.New("invalid txhash for unmarshalling; incorrect length") } @@ -67,8 +66,8 @@ func (b *TxCacheKey) MakeIterKey() ([]byte, error) { return nil, errorz.ErrInvalid{}.New("not initialized") } key := []byte{} - Prefix := gUtils.CopySlice(b.Prefix) - Height := gUtils.MarshalUint32(b.Height) + Prefix := utils.CopySlice(b.Prefix) + Height := utils.MarshalUint32(b.Height) key = append(key, Prefix...) key = append(key, []byte("|")...) key = append(key, Height...) diff --git a/consensus/objs/txcachekey_test.go b/consensus/objs/txcachekey_test.go index 33d26e04..1c73ad42 100644 --- a/consensus/objs/txcachekey_test.go +++ b/consensus/objs/txcachekey_test.go @@ -6,7 +6,7 @@ import ( "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/crypto" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" ) func txckEqual(t *testing.T, txck, txck2 *TxCacheKey) { @@ -48,7 +48,7 @@ func TestTxCacheKey(t *testing.T) { } txckEqual(t, txck, txck2) - hb := gUtils.MarshalUint32(height) + hb := utils.MarshalUint32(height) iterKeyTrue := []byte{} iterKeyTrue = append(iterKeyTrue, prefix...) iterKeyTrue = append(iterKeyTrue, []byte("|")...) diff --git a/consensus/objs/util.go b/consensus/objs/util.go index 8e4e980f..a9e8917a 100644 --- a/consensus/objs/util.go +++ b/consensus/objs/util.go @@ -12,6 +12,8 @@ import ( "github.com/MadBase/MadNet/utils" ) +// ExtractHR extracts the Height and Round from an interface; +// it panics on undefined types. func ExtractHR(any interface{}) (uint32, uint32) { switch v := any.(type) { case *RoundState: @@ -65,6 +67,8 @@ func ExtractHR(any interface{}) (uint32, uint32) { } } +// ExtractHCID extracts the Height and ChainID from an interface; +// it panics on undefined types. func ExtractHCID(any interface{}) (uint32, uint32) { switch v := any.(type) { case *RCert: @@ -94,11 +98,16 @@ func ExtractHCID(any interface{}) (uint32, uint32) { case *BlockHeader: rc := v.BClaims return rc.Height, rc.ChainID + case *BClaims: + rc := v + return rc.Height, rc.ChainID default: panic(fmt.Sprintf("undefined type in ExtractHCID %T", v)) } } +// ExtractRCertAny extracts an RCert from an interface; +// it panics on undefined types. func ExtractRCertAny(any interface{}) (*RCert, error) { switch v := any.(type) { case *BlockHeader: @@ -108,6 +117,8 @@ func ExtractRCertAny(any interface{}) (*RCert, error) { } } +// ExtractRCert extracts an RCert from an interface; +// it panics on undefined types. func ExtractRCert(any interface{}) *RCert { switch v := any.(type) { case *RoundState: @@ -151,6 +162,22 @@ func ExtractRCert(any interface{}) *RCert { } } +// RelateHR relates Height and Round between objects. +// Simply: +// if a is before b, return -1 +// if a is after b, return 1 +// if a equals b, return 0 +// +// More explicitly, we extract the height and round from objects a and b. +// +// If (aHeight == bHeight) && (aRound == bRound) +// return 0 +// +// If (aHeight < bHeight) || ((aHeight == bHeight) && (aRound < bRound)) +// return -1 +// +// If (aHeight > bHeight) || ((aHeight == bHeight) && (aRound > bRound)) +// return 1 func RelateHR(a, b interface{}) int { ah, ar := ExtractHR(a) bh, br := ExtractHR(b) @@ -171,6 +198,16 @@ func RelateHR(a, b interface{}) int { return 1 } +// RelateH relates Height between objects +// +// If aHeight == bHeight +// return 0 +// +// If aHeight < bHeight +// return -1 +// +// If aHeight > bHeight +// return 1 func RelateH(a, b interface{}) int { if a == nil && b != nil { return -1 @@ -189,6 +226,7 @@ func RelateH(a, b interface{}) int { return 1 } +// BClaimsEqual determines if two objects have equal BClaims objects func BClaimsEqual(a, b interface{}) (bool, error) { ab := ExtractBClaims(a) bb := ExtractBClaims(b) @@ -206,6 +244,8 @@ func BClaimsEqual(a, b interface{}) (bool, error) { return true, nil } +// ExtractBClaims extracts BClaims from an interface; +// it panics on undefined types. func ExtractBClaims(any interface{}) *BClaims { switch v := any.(type) { case *BlockHeader: @@ -223,12 +263,14 @@ func ExtractBClaims(any interface{}) *BClaims { } } +// PrevBlockEqual determines if objects agree on the previous block func PrevBlockEqual(a, b interface{}) bool { ab := ExtractRCert(a) bb := ExtractRCert(b) return bytes.Equal(ab.RClaims.PrevBlock, bb.RClaims.PrevBlock) } +// IsDeadBlockRound determines if an object is for the DeadBlockRound func IsDeadBlockRound(any interface{}) bool { _, r := ExtractHR(any) return r == constants.DEADBLOCKROUND @@ -242,6 +284,9 @@ func MakeTxRoot(txHashes [][]byte) ([]byte, error) { values := [][]byte{} for i := 0; i < len(txHashes); i++ { txHash := txHashes[i] + if len(txHash) != constants.HashLen { + return nil, errorz.ErrInvalid{}.New("incorrect txHash length") + } values = append(values, crypto.Hasher(txHash)) } // new in memory smt diff --git a/consensus/objs/util_test.go b/consensus/objs/util_test.go new file mode 100644 index 00000000..27c45365 --- /dev/null +++ b/consensus/objs/util_test.go @@ -0,0 +1,336 @@ +package objs + +import ( + "bytes" + "testing" + + "github.com/MadBase/MadNet/constants" + "github.com/MadBase/MadNet/crypto" +) + +func TestMakeTxRoot(t *testing.T) { + hashNull := crypto.Hasher([]byte{}) + retHash, err := MakeTxRoot(nil) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(hashNull, retHash) { + t.Fatal("invalid TxRoot") + } + + hashesBad := [][]byte{} + hashesBad = append(hashesBad, []byte{0}) + _, err = MakeTxRoot(hashesBad) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestGetProposerIdx(t *testing.T) { + height := uint32(1) + round := uint32(1) + numv := 4 + propIdx := uint8(1) + retIdx := GetProposerIdx(numv, height, round) + if retIdx != propIdx { + t.Fatal("Invalid proposer index (1)") + } + height = 5 + retIdx = GetProposerIdx(numv, height, round) + if retIdx != propIdx { + t.Fatal("Invalid proposer index (2)") + } + round = 2 + propIdx = 2 + retIdx = GetProposerIdx(numv, height, round) + if retIdx != propIdx { + t.Fatal("Invalid proposer index (3)") + } +} + +func TestSplitBlob(t *testing.T) { + data := make([]byte, 10) + blen := 3 + _, err := SplitBlob(data, blen) + if err == nil { + t.Fatal("Should have raised error (1)") + } + data = []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + blen = 2 + trueBuf := [][]byte{} + trueBuf = append(trueBuf, []byte{1, 2}) + trueBuf = append(trueBuf, []byte{3, 4}) + trueBuf = append(trueBuf, []byte{5, 6}) + trueBuf = append(trueBuf, []byte{7, 8}) + trueBuf = append(trueBuf, []byte{9, 10}) + buf, err := SplitBlob(data, blen) + if err != nil { + t.Fatal(err) + } + if len(buf) != len(trueBuf) { + t.Fatal("invalid split") + } + for k := 0; k < len(trueBuf); k++ { + if !bytes.Equal(buf[k], trueBuf[k]) { + t.Fatalf("invalid buf split") + } + } +} + +func TestExtractHR(t *testing.T) { + trueCid := uint32(42) + trueHeight := uint32(137) + trueRound := uint32(1) + bclaims := &BClaims{ + ChainID: trueCid, + Height: trueHeight, + TxCount: 0, + PrevBlock: crypto.Hasher([]byte("Genesis")), + TxRoot: crypto.Hasher([]byte("")), + StateRoot: crypto.Hasher([]byte("")), + HeaderRoot: crypto.Hasher([]byte("")), + } + height, round := ExtractHR(bclaims) + if height != trueHeight { + t.Fatal("Invalid height") + } + if round != trueRound { + t.Fatal("Invalid round") + } +} + +func TestExtractHRBad(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("Should panic") + } + }() + ExtractHR(nil) +} + +func TestExtractHCID(t *testing.T) { + trueCid := uint32(42) + trueHeight := uint32(137) + bclaims := &BClaims{ + ChainID: trueCid, + Height: trueHeight, + TxCount: 0, + PrevBlock: crypto.Hasher([]byte("Genesis")), + TxRoot: crypto.Hasher([]byte("")), + StateRoot: crypto.Hasher([]byte("")), + HeaderRoot: crypto.Hasher([]byte("")), + } + height, cid := ExtractHCID(bclaims) + if height != trueHeight { + t.Fatal("Invalid height") + } + if cid != trueCid { + t.Fatal("Invalid ChainID") + } +} + +func TestExtractHCIDBad(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("Should panic") + } + }() + ExtractHCID(nil) +} + +func TestExtractRCertAny(t *testing.T) { + cid := uint32(1) + height := uint32(2) + prevBlock := crypto.Hasher([]byte("Genesis")) + txRoot := crypto.Hasher([]byte("TxRoot")) + stateRoot := crypto.Hasher([]byte("StateRoot")) + headerRoot := crypto.Hasher([]byte("HeaderRoot")) + bc := &BClaims{ + ChainID: cid, + Height: height, + TxCount: 0, + PrevBlock: prevBlock, + TxRoot: txRoot, + StateRoot: stateRoot, + HeaderRoot: headerRoot, + } + sigGroup := make([]byte, constants.CurveBN256EthSigLen) + bh := &BlockHeader{ + BClaims: bc, + SigGroup: sigGroup, + } + bhsh, err := bh.BlockHash() + if err != nil { + t.Fatal(err) + } + + rc, err := ExtractRCertAny(bh) + if err != nil { + t.Fatal(err) + } + if rc.RClaims.ChainID != cid { + t.Fatal("invalid ChainID") + } + if rc.RClaims.Height != height+1 { + t.Fatal("invalid Height") + } + if rc.RClaims.Round != 1 { + t.Fatal("invalid Round") + } + if !bytes.Equal(bhsh, rc.RClaims.PrevBlock) { + t.Fatal("invalid PrevBlock") + } +} + +func TestExtractRCertAnyBad(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("Should panic") + } + }() + ExtractRCertAny(nil) +} + +func TestExtractRCertBad(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("Should panic") + } + }() + ExtractRCert(nil) +} + +func TestExtractBClaimsBad(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("Should panic") + } + }() + ExtractBClaims(nil) +} + +func TestRelateHR(t *testing.T) { + cid := uint32(66) + height1 := uint32(2) + round1 := uint32(1) + prevHash1 := make([]byte, constants.HashLen) + rc1 := &RClaims{ + ChainID: cid, + Height: height1, + Round: round1, + PrevBlock: prevHash1, + } + + height2 := uint32(2) + round2 := uint32(2) + prevHash2 := make([]byte, constants.HashLen) + rc2 := &RClaims{ + ChainID: cid, + Height: height2, + Round: round2, + PrevBlock: prevHash2, + } + + rel := RelateHR(rc1, rc2) + if rel != -1 { + t.Fatal("Should return -1") + } + + rel = RelateHR(rc2, rc1) + if rel != 1 { + t.Fatal("Should return 1") + } + + rel = RelateHR(rc1, rc1) + if rel != 0 { + t.Fatal("Should return 0") + } + + height3 := uint32(3) + round3 := uint32(1) + prevHash3 := make([]byte, constants.HashLen) + rc3 := &RClaims{ + ChainID: cid, + Height: height3, + Round: round3, + PrevBlock: prevHash3, + } + + height4 := uint32(4) + round4 := uint32(2) + prevHash4 := make([]byte, constants.HashLen) + rc4 := &RClaims{ + ChainID: cid, + Height: height4, + Round: round4, + PrevBlock: prevHash4, + } + + rel = RelateHR(rc3, rc4) + if rel != -1 { + t.Fatal("Should return -1") + } + rel = RelateHR(rc4, rc3) + if rel != 1 { + t.Fatal("Should return 1") + } +} + +func TestBClaimsEqual(t *testing.T) { + height1 := uint32(1) + cid := uint32(1) + bc1 := &BClaims{ + ChainID: cid, + Height: height1, + TxCount: 0, + PrevBlock: crypto.Hasher([]byte("Genesis")), + TxRoot: crypto.Hasher([]byte("")), + StateRoot: crypto.Hasher([]byte("")), + HeaderRoot: crypto.Hasher([]byte("")), + } + bh1 := &BlockHeader{ + BClaims: bc1, + } + + height2 := uint32(2) + bc2 := &BClaims{ + ChainID: cid, + Height: height2, + TxCount: 0, + PrevBlock: crypto.Hasher([]byte("Genesis")), + TxRoot: crypto.Hasher([]byte("")), + StateRoot: crypto.Hasher([]byte("")), + HeaderRoot: crypto.Hasher([]byte("")), + } + bh2 := &BlockHeader{ + BClaims: bc2, + } + + equal, err := BClaimsEqual(bh1, bh2) + if err != nil { + t.Fatal(err) + } + if equal { + t.Fatal("Should not be equal") + } + equal, err = BClaimsEqual(bh1, bh1) + if err != nil { + t.Fatal(err) + } + if !equal { + t.Fatal("Should be equal") + } + + bcBad := &BClaims{} + bhBad := &BlockHeader{ + BClaims: bcBad, + } + _, err = BClaimsEqual(bh1, bhBad) + if err == nil { + t.Fatal("Should raise an error (1)") + } + _, err = BClaimsEqual(bhBad, bh1) + if err == nil { + t.Fatal("Should raise an error (2)") + } +} diff --git a/consensus/objs/v.go b/consensus/objs/v.go index aee32e93..7b0c0e09 100644 --- a/consensus/objs/v.go +++ b/consensus/objs/v.go @@ -4,7 +4,7 @@ import ( mdefs "github.com/MadBase/MadNet/consensus/objs/capn" "github.com/MadBase/MadNet/consensus/objs/validator" "github.com/MadBase/MadNet/errorz" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" capnp "zombiezen.com/go/capnproto2" ) @@ -31,8 +31,8 @@ func (b *Validator) UnmarshalCapn(bh mdefs.Validator) error { if err != nil { return err } - b.VAddr = gUtils.CopySlice(bh.VAddr()) - b.GroupShare = gUtils.CopySlice(bh.GroupShare()) + b.VAddr = utils.CopySlice(bh.VAddr()) + b.GroupShare = utils.CopySlice(bh.GroupShare()) return nil } diff --git a/consensus/objs/vs.go b/consensus/objs/vs.go index 86655d55..0fa6134e 100644 --- a/consensus/objs/vs.go +++ b/consensus/objs/vs.go @@ -3,11 +3,10 @@ package objs import ( "bytes" - "github.com/MadBase/MadNet/errorz" - mdefs "github.com/MadBase/MadNet/consensus/objs/capn" "github.com/MadBase/MadNet/consensus/objs/vset" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/errorz" + "github.com/MadBase/MadNet/utils" capnp "zombiezen.com/go/capnproto2" ) @@ -41,7 +40,7 @@ func (b *ValidatorSet) UnmarshalCapn(bh mdefs.ValidatorSet) error { return err } b.NotBefore = bh.NotBefore() - b.GroupKey = gUtils.CopySlice(bh.GroupKey()) + b.GroupKey = utils.CopySlice(bh.GroupKey()) valList, err := bh.Validators() if err != nil { return err @@ -136,7 +135,7 @@ func (b *ValidatorSet) GroupShareIdx(groupShare []byte) (bool, int) { } func (b *ValidatorSet) IsVAddrValidator(addr []byte) bool { - addrCopy := gUtils.CopySlice(addr) + addrCopy := utils.CopySlice(addr) return b.ValidatorVAddrSet[string(addrCopy)] } diff --git a/consensus/objs/vskey.go b/consensus/objs/vskey.go index 6afab7d6..9e2feb43 100644 --- a/consensus/objs/vskey.go +++ b/consensus/objs/vskey.go @@ -2,7 +2,7 @@ package objs import ( "github.com/MadBase/MadNet/errorz" - gUtils "github.com/MadBase/MadNet/utils" + "github.com/MadBase/MadNet/utils" ) // ValidatorSetKey ... @@ -20,8 +20,8 @@ func (b *ValidatorSetKey) UnmarshalBinary(data []byte) error { if len(data) != 6 { return errorz.ErrInvalid{}.New("data incorrect length for unmarshalling ValidatorSetKey") } - b.Prefix = gUtils.CopySlice(data[0:2]) - nb, _ := gUtils.UnmarshalUint32(data[2:6]) + b.Prefix = utils.CopySlice(data[0:2]) + nb, _ := utils.UnmarshalUint32(data[2:6]) if nb == 0 { return errorz.ErrInvalid{}.New("invalid NotBefore for unmarshalling ValidatorSetKey; NotBefore == 0") } @@ -36,8 +36,8 @@ func (b *ValidatorSetKey) MarshalBinary() ([]byte, error) { return nil, errorz.ErrInvalid{}.New("not initialized") } key := []byte{} - Prefix := gUtils.CopySlice(b.Prefix) - nb := gUtils.MarshalUint32(b.NotBefore) + Prefix := utils.CopySlice(b.Prefix) + nb := utils.MarshalUint32(b.NotBefore) key = append(key, Prefix...) key = append(key, nb...) return key, nil diff --git a/consensus/request/client.go b/consensus/request/client.go index e52cbd19..7ccc4f83 100644 --- a/consensus/request/client.go +++ b/consensus/request/client.go @@ -6,6 +6,7 @@ import ( "github.com/MadBase/MadNet/consensus/objs" "github.com/MadBase/MadNet/constants" "github.com/MadBase/MadNet/crypto" + "github.com/MadBase/MadNet/dynamics" "github.com/MadBase/MadNet/errorz" "github.com/MadBase/MadNet/logging" "github.com/MadBase/MadNet/middleware" @@ -22,14 +23,16 @@ type Client struct { logger *logrus.Logger secpVal *crypto.Secp256k1Validator groupVal *crypto.BNGroupValidator + storage dynamics.StorageGetter } // Init initializes the object -func (rb *Client) Init(client pb.P2PClient) { +func (rb *Client) Init(client pb.P2PClient, storage dynamics.StorageGetter) { rb.logger = logging.GetLogger(constants.LoggerConsensus) rb.client = client rb.groupVal = &crypto.BNGroupValidator{} rb.secpVal = &crypto.Secp256k1Validator{} + rb.storage = storage } // RequestP2PGetSnapShotNode implements the client for the P2P method diff --git a/consensus/request/handlers.go b/consensus/request/handlers.go index c90645ca..670f3f14 100644 --- a/consensus/request/handlers.go +++ b/consensus/request/handlers.go @@ -5,6 +5,7 @@ import ( "sync" "github.com/MadBase/MadNet/constants" + "github.com/MadBase/MadNet/dynamics" "github.com/MadBase/MadNet/consensus/db" "github.com/MadBase/MadNet/interfaces" @@ -36,10 +37,11 @@ type Handler struct { database *db.Database logger *logrus.Logger app appHandler + storage dynamics.StorageGetter } // Init initializes the object -func (rb *Handler) Init(database *db.Database, app appHandler) { +func (rb *Handler) Init(database *db.Database, app appHandler, storage dynamics.StorageGetter) { rb.logger = logging.GetLogger(constants.LoggerConsensus) background := context.Background() ctx, cf := context.WithCancel(background) @@ -48,6 +50,7 @@ func (rb *Handler) Init(database *db.Database, app appHandler) { rb.wg = sync.WaitGroup{} rb.app = app rb.database = database + rb.storage = storage } // Done will trInger when both of the gossip busses have stopped @@ -111,7 +114,7 @@ func (rb *Handler) HandleP2PGetBlockHeaders(ctx context.Context, r *pb.GetBlockH if err != nil { return err } - if len(hdrbytes)+byteCount < constants.MaxBytes { + if len(hdrbytes)+byteCount < int(rb.storage.GetMaxBytes()) { byteCount = byteCount + len(hdrbytes) hdrs = append(hdrs, hdrbytes) } else { diff --git a/consensus/synchronizer.go b/consensus/synchronizer.go index 69cb335a..40e56502 100644 --- a/consensus/synchronizer.go +++ b/consensus/synchronizer.go @@ -12,6 +12,7 @@ import ( "github.com/MadBase/MadNet/consensus/gossip" "github.com/MadBase/MadNet/consensus/lstate" "github.com/MadBase/MadNet/constants" + "github.com/MadBase/MadNet/dynamics" "github.com/MadBase/MadNet/errorz" "github.com/MadBase/MadNet/logging" "github.com/MadBase/MadNet/peering" @@ -211,10 +212,12 @@ type Synchronizer struct { peerMinThresh *remoteVar ethSyncDone *remoteVar madSyncDone *resetVar + + storage dynamics.StorageGetter } // Init initializes the struct -func (s *Synchronizer) Init(cdb *db.Database, mdb *badger.DB, tdb *badger.DB, gc *gossip.Client, gh *gossip.Handlers, ep *evidence.Pool, eng *lstate.Engine, app *application.Application, ah *admin.Handlers, pman *peering.PeerManager) { +func (s *Synchronizer) Init(cdb *db.Database, mdb *badger.DB, tdb *badger.DB, gc *gossip.Client, gh *gossip.Handlers, ep *evidence.Pool, eng *lstate.Engine, app *application.Application, ah *admin.Handlers, pman *peering.PeerManager, storage dynamics.StorageGetter) { s.logger = logging.GetLogger(constants.LoggerConsensus) s.cdb = cdb s.mdb = mdb @@ -234,6 +237,7 @@ func (s *Synchronizer) Init(cdb *db.Database, mdb *badger.DB, tdb *badger.DB, gc s.ethSyncDone = newRemoteVar(s.adminHandler.IsSynchronized) s.peerMinThresh = newRemoteVar(s.peerMan.PeeringComplete) s.madSyncDone = newResetVar() + s.storage = storage } func (s *Synchronizer) CloseChan() <-chan struct{} { @@ -414,7 +418,7 @@ func (s *Synchronizer) adminInteruptLoop() { func (s *Synchronizer) setupLoops() { stateLoopInSyncConfig := newLoopConfig(). withName("StateLoop-InSync"). - withInitialDelay(9*constants.MsgTimeout). + withInitialDelay(9*s.storage.GetMsgTimeout()). withFn2(s.stateHandler.UpdateLocalState, s.madSyncDone.set). withFreq(200 * time.Millisecond). withDelayOnConditionFailure(200 * time.Millisecond). @@ -461,10 +465,10 @@ func (s *Synchronizer) setupLoops() { reGossipLoopConfig := newLoopConfig(). withName("ReGossipLoop"). - withInitialDelay(9 * constants.MsgTimeout). + withInitialDelay(9 * s.storage.GetMsgTimeout()). withFn(s.gossipClient.ReGossip). - withFreq(9 * constants.MsgTimeout). - withDelayOnConditionFailure(constants.MsgTimeout). + withFreq(9 * s.storage.GetMsgTimeout()). + withDelayOnConditionFailure(s.storage.GetMsgTimeout()). withLockFreeCondition(s.isNotClosing). withLockFreeCondition(s.initialized.isSet). withLockFreeCondition(s.ethSyncDone.isSet). diff --git a/constants/consensus.go b/constants/consensus.go index b0ba82fe..8ff719c6 100644 --- a/constants/consensus.go +++ b/constants/consensus.go @@ -6,15 +6,8 @@ import "time" const ( DEADBLOCKROUND uint32 = 5 DEADBLOCKROUNDNR = DEADBLOCKROUND - 1 - MaxBytes = 3000000 - MaxProposalSize = MaxBytes SrvrMsgTimeout = 3 * time.Second // Do not go lower than 2 seconds! MsgTimeout = 4 * time.Second // Do not go lower than 2 seconds! - ProposalStepTO = 4 * time.Second //4 * time.Second - PreVoteStepTO = 3 * time.Second //4 * time.Second - PreCommitStepTO = 3 * time.Second //4 * time.Second - DBRNRTO = 24 * time.Second - DownloadTO = ProposalStepTO + PreVoteStepTO + PreCommitStepTO ) // AdminHandlerKid returns a constant byte slice to be used as Key ID diff --git a/constants/dbprefix/consensus.go b/constants/dbprefix/consensus.go index 8f639027..8c9b0ac8 100644 --- a/constants/dbprefix/consensus.go +++ b/constants/dbprefix/consensus.go @@ -122,6 +122,14 @@ func PrefixStagedBlockHeaderKey() []byte { return []byte("a3") } +func PrefixRawStorageKey() []byte { + return []byte("a4") +} + +func PrefixStorageNodeKey() []byte { + return []byte("a5") +} + func PrefixPendingNodeKeyCount() []byte { return []byte("Ay") } diff --git a/crypto/bn.go b/crypto/bn.go index 9ec1b729..67fd54b5 100644 --- a/crypto/bn.go +++ b/crypto/bn.go @@ -13,24 +13,28 @@ type BNSigner struct { } // SetPrivk sets the private key of the BNSigner. -func (bns *BNSigner) SetPrivk(privk []byte) { +func (bns *BNSigner) SetPrivk(privk []byte) error { + if bns == nil { + return ErrInvalid + } bns.privk = new(big.Int).SetBytes(privk) bns.privk.Mod(bns.privk, bn256.Order) bns.pubk = new(bn256.G2).ScalarBaseMult(bns.privk) + return nil } // Pubkey returns the marshalled public key of the BNSigner. func (bns *BNSigner) Pubkey() ([]byte, error) { - if bns.privk != nil { - return bns.pubk.Marshal(), nil + if bns == nil || bns.privk == nil { + return nil, ErrPrivkNotSet } - return nil, ErrPrivkNotSet + return bns.pubk.Marshal(), nil } // Sign will generate a signature for msg using the private key of the // BNSigner. func (bns *BNSigner) Sign(msg []byte) ([]byte, error) { - if bns.privk == nil { + if bns == nil || bns.privk == nil { return nil, ErrPrivkNotSet } pubkbytes := bns.pubk.Marshal() diff --git a/crypto/bn_test.go b/crypto/bn_test.go index 16e392a3..4408d604 100644 --- a/crypto/bn_test.go +++ b/crypto/bn_test.go @@ -17,7 +17,10 @@ func TestSetPrivK(t *testing.T) { privkBig, _ := new(big.Int).SetString("1234567890", 10) privkBig.Mod(privkBig, cloudflare.Order) privk := privkBig.Bytes() - s.SetPrivk(privk) + err = s.SetPrivk(privk) + if err != nil { + t.Fatal(err) + } } func TestSignAndValidate(t *testing.T) { @@ -29,7 +32,10 @@ func TestSignAndValidate(t *testing.T) { if err != ErrPrivkNotSet { t.Fatal("Should raise private key not set error!") } - s.SetPrivk(Hasher([]byte("secret"))) + err = s.SetPrivk(Hasher([]byte("secret"))) + if err != nil { + t.Fatal(err) + } signature, err := s.Sign(msg) if err != nil { t.Fatal(err) @@ -67,7 +73,10 @@ func TestSignerPubkeyFromSig(t *testing.T) { // Valid signature and validation s := &BNSigner{} - s.SetPrivk(Hasher([]byte("secret"))) + err := s.SetPrivk(Hasher([]byte("secret"))) + if err != nil { + t.Fatal(err) + } signature, err := s.Sign(msg) if err != nil { t.Fatal(err) diff --git a/crypto/bngroup.go b/crypto/bngroup.go index 6a0422db..8935c86c 100644 --- a/crypto/bngroup.go +++ b/crypto/bngroup.go @@ -15,15 +15,22 @@ type BNGroupSigner struct { } // SetPrivk sets the private key of the BNGroupSigner. -func (bns *BNGroupSigner) SetPrivk(privk []byte) { +func (bns *BNGroupSigner) SetPrivk(privk []byte) error { + if bns == nil { + return ErrInvalid + } bns.privk = new(big.Int).SetBytes(privk) bns.privk.Mod(bns.privk, bn256.Order) bns.pubk = new(bn256.G2).ScalarBaseMult(bns.privk) + return nil } // SetGroupPubk will set the public key of the entire group; // this is also called the master public key. func (bns *BNGroupSigner) SetGroupPubk(groupPubk []byte) error { + if bns == nil { + return ErrInvalid + } pubkpoint := new(bn256.G2) _, err := pubkpoint.Unmarshal(groupPubk) if err != nil { @@ -64,25 +71,28 @@ func (bns *BNGroupSigner) VerifyGroupShares(groupShares [][]byte) error { // PubkeyShare returns the marshalled public key of the BNGroupSigner func (bns *BNGroupSigner) PubkeyShare() ([]byte, error) { - if bns.privk != nil { - return bns.pubk.Marshal(), nil + if bns == nil || bns.privk == nil { + return nil, ErrPrivkNotSet } - return nil, ErrPrivkNotSet + return bns.pubk.Marshal(), nil } // PubkeyGroup returns the marshalled public key of the group // (master public key). func (bns *BNGroupSigner) PubkeyGroup() ([]byte, error) { - if bns.groupPubk != nil { - return bns.groupPubk.Marshal(), nil + if bns == nil || bns.groupPubk == nil { + return nil, ErrPubkeyGroupNotSet } - return nil, ErrPubkeyGroupNotSet + return bns.groupPubk.Marshal(), nil } // Sign will generate a signature for msg using the private key of the // BNGroupSigner; this signature can be aggregated to form a valid // group signature. func (bns *BNGroupSigner) Sign(msg []byte) ([]byte, error) { + if bns == nil { + return nil, ErrInvalid + } sigpoint, err := bn256.Sign(msg, bns.privk, bn256.HashToG1) if err != nil { return nil, err @@ -93,6 +103,9 @@ func (bns *BNGroupSigner) Sign(msg []byte) ([]byte, error) { // Aggregate attempts to combine the slice of signatures in sigs into // a group signature. func (bns *BNGroupSigner) Aggregate(sigs [][]byte, groupShares [][]byte) ([]byte, error) { + if bns == nil { + return nil, ErrInvalid + } err := bns.VerifyGroupShares(groupShares) if err != nil { return nil, err diff --git a/crypto/bngroup_test.go b/crypto/bngroup_test.go index 1f03a199..fb7f8e4e 100644 --- a/crypto/bngroup_test.go +++ b/crypto/bngroup_test.go @@ -13,7 +13,10 @@ func TestGroupSignerSetPrivK(t *testing.T) { privkBig, _ := new(big.Int).SetString("1234567890", 10) privkBig.Mod(privkBig, bn256.Order) privk := privkBig.Bytes() - s.SetPrivk(privk) + err := s.SetPrivk(privk) + if err != nil { + t.Fatal(err) + } } func TestGroupSignerSetGroupPubk(t *testing.T) { @@ -48,7 +51,10 @@ func TestGroupSignerPubkeyShare(t *testing.T) { privk := privkBig.Bytes() pubkBN := new(bn256.G2).ScalarBaseMult(privkBig) pubkBNBytes := pubkBN.Marshal() - s.SetPrivk(privk) + err = s.SetPrivk(privk) + if err != nil { + t.Fatal(err) + } pubkBytes, err := s.PubkeyShare() if err != nil { t.Fatal("Error occurred when calling bns.PubkeyShare()") @@ -89,7 +95,10 @@ func TestGroupSignAndValidate(t *testing.T) { s := new(BNGroupSigner) privkBig := big.NewInt(1234567890) privk := privkBig.Bytes() - s.SetPrivk(privk) + err := s.SetPrivk(privk) + if err != nil { + t.Fatal(err) + } sig, err := s.Sign(msg) if err != nil { t.Fatal(err) @@ -131,7 +140,10 @@ func TestGroupSignerPubkeyFromSig(t *testing.T) { s := new(BNGroupSigner) privkBig := big.NewInt(1234567890) privk := privkBig.Bytes() - s.SetPrivk(privk) + err := s.SetPrivk(privk) + if err != nil { + t.Fatal(err) + } sig, err := s.Sign(msg) if err != nil { t.Fatal(err) @@ -314,7 +326,10 @@ func TestGroupSignerAggregate(t *testing.T) { gpk1 := new(bn256.G2).ScalarBaseMult(gsk1) groupShares[0] = gpk1.Marshal() s1 := new(BNGroupSigner) - s1.SetPrivk(gsk1.Bytes()) + err := s1.SetPrivk(gsk1.Bytes()) + if err != nil { + t.Fatal(err) + } sig1, err := s1.Sign(msg) if err != nil { t.Fatal(err) @@ -325,7 +340,10 @@ func TestGroupSignerAggregate(t *testing.T) { gpk2 := new(bn256.G2).ScalarBaseMult(gsk2) groupShares[1] = gpk2.Marshal() s2 := new(BNGroupSigner) - s2.SetPrivk(gsk2.Bytes()) + err = s2.SetPrivk(gsk2.Bytes()) + if err != nil { + t.Fatal(err) + } sig2, err := s2.Sign(msg) if err != nil { t.Fatal(err) @@ -336,7 +354,10 @@ func TestGroupSignerAggregate(t *testing.T) { gpk3 := new(bn256.G2).ScalarBaseMult(gsk3) groupShares[2] = gpk3.Marshal() s3 := new(BNGroupSigner) - s3.SetPrivk(gsk3.Bytes()) + err = s3.SetPrivk(gsk3.Bytes()) + if err != nil { + t.Fatal(err) + } sig3, err := s3.Sign(msg) if err != nil { t.Fatal(err) @@ -347,7 +368,10 @@ func TestGroupSignerAggregate(t *testing.T) { gpk4 := new(bn256.G2).ScalarBaseMult(gsk4) groupShares[3] = gpk4.Marshal() s4 := new(BNGroupSigner) - s4.SetPrivk(gsk4.Bytes()) + err = s4.SetPrivk(gsk4.Bytes()) + if err != nil { + t.Fatal(err) + } sig4, err := s4.Sign(msg) if err != nil { t.Fatal(err) diff --git a/crypto/errors.go b/crypto/errors.go index 39289f19..2428b73d 100644 --- a/crypto/errors.go +++ b/crypto/errors.go @@ -13,6 +13,10 @@ var ( // ErrInvalidSignature occurs when signature validation fails ErrInvalidSignature = errors.New("signature validation failed") + // ErrInvalid occurs when signer is not valid; + // this occurs when signer is not initialized. + ErrInvalid = errors.New("invalid signer") + // ErrInvalidPubkeyShares occurs when multiple copies of the same public // key are contained when attempting to set GroupShares. ErrInvalidPubkeyShares = errors.New("groupShares contains repeated public keys") diff --git a/crypto/secp.go b/crypto/secp.go index 28a495b3..93382bdf 100644 --- a/crypto/secp.go +++ b/crypto/secp.go @@ -17,15 +17,18 @@ type Secp256k1Signer struct { // Pubkey returns the marshalled public key of the Secp256k1Signer // (uncompressed format). func (secps *Secp256k1Signer) Pubkey() ([]byte, error) { - if secps.privk != nil { - return utils.CopySlice(secps.pubk), nil + if secps == nil || secps.privk == nil { + return nil, ErrPrivkNotSet } - return nil, ErrPrivkNotSet + return utils.CopySlice(secps.pubk), nil } // SetPrivk sets the private key of the Secp256k1Signer; // privk is required to be 32 bytes! func (secps *Secp256k1Signer) SetPrivk(privk []byte) error { + if secps == nil { + return ErrInvalid + } ecprivk, err := eth.ToECDSA(privk) if err != nil { return err @@ -40,7 +43,7 @@ func (secps *Secp256k1Signer) SetPrivk(privk []byte) error { // Secp256k1Signer; eth.Sign *assumes* we are signing the // *hash of the message* (digestHash) and *not* the message itself. func (secps *Secp256k1Signer) Sign(msg []byte) ([]byte, error) { - if secps.privk == nil { + if secps == nil || secps.privk == nil { return nil, ErrPrivkNotSet } digestHash := Hasher(msg) diff --git a/dynamics/consensus.go b/dynamics/consensus.go new file mode 100644 index 00000000..2d6a1c04 --- /dev/null +++ b/dynamics/consensus.go @@ -0,0 +1,18 @@ +package dynamics + +import ( + "time" +) + +// Original from constants/consensus.go +const ( + maxBytes = 3000000 + maxProposalSize = maxBytes // Parameterize: equal to maxBytes + msgTimeout = 4 * time.Second + srvrMsgTimeout = (3 * msgTimeout) / 4 // Parameterize: 0.75*MsgTimeout + proposalStepTO = 4 * time.Second + preVoteStepTO = 3 * time.Second + preCommitStepTO = 3 * time.Second + dBRNRTO = (5 * (proposalStepTO + preVoteStepTO + preCommitStepTO)) / 2 // Parameterize: make 2.5 times Prop, PV, PC timeouts + downloadTO = proposalStepTO + preVoteStepTO + preCommitStepTO // Parameterize: sum of Prop, PV, PC timeouts +) diff --git a/dynamics/db.go b/dynamics/db.go new file mode 100644 index 00000000..d57045b5 --- /dev/null +++ b/dynamics/db.go @@ -0,0 +1,108 @@ +package dynamics + +import ( + "sync" + + "github.com/dgraph-io/badger/v2" + "github.com/sirupsen/logrus" +) + +// Database is an abstraction for object storage +type Database struct { + sync.Mutex + rawDB rawDataBase + logger *logrus.Logger +} + +// SetNode stores Node in the database +func (db *Database) SetNode(txn *badger.Txn, node *Node) error { + if !node.IsValid() { + return ErrInvalidNode + } + nodeKey, err := makeNodeKey(node.thisEpoch) + if err != nil { + return err + } + key, err := nodeKey.Marshal() + if err != nil { + return err + } + nodeBytes, err := node.Marshal() + if err != nil { + return err + } + err = db.rawDB.SetValue(txn, key, nodeBytes) + if err != nil { + return err + } + return nil +} + +// GetNode retrieves Node from the database +func (db *Database) GetNode(txn *badger.Txn, epoch uint32) (*Node, error) { + nodeKey, err := makeNodeKey(epoch) + if err != nil { + return nil, err + } + key, err := nodeKey.Marshal() + if err != nil { + return nil, err + } + v, err := db.rawDB.GetValue(txn, key) + if err != nil { + return nil, err + } + node := &Node{} + err = node.Unmarshal(v) + if err != nil { + return nil, err + } + if !node.IsValid() { + return nil, ErrInvalidNode + } + return node, nil +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +// SetLinkedList saves LinkedList to the database +func (db *Database) SetLinkedList(txn *badger.Txn, ll *LinkedList) error { + if !ll.IsValid() { + return ErrInvalid + } + value := ll.Marshal() + llKey := makeLinkedListKey() + key, err := llKey.Marshal() + if err != nil { + return err + } + err = db.rawDB.SetValue(txn, key, value) + if err != nil { + return err + } + return nil +} + +// GetLinkedList retrieves LinkedList from the database +func (db *Database) GetLinkedList(txn *badger.Txn) (*LinkedList, error) { + llKey := makeLinkedListKey() + key, err := llKey.Marshal() + if err != nil { + return nil, err + } + v, err := db.rawDB.GetValue(txn, key) + if err != nil { + return nil, err + } + ll := &LinkedList{} + err = ll.Unmarshal(v) + if err != nil { + return nil, err + } + if !ll.IsValid() { + return nil, ErrInvalid + } + return ll, nil +} diff --git a/dynamics/db_test.go b/dynamics/db_test.go new file mode 100644 index 00000000..4086cbf6 --- /dev/null +++ b/dynamics/db_test.go @@ -0,0 +1,166 @@ +package dynamics + +import ( + "bytes" + "testing" + + "github.com/dgraph-io/badger/v2" + "github.com/sirupsen/logrus" +) + +type mockRawDB struct { + rawDB map[string]string +} + +func (m *mockRawDB) GetValue(txn *badger.Txn, key []byte) ([]byte, error) { + strKey := string(key) + strValue, ok := m.rawDB[strKey] + if !ok { + return nil, ErrKeyNotPresent + } + value := []byte(strValue) + return value, nil +} + +func (m *mockRawDB) SetValue(txn *badger.Txn, key []byte, value []byte) error { + strKey := string(key) + strValue := string(value) + m.rawDB[strKey] = strValue + return nil +} + +func (m *mockRawDB) DeleteValue(key []byte) error { + strKey := string(key) + _, ok := m.rawDB[strKey] + if !ok { + return ErrKeyNotPresent + } + delete(m.rawDB, strKey) + return nil +} + +func (m *mockRawDB) View(fn func(txn *badger.Txn) error) error { + return fn(nil) +} + +func (m *mockRawDB) Update(fn func(txn *badger.Txn) error) error { + return fn(nil) +} + +func TestMock(t *testing.T) { + key := []byte("Key") + value := []byte("Key") + + m := &mockRawDB{} + m.rawDB = make(map[string]string) + + _, err := m.GetValue(nil, key) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + err = m.SetValue(nil, key, value) + if err != nil { + t.Fatal(err) + } + + retValue, err := m.GetValue(nil, key) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(retValue, value) { + t.Fatal("values do not match") + } + + err = m.DeleteValue(key) + if err != nil { + t.Fatal(err) + } + _, err = m.GetValue(nil, key) + if err == nil { + t.Fatal("Should have raised error (2)") + } +} + +func newLogger() *logrus.Logger { + logger := logrus.New() + return logger +} + +func initializeDB() *Database { + logger := newLogger() + db := &Database{} + db.logger = logger + mock := &mockRawDB{} + mock.rawDB = make(map[string]string) + db.rawDB = mock + return db +} + +func TestGetSetNode(t *testing.T) { + db := initializeDB() + + node := &Node{} + err := db.SetNode(nil, node) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + node.prevEpoch = 1 + node.thisEpoch = 1 + node.nextEpoch = 1 + node.rawStorage = &RawStorage{} + err = db.SetNode(nil, node) + if err != nil { + t.Fatal(err) + } + nodeBytes, err := node.Marshal() + if err != nil { + t.Fatal(err) + } + + // Should raise error + _, err = db.GetNode(nil, 0) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + node2, err := db.GetNode(nil, 1) + if err != nil { + t.Fatal(err) + } + node2Bytes, err := node2.Marshal() + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(nodeBytes, node2Bytes) { + t.Fatal("nodes do not match") + } +} + +func TestGetSetLinkedList(t *testing.T) { + db := initializeDB() + + ll := &LinkedList{} + err := db.SetLinkedList(nil, ll) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + ll.epochLastUpdated = 1 + err = db.SetLinkedList(nil, ll) + if err != nil { + t.Fatal(err) + } + llBytes := ll.Marshal() + + ll2, err := db.GetLinkedList(nil) + if err != nil { + t.Fatal(err) + } + ll2Bytes := ll2.Marshal() + if !bytes.Equal(llBytes, ll2Bytes) { + t.Fatal("LinkedLists do not match") + } +} diff --git a/dynamics/errors.go b/dynamics/errors.go new file mode 100644 index 00000000..cb1c5545 --- /dev/null +++ b/dynamics/errors.go @@ -0,0 +1,41 @@ +package dynamics + +import ( + "errors" + + "github.com/dgraph-io/badger/v2" +) + +var ( + // ErrRawStorageNilPointer is an error which results from a + // RawStorage struct which has not been initialized. + ErrRawStorageNilPointer = errors.New("invalid RawStorage: nil pointer") + + // ErrZeroEpoch is an error which is raised whenever the epoch is given + // as zero; there is no zero epoch. + ErrZeroEpoch = errors.New("invalid epoch: no zero epoch") + + // ErrUnmarshalEmpty is an error which is raised whenever attempting + // to unmarshal an empty byte slice. + ErrUnmarshalEmpty = errors.New("invalid: attempting to unmarshal empty byte slice") + + // ErrKeyNotPresent is an error which is raised when a key is not present + // in the database. + ErrKeyNotPresent = badger.ErrKeyNotFound + + // ErrInvalidUpdateValue is an error which is returned when the data + // for updating rawStorage is invalid. + ErrInvalidUpdateValue = errors.New("invalid update value for storage") + + // ErrInvalidValue is an error which is returned when the value is invalid. + ErrInvalidValue = errors.New("invalid value") + + // ErrInvalid is an error which is returned when the struct is invalid. + ErrInvalid = errors.New("invalid value") + + // ErrInvalidNodeKey is an error which occurs when the NodeKey is invalid + ErrInvalidNodeKey = errors.New("invalid NodeKey") + + // ErrInvalidNode is an error which occurs when a Node is invalid + ErrInvalidNode = errors.New("invalid Node") +) diff --git a/dynamics/linkedlist.go b/dynamics/linkedlist.go new file mode 100644 index 00000000..e705c777 --- /dev/null +++ b/dynamics/linkedlist.go @@ -0,0 +1,81 @@ +package dynamics + +import ( + "github.com/MadBase/MadNet/constants/dbprefix" + "github.com/MadBase/MadNet/utils" +) + +// LinkedList is a doubly linked list which will store nodes corresponding +// to changes to dynamic parameters. +// We store the largest epoch which has been updated. +type LinkedList struct { + epochLastUpdated uint32 +} + +func makeLinkedListKey() *NodeKey { + nk := &NodeKey{ + prefix: dbprefix.PrefixStorageNodeKey(), + epoch: 0, + } + return nk +} + +// GetEpochLastUpdated returns highest epoch with changes +func (ll *LinkedList) GetEpochLastUpdated() uint32 { + return ll.epochLastUpdated +} + +// SetEpochLastUpdated returns highest epoch with changes +func (ll *LinkedList) SetEpochLastUpdated(epoch uint32) error { + if epoch == 0 { + return ErrZeroEpoch + } + ll.epochLastUpdated = epoch + return nil +} + +// Marshal marshals LinkedList +func (ll *LinkedList) Marshal() []byte { + eluBytes := utils.MarshalUint32(ll.epochLastUpdated) + return eluBytes +} + +// Unmarshal unmarshals LinkedList +func (ll *LinkedList) Unmarshal(v []byte) error { + if len(v) != 4 { + return ErrInvalidNode + } + elu, _ := utils.UnmarshalUint32(v[0:4]) + ll.epochLastUpdated = elu + return nil +} + +// IsValid returns true if LinkedList is valid +func (ll *LinkedList) IsValid() bool { + if ll.epochLastUpdated == 0 { + return false + } + return true +} + +// CreateLinkedList creates the first node in a LinkedList. +// These values can then be stored in the database. +func CreateLinkedList(epoch uint32, rs *RawStorage) (*Node, *LinkedList, error) { + if epoch == 0 { + return nil, nil, ErrZeroEpoch + } + rsCopy, err := rs.Copy() + if err != nil { + return nil, nil, err + } + node := &Node{ + thisEpoch: epoch, + prevEpoch: epoch, + nextEpoch: epoch, + rawStorage: rsCopy, + } + linkedList := &LinkedList{ + epochLastUpdated: epoch, + } + return node, linkedList, nil +} diff --git a/dynamics/linkedlist_test.go b/dynamics/linkedlist_test.go new file mode 100644 index 00000000..4630f568 --- /dev/null +++ b/dynamics/linkedlist_test.go @@ -0,0 +1,120 @@ +package dynamics + +import ( + "bytes" + "testing" + + "github.com/MadBase/MadNet/constants" + "github.com/MadBase/MadNet/constants/dbprefix" +) + +func TestLinkedListMakeKeys(t *testing.T) { + llk := makeLinkedListKey() + if llk.epoch != 0 { + t.Fatal("epoch should be 0") + } + if !bytes.Equal(llk.prefix, dbprefix.PrefixStorageNodeKey()) { + t.Fatal("prefixes do not match") + } + llkBytes, err := llk.Marshal() + if err != nil { + t.Fatal(err) + } + llkTrue := []byte{} + llkTrue = append(llkTrue, dbprefix.PrefixStorageNodeKey()...) + llkTrue = append(llkTrue, 0, 0, 0, 0) + if !bytes.Equal(llkBytes, llkTrue) { + t.Fatal("marshalled bytes do not match") + } +} + +func TestLinkedListMarshal(t *testing.T) { + ll := &LinkedList{} + if ll.IsValid() { + t.Fatal("Should not have valid LinkedList") + } + + invalidBytes := []byte{0, 1, 2, 3, 4} + err := ll.Unmarshal(invalidBytes) + if err == nil { + t.Fatal("Should have raised error (2)") + } + + invalidBytes2 := make([]byte, 4) + err = ll.Unmarshal(invalidBytes2) + if err != nil { + t.Fatal(err) + } + if ll.epochLastUpdated != 0 { + t.Fatal("Should have raised error (3)") + } + + v := []byte{255, 255, 255, 255} + err = ll.Unmarshal(v) + if err != nil { + t.Fatal(err) + } + if ll.epochLastUpdated != constants.MaxUint32 { + t.Fatal("Invalid LinkedList (1)") + } + + retBytes := ll.Marshal() + if !bytes.Equal(retBytes, v) { + t.Fatal("invalid marshalled bytes") + } +} + +func TestLinkedListGetSet(t *testing.T) { + ll := &LinkedList{} + err := ll.SetEpochLastUpdated(0) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + elu := uint32(123456) + err = ll.SetEpochLastUpdated(elu) + if err != nil { + t.Fatal(err) + } + retElu := ll.GetEpochLastUpdated() + if retElu != elu { + t.Fatal("Invalid EpochLastUpdated") + } + + if !ll.IsValid() { + t.Fatal("LinkedList should be valid") + } +} + +func TestCreateLinkedList(t *testing.T) { + epoch := uint32(0) + _, _, err := CreateLinkedList(epoch, nil) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + epoch = 1 + _, _, err = CreateLinkedList(epoch, nil) + if err == nil { + t.Fatal("Should have raised error (2)") + } + + rs := &RawStorage{} + rs.standardParameters() + node, linkedlist, err := CreateLinkedList(epoch, rs) + if err != nil { + t.Fatal(err) + } + if node.thisEpoch != epoch { + t.Fatal("invalid thisEpoch") + } + if node.prevEpoch != epoch { + t.Fatal("invalid prevEpoch") + } + if node.nextEpoch != epoch { + t.Fatal("invalid nextEpoch") + } + if linkedlist.epochLastUpdated != epoch { + t.Fatal("invalid epochLastUpdated") + } +} diff --git a/dynamics/node.go b/dynamics/node.go new file mode 100644 index 00000000..b01a1315 --- /dev/null +++ b/dynamics/node.go @@ -0,0 +1,157 @@ +package dynamics + +import ( + "github.com/MadBase/MadNet/utils" +) + +// Node contains necessary information about RawStorage; +// it also points to the epoch of the previous node and next node +// in the doubly linked list. +type Node struct { + thisEpoch uint32 + prevEpoch uint32 + nextEpoch uint32 + rawStorage *RawStorage +} + +// Marshal marshals a Node +func (n *Node) Marshal() ([]byte, error) { + rsBytes, err := n.rawStorage.Marshal() + if err != nil { + return nil, err + } + teBytes := utils.MarshalUint32(n.thisEpoch) + peBytes := utils.MarshalUint32(n.prevEpoch) + neBytes := utils.MarshalUint32(n.nextEpoch) + v := []byte{} + v = append(v, teBytes...) + v = append(v, peBytes...) + v = append(v, neBytes...) + v = append(v, rsBytes...) + return v, nil +} + +// Unmarshal unmarshals a Node +func (n *Node) Unmarshal(v []byte) error { + if len(v) < 12 { + return ErrInvalid + } + thisEpoch, _ := utils.UnmarshalUint32(v[0:4]) + prevEpoch, _ := utils.UnmarshalUint32(v[4:8]) + nextEpoch, _ := utils.UnmarshalUint32(v[8:12]) + n.thisEpoch = thisEpoch + n.prevEpoch = prevEpoch + n.nextEpoch = nextEpoch + n.rawStorage = &RawStorage{} + err := n.rawStorage.Unmarshal(v[12:]) + if err != nil { + return err + } + return nil +} + +// IsValid returns true if Node is valid +func (n *Node) IsValid() bool { + if n == nil { + return false + } + if n.thisEpoch == 0 || n.prevEpoch == 0 || n.nextEpoch == 0 { + // node has not set values; invalid + return false + } + if n.prevEpoch > n.thisEpoch || n.thisEpoch > n.nextEpoch { + // node has not been correctly defined; invalid + return false + } + if !n.rawStorage.IsValid() { + return false + } + return true +} + +// IsPreValid returns true if Node is ready to be added to database +// but prevEpoch and nextEpoch are not yet set +func (n *Node) IsPreValid() bool { + if n == nil { + return false + } + if n.thisEpoch == 0 || n.prevEpoch != 0 || n.nextEpoch != 0 { + // Only thisEpoch should be set; invalid + return false + } + if !n.rawStorage.IsValid() { + return false + } + return true +} + +// Copy makes a copy of Node +func (n *Node) Copy() (*Node, error) { + nodeBytes, err := n.Marshal() + if err != nil { + return nil, err + } + nodeCopy := &Node{} + err = nodeCopy.Unmarshal(nodeBytes) + if err != nil { + return nil, err + } + return nodeCopy, nil +} + +// SetEpochs sets n.prevEpoch and n.nextEpoch. +func (n *Node) SetEpochs(prevNode *Node, nextNode *Node) error { + if !n.IsPreValid() { + return ErrInvalid + } + if prevNode.IsValid() && nextNode.IsValid() && prevNode.thisEpoch < n.thisEpoch && n.thisEpoch < nextNode.thisEpoch { + // In this setting, we want to add a new node in between prevNode and nextNode + // + // Update prevNode; + // must point forward to n + prevNode.nextEpoch = n.thisEpoch + // Update epochs for n; + // must point backward to prevNode and forward to nextNode + n.prevEpoch = prevNode.thisEpoch + n.nextEpoch = nextNode.thisEpoch + // Update nextNode; + // must point backward to n + nextNode.prevEpoch = n.thisEpoch + return nil + } + if prevNode.IsValid() && nextNode == nil && prevNode.thisEpoch < n.thisEpoch && prevNode.IsHead() { + // n is the new Head + // Update prevNode.nextEpoch + prevNode.nextEpoch = n.thisEpoch + // Update epochs for n; + // must point backward to prevNode and forward to self + n.prevEpoch = prevNode.thisEpoch + n.nextEpoch = n.thisEpoch + return nil + } + return ErrInvalid +} + +// IsHead returns true if Node is end of linked list; +// in this case, n.nextEpoch == n.thisEpoch +func (n *Node) IsHead() bool { + if !n.IsValid() { + return false + } + if n.thisEpoch == n.nextEpoch { + return true + } + return false +} + +// IsTail returns true if Node is beginning of linked list; +// in this case, n.prevEpoch == n.thisEpoch +func (n *Node) IsTail() bool { + if !n.IsValid() { + return false + } + if n.thisEpoch == n.prevEpoch { + return true + } + return false +} diff --git a/dynamics/node_test.go b/dynamics/node_test.go new file mode 100644 index 00000000..e2cfc8e4 --- /dev/null +++ b/dynamics/node_test.go @@ -0,0 +1,584 @@ +package dynamics + +import ( + "bytes" + "testing" +) + +func TestNodeMarshal(t *testing.T) { + node := &Node{} + _, err := node.Marshal() + if err == nil { + t.Fatal("Should have raied error (1)") + } + + epoch := uint32(1) + rs := &RawStorage{} + rs.standardParameters() + node, _, err = CreateLinkedList(epoch, rs) + if err != nil { + t.Fatal(err) + } + + nodeBytes, err := node.Marshal() + if err != nil { + t.Fatal(err) + } + node2 := &Node{} + err = node2.Unmarshal(nodeBytes) + if err != nil { + t.Fatal(err) + } + if node.thisEpoch != node2.thisEpoch { + t.Fatal("invalid thisEpoch") + } + if node.prevEpoch != node2.prevEpoch { + t.Fatal("invalid prevEpoch") + } + if node.nextEpoch != node2.nextEpoch { + t.Fatal("invalid nextEpoch") + } + rsBytes, err := node.rawStorage.Marshal() + if err != nil { + t.Fatal(err) + } + rs2Bytes, err := node2.rawStorage.Marshal() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(rsBytes, rs2Bytes) { + t.Fatal("invalid RawStroage") + } + + v := []byte{} + err = node.Unmarshal(v) + if err == nil { + t.Fatal("Should have raised error (2)") + } + + v = make([]byte, 12) + err = node.Unmarshal(v) + if err == nil { + t.Fatal("Should have raised error (3)") + } + + v = make([]byte, 13) + err = node.Unmarshal(v) + if err == nil { + t.Fatal("Should have raised error (4)") + } +} + +func TestNodeCopy(t *testing.T) { + n := &Node{} + _, err := n.Copy() + if err == nil { + t.Fatal("Should have raised error (1)") + } + + n.prevEpoch = 1 + n.thisEpoch = 1 + n.nextEpoch = 1 + n.rawStorage = &RawStorage{} + n2, err := n.Copy() + if err != nil { + t.Fatal(err) + } + + nBytes, err := n.Marshal() + if err != nil { + t.Fatal(err) + } + n2Bytes, err := n2.Marshal() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(nBytes, n2Bytes) { + t.Fatal("nodes do not match") + } +} + +type wNode struct { + node *Node +} + +func TestNodeIsValid(t *testing.T) { + wNode := &wNode{} + if wNode.node.IsValid() { + t.Fatal("Node should not be valid (0)") + } + + node := &Node{} + if node.IsValid() { + t.Fatal("Node should not be valid (1)") + } + + node.prevEpoch = 3 + node.thisEpoch = 2 + node.nextEpoch = 3 + if node.IsValid() { + t.Fatal("Node should not be valid (2)") + } + + node.prevEpoch = 1 + node.thisEpoch = 3 + node.nextEpoch = 2 + if node.IsValid() { + t.Fatal("Node should not be valid (3)") + } + + node.prevEpoch = 1 + node.thisEpoch = 2 + node.nextEpoch = 3 + if node.IsValid() { + t.Fatal("Node should not be valid (4)") + } + + node.rawStorage = &RawStorage{} + if !node.IsValid() { + t.Fatal("Node should be valid") + } +} + +func TestNodeIsPreValid(t *testing.T) { + wNode := &wNode{} + if wNode.node.IsPreValid() { + t.Fatal("Node should not be prevalid (0)") + } + + node := &Node{} + if node.IsPreValid() { + t.Fatal("Node should not be prevalid (1)") + } + + node.prevEpoch = 0 + node.thisEpoch = 0 + node.nextEpoch = 0 + if node.IsPreValid() { + t.Fatal("Node should not be prevalid (2)") + } + + node.prevEpoch = 1 + node.thisEpoch = 1 + node.nextEpoch = 0 + if node.IsPreValid() { + t.Fatal("Node should not be prevalid (3)") + } + + node.prevEpoch = 0 + node.thisEpoch = 1 + node.nextEpoch = 1 + if node.IsPreValid() { + t.Fatal("Node should not be prevalid (4)") + } + + node.prevEpoch = 0 + node.thisEpoch = 1 + node.nextEpoch = 0 + if node.IsPreValid() { + t.Fatal("Node should not be prevalid (5)") + } + + node.rawStorage = &RawStorage{} + if !node.IsPreValid() { + t.Fatal("Node should be prevalid") + } +} + +func TestNodeIsHead(t *testing.T) { + node := &Node{} + if node.IsHead() { + t.Fatal("Node invalid; should be false") + } + + node.prevEpoch = 1 + node.thisEpoch = 1 + node.nextEpoch = 1 + node.rawStorage = &RawStorage{} + if !node.IsHead() { + t.Fatal("Should be Head") + } + + node.nextEpoch = 2 + if node.IsHead() { + t.Fatal("Should not be Head") + } +} + +func TestNodeIsTail(t *testing.T) { + node := &Node{} + if node.IsTail() { + t.Fatal("Node invalid; should be false") + } + + node.prevEpoch = 1 + node.thisEpoch = 1 + node.nextEpoch = 1 + node.rawStorage = &RawStorage{} + if !node.IsTail() { + t.Fatal("Should be Tail") + } + + node.thisEpoch = 2 + node.nextEpoch = 2 + if node.IsTail() { + t.Fatal("Should not be Tail") + } +} + +// SetNode with prevNode at Head +func TestNodeSetEpochsGood1(t *testing.T) { + rs := &RawStorage{} + rs.standardParameters() + nodeEpoch := uint32(25519) + node := &Node{ + prevEpoch: 0, + thisEpoch: nodeEpoch, + nextEpoch: 0, + rawStorage: rs, + } + if !node.IsPreValid() { + t.Fatal("node should be preValid") + } + rsNew, err := rs.Copy() + if err != nil { + t.Fatal(err) + } + rsNew.MaxBytes = 1234567890 + first := uint32(1) + last := uint32(257) + prevEpoch := last + prevNode := &Node{ + prevEpoch: first, + thisEpoch: prevEpoch, + nextEpoch: last, + rawStorage: rsNew, + } + if !prevNode.IsValid() { + t.Fatal("prevNode should be Valid") + } + if prevNode.thisEpoch >= node.thisEpoch { + t.Fatal("Should have prevNode.thisEpoch < node.thisEpoch") + } + err = node.SetEpochs(prevNode, nil) + if err != nil { + t.Fatal(err) + } + + // Now need to confirm all epochs are good. + if prevNode.prevEpoch != first { + t.Fatal("prevNode.prevEpoch is incorrect") + } + if prevNode.thisEpoch != prevEpoch { + t.Fatal("prevNode.thisEpoch is incorrect") + } + if prevNode.nextEpoch != nodeEpoch { + t.Fatal("prevNode.nextEpoch is incorrect; it does not point to new nodeEpoch") + } + if node.prevEpoch != prevEpoch { + t.Fatal("prevNode.prevEpoch is incorrect; it does not equal prevEpoch") + } + if node.thisEpoch != nodeEpoch { + t.Fatal("node.thisEpoch is incorrect") + } + if node.nextEpoch != nodeEpoch { + t.Fatal("node.nextEpoch is incorrect; it does not point to self") + } +} + +// SetNode in between prevNode and nextNode +func TestNodeSetEpochsGood2(t *testing.T) { + rs := &RawStorage{} + rs.standardParameters() + nodeEpoch := uint32(25519) + node := &Node{ + prevEpoch: 0, + thisEpoch: nodeEpoch, + nextEpoch: 0, + rawStorage: rs, + } + if !node.IsPreValid() { + t.Fatal("node should be preValid") + } + + rsNew, err := rs.Copy() + if err != nil { + t.Fatal(err) + } + rsNew.MaxBytes = 1234567890 + + first := uint32(1) + last := uint32(1234567890) + prevNode := &Node{ + prevEpoch: first, + thisEpoch: first, + nextEpoch: last, + rawStorage: rsNew, + } + if !prevNode.IsValid() { + t.Fatal("prevNode should be Valid") + } + if node.thisEpoch < prevNode.thisEpoch { + t.Fatal("Should have node.thisEpoch < nextNode.thisEpoch") + } + + nextNode := &Node{ + prevEpoch: first, + thisEpoch: last, + nextEpoch: last, + rawStorage: rsNew, + } + if !nextNode.IsValid() { + t.Fatal("nextNode should be Valid") + } + if node.thisEpoch >= nextNode.thisEpoch { + t.Fatal("Should have node.thisEpoch < nextNode.thisEpoch") + } + + err = node.SetEpochs(prevNode, nextNode) + if err != nil { + t.Fatal(err) + } + + // Now need to confirm all epochs are good. + if prevNode.prevEpoch != first { + t.Fatal("nextNode.prevEpoch is incorrect") + } + if prevNode.thisEpoch != first { + t.Fatal("nextNode.thisEpoch is incorrect") + } + if prevNode.nextEpoch != nodeEpoch { + t.Fatal("nextNode.nextEpoch is incorrect") + } + + if node.prevEpoch != first { + t.Fatal("node.prevEpoch is incorrect") + } + if node.thisEpoch != nodeEpoch { + t.Fatal("node.thisEpoch is incorrect") + } + if node.nextEpoch != last { + t.Fatal("node.nextEpoch is incorrect") + } + + if nextNode.prevEpoch != nodeEpoch { + t.Fatal("nextNode.prevEpoch is incorrect") + } + if nextNode.thisEpoch != last { + t.Fatal("nextNode.thisEpoch is incorrect") + } + if nextNode.nextEpoch != last { + t.Fatal("nextNode.nextEpoch is incorrect") + } +} + +// We should raise an error when having node not PreValid +func TestNodeSetEpochsBad1(t *testing.T) { + node := &Node{} + err := node.SetEpochs(nil, nil) + if err == nil { + t.Fatal("Should have raised error") + } +} + +// We should raise error for prevNode being invalid +func TestNodeSetEpochsBad2(t *testing.T) { + rs := &RawStorage{} + rs.standardParameters() + node := &Node{ + prevEpoch: 0, + thisEpoch: 25519, + nextEpoch: 0, + rawStorage: rs, + } + if !node.IsPreValid() { + t.Fatal("node should be preValid") + } + prevNode := &Node{} + if prevNode.IsValid() { + t.Fatal("prevNode should not be valid") + } + err := node.SetEpochs(prevNode, nil) + if err == nil { + t.Fatal("Should have raised error") + } +} + +// We should raise error for nextNode not nil +func TestNodeSetEpochsBad3(t *testing.T) { + rs := &RawStorage{} + rs.standardParameters() + node := &Node{ + prevEpoch: 0, + thisEpoch: 25519, + nextEpoch: 0, + rawStorage: rs, + } + if !node.IsPreValid() { + t.Fatal("node should be preValid") + } + prevNode := &Node{ + prevEpoch: 1, + thisEpoch: 257, + nextEpoch: 123456789, + rawStorage: rs, + } + if !prevNode.IsValid() { + t.Fatal("prevNode should be Valid") + } + nextNode := &Node{} + if nextNode == nil { + t.Fatal("nextNode should not be nil") + } + err := node.SetEpochs(prevNode, nextNode) + if err == nil { + t.Fatal("Should have raised error") + } +} + +// We should raise error for prevNode.thisEpoch >= node.thisEpoch +func TestNodeSetEpochsBad4(t *testing.T) { + rs := &RawStorage{} + rs.standardParameters() + node := &Node{ + prevEpoch: 0, + thisEpoch: 25519, + nextEpoch: 0, + rawStorage: rs, + } + if !node.IsPreValid() { + t.Fatal("node should be preValid") + } + prevNode := &Node{ + prevEpoch: 1, + thisEpoch: 25519, + nextEpoch: 123456789, + rawStorage: rs, + } + if !prevNode.IsValid() { + t.Fatal("prevNode should be Valid") + } + if prevNode.thisEpoch < node.thisEpoch { + t.Fatal("Should have prevNode.thisEpoch >= node.thisEpoch") + } + err := node.SetEpochs(prevNode, nil) + if err == nil { + t.Fatal("Should have raised error") + } +} + +// We should raise error for prevNode not nil +func TestNodeSetEpochsBad5(t *testing.T) { + rs := &RawStorage{} + rs.standardParameters() + node := &Node{ + prevEpoch: 0, + thisEpoch: 25519, + nextEpoch: 0, + rawStorage: rs, + } + if !node.IsPreValid() { + t.Fatal("node should be preValid") + } + prevNode := &Node{} + if prevNode.IsValid() { + t.Fatal("prevNode should not be valid") + } + if prevNode == nil { + t.Fatal("prevNode should not be nil") + } + nextNode := &Node{} + err := node.SetEpochs(prevNode, nextNode) + if err == nil { + t.Fatal("Should have raised error") + } +} + +// We should raise error for prevNode not nil +func TestNodeSetEpochsBad6(t *testing.T) { + rs := &RawStorage{} + rs.standardParameters() + node := &Node{ + prevEpoch: 0, + thisEpoch: 25519, + nextEpoch: 0, + rawStorage: rs, + } + nextNode := &Node{} + if nextNode.IsValid() { + t.Fatal("nextNode should not be valid") + } + err := node.SetEpochs(nil, nextNode) + if err == nil { + t.Fatal("Should have raised error") + } +} + +// We should raise error for prevNode not nil +func TestNodeSetEpochsBad7(t *testing.T) { + rs := &RawStorage{} + rs.standardParameters() + node := &Node{ + prevEpoch: 0, + thisEpoch: 25519, + nextEpoch: 0, + rawStorage: rs, + } + rsNew, err := rs.Copy() + if err != nil { + t.Fatal(err) + } + rsNew.MaxBytes = 1234567890 + nextNode := &Node{ + prevEpoch: 1, + thisEpoch: 257, + nextEpoch: 123456789, + rawStorage: rsNew, + } + if !nextNode.IsValid() { + t.Fatal("nextNode should not be valid") + } + if node.thisEpoch < nextNode.thisEpoch { + t.Fatal("We should not have node.thisEpoch >= nextNode.thisEpoch to raise error") + } + err = node.SetEpochs(nil, nextNode) + if err == nil { + t.Fatal("Should have raised error") + } +} + +// We should raise error for prevNode not nil +func TestNodeSetEpochsBad8(t *testing.T) { + rs := &RawStorage{} + rs.standardParameters() + node := &Node{ + prevEpoch: 0, + thisEpoch: 25519, + nextEpoch: 0, + rawStorage: rs, + } + rsNew, err := rs.Copy() + if err != nil { + t.Fatal(err) + } + rsNew.MaxBytes = 1234567890 + nextNode := &Node{ + prevEpoch: 1, + thisEpoch: 123456, + nextEpoch: 123456789, + rawStorage: rsNew, + } + if !nextNode.IsValid() { + t.Fatal("nextNode should not be valid") + } + if node.thisEpoch >= nextNode.thisEpoch { + t.Fatal("We should have node.thisEpoch >= nextNode.thisEpoch") + } + if nextNode.IsTail() { + t.Fatal("We should not have nextNode is tail to raise error") + } + err = node.SetEpochs(nil, nextNode) + if err == nil { + t.Fatal("Should have raised error") + } +} diff --git a/dynamics/nodekey.go b/dynamics/nodekey.go new file mode 100644 index 00000000..34e1388f --- /dev/null +++ b/dynamics/nodekey.go @@ -0,0 +1,37 @@ +package dynamics + +import ( + "bytes" + + "github.com/MadBase/MadNet/constants/dbprefix" + "github.com/MadBase/MadNet/utils" +) + +// NodeKey stores the necessary information to load a Node +type NodeKey struct { + prefix []byte + epoch uint32 +} + +func makeNodeKey(epoch uint32) (*NodeKey, error) { + if epoch == 0 { + return nil, ErrZeroEpoch + } + nk := &NodeKey{ + prefix: dbprefix.PrefixStorageNodeKey(), + epoch: epoch, + } + return nk, nil +} + +// Marshal converts NodeKey into the byte slice +func (nk *NodeKey) Marshal() ([]byte, error) { + if !bytes.Equal(nk.prefix, dbprefix.PrefixStorageNodeKey()) { + return nil, ErrInvalidNodeKey + } + epochBytes := utils.MarshalUint32(nk.epoch) + key := []byte{} + key = append(key, nk.prefix...) + key = append(key, epochBytes...) + return key, nil +} diff --git a/dynamics/nodekey_test.go b/dynamics/nodekey_test.go new file mode 100644 index 00000000..c2b5bc28 --- /dev/null +++ b/dynamics/nodekey_test.go @@ -0,0 +1,55 @@ +package dynamics + +import ( + "bytes" + "errors" + "testing" + + "github.com/MadBase/MadNet/constants/dbprefix" + "github.com/MadBase/MadNet/utils" +) + +func TestNodeMakeKeys(t *testing.T) { + epoch := uint32(0) + _, err := makeNodeKey(epoch) + if !errors.Is(err, ErrZeroEpoch) { + t.Fatal("Should have returned error for zero epoch") + } + + nk := &NodeKey{} + _, err = nk.Marshal() + if err == nil { + t.Fatal("Should have raised error") + } + + epoch = 1 + nk, err = makeNodeKey(epoch) + if err != nil { + t.Fatal(err) + } + if nk.epoch != epoch { + t.Fatal("epochs do not match") + } + if !bytes.Equal(nk.prefix, dbprefix.PrefixStorageNodeKey()) { + t.Fatal("prefixes do not match (1)") + } + nkBytes, err := nk.Marshal() + if err != nil { + t.Fatal(err) + } + nkTrue := []byte{} + nkTrue = append(nkTrue, dbprefix.PrefixStorageNodeKey()...) + epochBytes := utils.MarshalUint32(epoch) + nkTrue = append(nkTrue, epochBytes...) + if !bytes.Equal(nkBytes, nkTrue) { + t.Fatal("invalid marshalling") + } + + llk := makeLinkedListKey() + if llk.epoch != 0 { + t.Fatal("epoch should be 0") + } + if !bytes.Equal(nk.prefix, dbprefix.PrefixStorageNodeKey()) { + t.Fatal("prefixes do not match (2)") + } +} diff --git a/dynamics/rawdb.go b/dynamics/rawdb.go new file mode 100644 index 00000000..34b01752 --- /dev/null +++ b/dynamics/rawdb.go @@ -0,0 +1,12 @@ +package dynamics + +import ( + "github.com/dgraph-io/badger/v2" +) + +type rawDataBase interface { + GetValue(txn *badger.Txn, key []byte) ([]byte, error) + SetValue(txn *badger.Txn, key []byte, value []byte) error + Update(func(txn *badger.Txn) error) error + View(func(txn *badger.Txn) error) error +} diff --git a/dynamics/rawstorage.go b/dynamics/rawstorage.go new file mode 100644 index 00000000..4628dcec --- /dev/null +++ b/dynamics/rawstorage.go @@ -0,0 +1,416 @@ +package dynamics + +import ( + "encoding/json" + "math/big" + "time" +) + +// RawStorage is the struct which stores dynamic values; +// these values may change from epoch to epoch +type RawStorage struct { + MaxBytes uint32 `json:"maxBytes,omitempty"` + MaxProposalSize uint32 `json:"maxProposalSize,omitempty"` + ProposalStepTimeout time.Duration `json:"proposalStepTimeout,omitempty"` + PreVoteStepTimeout time.Duration `json:"preVoteStepTimeout,omitempty"` + PreCommitStepTimeout time.Duration `json:"preCommitStepTimeout,omitempty"` + DeadBlockRoundNextRoundTimeout time.Duration `json:"deadBlockRoundNextRoundTimeout,omitempty"` + DownloadTimeout time.Duration `json:"downloadTimeout,omitempty"` + SrvrMsgTimeout time.Duration `json:"srvrMsgTimeout,omitempty"` + MsgTimeout time.Duration `json:"msgTimeout,omitempty"` + + MinTxFee *big.Int `json:"minTxFee,omitempty"` + TxValidVersion uint32 `json:"txValidVersion,omitempty"` + + ValueStoreFee *big.Int `json:"valueStoreFee,omitempty"` + ValueStoreValidVersion uint32 `json:"valueStoreValidVersion,omitempty"` + + AtomicSwapFee *big.Int `json:"atomicSwapFee,omitempty"` + AtomicSwapValidStopEpoch uint32 `json:"atomicSwapValidStopEpoch,omitempty"` + + DataStoreEpochFee *big.Int `json:"dataStoreEpochFee,omitempty"` + DataStoreValidVersion uint32 `json:"dataStoreValidVersion,omitempty"` +} + +// Marshal performs json.Marshal on the RawStorage struct. +func (rs *RawStorage) Marshal() ([]byte, error) { + if rs == nil { + return nil, ErrRawStorageNilPointer + } + return json.Marshal(rs) +} + +// Unmarshal performs json.Unmarshal on the RawStorage struct. +func (rs *RawStorage) Unmarshal(v []byte) error { + if rs == nil { + return ErrRawStorageNilPointer + } + if len(v) == 0 { + return ErrUnmarshalEmpty + } + return json.Unmarshal(v, rs) +} + +// Copy makes a complete copy of RawStorage struct. +func (rs *RawStorage) Copy() (*RawStorage, error) { + rsBytes, err := rs.Marshal() + if err != nil { + return nil, err + } + c := &RawStorage{} + err = c.Unmarshal(rsBytes) + if err != nil { + return nil, err + } + return c, nil +} + +// IsValid returns true if we can successfully make a copy +func (rs *RawStorage) IsValid() bool { + _, err := rs.Copy() + if err != nil { + return false + } + return true +} + +// UpdateValue updates the field with the appropriate value. +func (rs *RawStorage) UpdateValue(update Updater) error { + value := update.Value() + switch update.Type() { + case MaxBytesType: + // uint32 + v, err := stringToUint32(value) + if err != nil { + return err + } + rs.SetMaxBytes(v) + case ProposalStepTimeoutType: + // time.Duration + v, err := stringToTimeDuration(value) + if err != nil { + return err + } + rs.SetProposalStepTimeout(v) + case PreVoteStepTimeoutType: + // time.Duration + v, err := stringToTimeDuration(value) + if err != nil { + return err + } + rs.SetPreVoteStepTimeout(v) + case PreCommitStepTimeoutType: + // time.Duration + v, err := stringToTimeDuration(value) + if err != nil { + return err + } + rs.SetPreCommitStepTimeout(v) + case MsgTimeoutType: + // time.Duration + v, err := stringToTimeDuration(value) + if err != nil { + return err + } + rs.SetMsgTimeout(v) + case MinTxFeeType: + // *big.Int + v, err := stringToBigInt(value) + if err != nil { + return err + } + err = rs.SetMinTxFee(v) + if err != nil { + return err + } + case TxValidVersionType: + // uint32 + v, err := stringToUint32(value) + if err != nil { + return err + } + rs.SetTxValidVersion(v) + case ValueStoreFeeType: + // *big.Int + v, err := stringToBigInt(value) + if err != nil { + return err + } + err = rs.SetValueStoreFee(v) + if err != nil { + return err + } + case ValueStoreValidVersionType: + // uint32 + v, err := stringToUint32(value) + if err != nil { + return err + } + rs.SetValueStoreValidVersion(v) + case AtomicSwapFeeType: + // *big.Int + v, err := stringToBigInt(value) + if err != nil { + return err + } + err = rs.SetAtomicSwapFee(v) + if err != nil { + return err + } + case AtomicSwapValidStopEpochType: + // uint32 + v, err := stringToUint32(value) + if err != nil { + return err + } + rs.SetAtomicSwapValidStopEpoch(v) + case DataStoreEpochFeeType: + // *big.Int + v, err := stringToBigInt(value) + if err != nil { + return err + } + err = rs.SetDataStoreEpochFee(v) + if err != nil { + return err + } + case DataStoreValidVersionType: + // uint32 + v, err := stringToUint32(value) + if err != nil { + return err + } + rs.SetDataStoreValidVersion(v) + default: + return ErrInvalidUpdateValue + } + return nil +} + +// standardParameters initializes RawStorage with the standard (original) +// parameters for the system. +func (rs *RawStorage) standardParameters() { + rs.MaxBytes = maxBytes + rs.MaxProposalSize = maxProposalSize + rs.ProposalStepTimeout = proposalStepTO + rs.PreVoteStepTimeout = preVoteStepTO + rs.PreCommitStepTimeout = preCommitStepTO + rs.DeadBlockRoundNextRoundTimeout = dBRNRTO + rs.DownloadTimeout = downloadTO + rs.SrvrMsgTimeout = srvrMsgTimeout + rs.MsgTimeout = msgTimeout +} + +// GetMaxBytes returns the maximum allowed bytes +func (rs *RawStorage) GetMaxBytes() uint32 { + return rs.MaxBytes +} + +// SetMaxBytes sets the maximum allowed bytes +func (rs *RawStorage) SetMaxBytes(value uint32) { + rs.MaxBytes = value + rs.MaxProposalSize = value +} + +// GetMaxProposalSize returns the maximum size of bytes allowed in a proposal +func (rs *RawStorage) GetMaxProposalSize() uint32 { + return rs.MaxProposalSize +} + +// GetSrvrMsgTimeout returns the time before timeout of server message +func (rs *RawStorage) GetSrvrMsgTimeout() time.Duration { + return rs.SrvrMsgTimeout +} + +// GetMsgTimeout returns the timeout to receive a message +func (rs *RawStorage) GetMsgTimeout() time.Duration { + return rs.MsgTimeout +} + +// SetMsgTimeout sets the timeout to receive a message +func (rs *RawStorage) SetMsgTimeout(value time.Duration) { + rs.MsgTimeout = value + rs.SrvrMsgTimeout = (3 * value) / 4 +} + +// GetProposalStepTimeout returns the proposal step timeout +func (rs *RawStorage) GetProposalStepTimeout() time.Duration { + return rs.ProposalStepTimeout +} + +// SetProposalStepTimeout sets the proposal step timeout +func (rs *RawStorage) SetProposalStepTimeout(value time.Duration) { + rs.ProposalStepTimeout = value + sum := rs.ProposalStepTimeout + rs.PreVoteStepTimeout + rs.PreCommitStepTimeout + rs.DownloadTimeout = sum + rs.DeadBlockRoundNextRoundTimeout = (5 * sum) / 2 +} + +// GetPreVoteStepTimeout returns the prevote step timeout +func (rs *RawStorage) GetPreVoteStepTimeout() time.Duration { + return rs.PreVoteStepTimeout +} + +// SetPreVoteStepTimeout sets the prevote step timeout +func (rs *RawStorage) SetPreVoteStepTimeout(value time.Duration) { + rs.PreVoteStepTimeout = value + sum := rs.ProposalStepTimeout + rs.PreVoteStepTimeout + rs.PreCommitStepTimeout + rs.DownloadTimeout = sum + rs.DeadBlockRoundNextRoundTimeout = (5 * sum) / 2 +} + +// GetPreCommitStepTimeout returns the precommit step timeout +func (rs *RawStorage) GetPreCommitStepTimeout() time.Duration { + return rs.PreCommitStepTimeout +} + +// SetPreCommitStepTimeout sets the precommit step timeout +func (rs *RawStorage) SetPreCommitStepTimeout(value time.Duration) { + rs.PreCommitStepTimeout = value + sum := rs.ProposalStepTimeout + rs.PreVoteStepTimeout + rs.PreCommitStepTimeout + rs.DownloadTimeout = sum + rs.DeadBlockRoundNextRoundTimeout = (5 * sum) / 2 +} + +// GetDeadBlockRoundNextRoundTimeout returns the timeout required before +// moving into the DeadBlockRound +func (rs *RawStorage) GetDeadBlockRoundNextRoundTimeout() time.Duration { + return rs.DeadBlockRoundNextRoundTimeout +} + +// GetDownloadTimeout returns the timeout for downloads +func (rs *RawStorage) GetDownloadTimeout() time.Duration { + return rs.DownloadTimeout +} + +// GetMinTxFee returns the minimun tx burned fee +func (rs *RawStorage) GetMinTxFee() *big.Int { + if rs.MinTxFee == nil { + rs.MinTxFee = new(big.Int) + } + return rs.MinTxFee +} + +// SetMinTxFee sets the minimun tx burned fee +func (rs *RawStorage) SetMinTxFee(value *big.Int) error { + if value == nil { + return ErrInvalidValue + } + if rs.MinTxFee == nil { + rs.MinTxFee = new(big.Int) + } + if value.Sign() < 0 { + return ErrInvalidValue + } + rs.MinTxFee.Set(value) + return nil +} + +// GetTxValidVersion returns the valid version of tx +func (rs *RawStorage) GetTxValidVersion() uint32 { + return rs.TxValidVersion +} + +// SetTxValidVersion sets the minimun tx burned fee +func (rs *RawStorage) SetTxValidVersion(value uint32) { + rs.TxValidVersion = value +} + +// GetDataStoreEpochFee returns the minimun ValueStore burned fee +func (rs *RawStorage) GetDataStoreEpochFee() *big.Int { + if rs.DataStoreEpochFee == nil { + rs.DataStoreEpochFee = new(big.Int) + } + return rs.DataStoreEpochFee +} + +// SetDataStoreEpochFee sets the minimun ValueStore burned fee +func (rs *RawStorage) SetDataStoreEpochFee(value *big.Int) error { + if value == nil { + return ErrInvalidValue + } + if rs.DataStoreEpochFee == nil { + rs.DataStoreEpochFee = new(big.Int) + } + if value.Sign() < 0 { + return ErrInvalidValue + } + rs.DataStoreEpochFee.Set(value) + return nil +} + +// GetValueStoreFee returns the minimun ValueStore burned fee +func (rs *RawStorage) GetValueStoreFee() *big.Int { + if rs.ValueStoreFee == nil { + rs.ValueStoreFee = new(big.Int) + } + return rs.ValueStoreFee +} + +// SetValueStoreFee sets the minimun ValueStore burned fee +func (rs *RawStorage) SetValueStoreFee(value *big.Int) error { + if value == nil { + return ErrInvalidValue + } + if rs.ValueStoreFee == nil { + rs.ValueStoreFee = new(big.Int) + } + if value.Sign() < 0 { + return ErrInvalidValue + } + rs.ValueStoreFee.Set(value) + return nil +} + +// GetValueStoreValidVersion returns the valid version of ValueStore +func (rs *RawStorage) GetValueStoreValidVersion() uint32 { + return rs.ValueStoreValidVersion +} + +// SetValueStoreValidVersion sets the valid version of ValueStore +func (rs *RawStorage) SetValueStoreValidVersion(value uint32) { + rs.ValueStoreValidVersion = value +} + +// GetAtomicSwapFee returns the minimun AtomicSwap burned fee +func (rs *RawStorage) GetAtomicSwapFee() *big.Int { + if rs.AtomicSwapFee == nil { + rs.AtomicSwapFee = new(big.Int) + } + return rs.AtomicSwapFee +} + +// SetAtomicSwapFee sets the minimun AtomicSwap burned fee +func (rs *RawStorage) SetAtomicSwapFee(value *big.Int) error { + if value == nil { + return ErrInvalidValue + } + if rs.AtomicSwapFee == nil { + rs.AtomicSwapFee = new(big.Int) + } + if value.Sign() < 0 { + return ErrInvalidValue + } + rs.AtomicSwapFee.Set(value) + return nil +} + +// GetAtomicSwapValidStopEpoch returns the valid version of AtomicSwap +func (rs *RawStorage) GetAtomicSwapValidStopEpoch() uint32 { + return rs.AtomicSwapValidStopEpoch +} + +// SetAtomicSwapValidStopEpoch sets the valid version of AtomicSwap +func (rs *RawStorage) SetAtomicSwapValidStopEpoch(value uint32) { + rs.AtomicSwapValidStopEpoch = value +} + +// GetDataStoreValidVersion returns the valid version of DataStore +func (rs *RawStorage) GetDataStoreValidVersion() uint32 { + return rs.DataStoreValidVersion +} + +// SetDataStoreValidVersion sets the valid version of AtomicSwap +func (rs *RawStorage) SetDataStoreValidVersion(value uint32) { + rs.DataStoreValidVersion = value +} diff --git a/dynamics/rawstorage_test.go b/dynamics/rawstorage_test.go new file mode 100644 index 00000000..b742de9b --- /dev/null +++ b/dynamics/rawstorage_test.go @@ -0,0 +1,1216 @@ +package dynamics + +import ( + "bytes" + "errors" + "math/big" + "strconv" + "testing" + "time" +) + +func TestRawStorageMarshal(t *testing.T) { + rs := &RawStorage{} + _, err := rs.Marshal() + if err != nil { + t.Fatal(err) + } + s := &Storage{} + _, err = s.rawStorage.Marshal() + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestRawStorageUnmarshal(t *testing.T) { + rs := &RawStorage{} + v, err := rs.Marshal() + if err != nil { + t.Fatal(err) + } + rs2 := &RawStorage{} + err = rs2.Unmarshal(v) + if err != nil { + t.Fatal(err) + } + + v = []byte{} + rs3 := &RawStorage{} + err = rs3.Unmarshal(v) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + s := &Storage{} + err = s.rawStorage.Unmarshal(v) + if err == nil { + t.Fatal("Should have raised error (2)") + } +} + +func TestRawStorageCopy(t *testing.T) { + // Copy empty RawStorage + rs1 := &RawStorage{} + rs2, err := rs1.Copy() + if err != nil { + t.Fatal(err) + } + rs1Bytes, err := rs1.Marshal() + if err != nil { + t.Fatal(err) + } + rs2Bytes, err := rs2.Marshal() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(rs1Bytes, rs2Bytes) { + t.Fatal("Should have equal bytes (1)") + } + + // Copy RawStorage with parameters + rs1.standardParameters() + rs2, err = rs1.Copy() + if err != nil { + t.Fatal(err) + } + rs1Bytes, err = rs1.Marshal() + if err != nil { + t.Fatal(err) + } + rs2Bytes, err = rs2.Marshal() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(rs1Bytes, rs2Bytes) { + t.Fatal("Should have equal bytes (2)") + } + + // Copy RawStorage with some parameters set to zero + rs1.MaxBytes = 0 + rs2, err = rs1.Copy() + if err != nil { + t.Fatal(err) + } + rs1Bytes, err = rs1.Marshal() + if err != nil { + t.Fatal(err) + } + rs2Bytes, err = rs2.Marshal() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(rs1Bytes, rs2Bytes) { + t.Fatal("Should have equal bytes (3)") + } + + s := &Storage{} + _, err = s.rawStorage.Copy() + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestRawStorageStandardParameters(t *testing.T) { + rs := &RawStorage{} + rs.standardParameters() + + retMaxBytes := rs.GetMaxBytes() + if retMaxBytes != maxBytes { + t.Fatal("Should be equal (1)") + } + + retMaxProposalSize := rs.GetMaxProposalSize() + if retMaxProposalSize != maxProposalSize { + t.Fatal("Should be equal (2)") + } + + retSrvrMsgTimeout := rs.GetSrvrMsgTimeout() + if retSrvrMsgTimeout != srvrMsgTimeout { + t.Fatal("Should be equal (3)") + } + + retMsgTimeout := rs.GetMsgTimeout() + if retMsgTimeout != msgTimeout { + t.Fatal("Should be equal (4)") + } + + retProposalTimeout := rs.GetProposalStepTimeout() + if retProposalTimeout != proposalStepTO { + t.Fatal("Should be equal (5)") + } + + retPreVoteTimeout := rs.GetPreVoteStepTimeout() + if retPreVoteTimeout != preVoteStepTO { + t.Fatal("Should be equal (6)") + } + + retPreCommitTimeout := rs.GetPreCommitStepTimeout() + if retPreCommitTimeout != preCommitStepTO { + t.Fatal("Should be equal (7)") + } + + retDBRNRTO := rs.GetDeadBlockRoundNextRoundTimeout() + if retDBRNRTO != dBRNRTO { + t.Fatal("Should be equal (8)") + } + + retDownloadTO := rs.GetDownloadTimeout() + if retDownloadTO != downloadTO { + t.Fatal("Should be equal (9)") + } +} + +func TestRawStorageMaxBytes(t *testing.T) { + rs := &RawStorage{} + retMaxBytes0 := rs.GetMaxBytes() + if retMaxBytes0 != 0 { + t.Fatal("Should be zero") + } + + value := uint32(10000) + rs.SetMaxBytes(value) + retMaxBytes := rs.GetMaxBytes() + if retMaxBytes != value { + t.Fatal("Should be equal (1)") + } + + retMaxProposalSize := rs.GetMaxProposalSize() + if retMaxProposalSize != value { + t.Fatal("Should be equal (2)") + } +} + +func TestRawStorageMaxProposalSize(t *testing.T) { + rs := &RawStorage{} + retMaxProposalSize0 := rs.GetMaxProposalSize() + if retMaxProposalSize0 != 0 { + t.Fatal("Should be zero (2)") + } + + value := uint32(10000) + rs.SetMaxBytes(value) + retMaxProposalSize := rs.GetMaxProposalSize() + if retMaxProposalSize != value { + t.Fatal("Should be equal (2)") + } +} + +func TestRawStorageMsgTimeout(t *testing.T) { + rs := &RawStorage{} + retMsgTimeout0 := rs.GetMsgTimeout() + if retMsgTimeout0 != 0 { + t.Fatal("Should be zero") + } + + value := time.Second + rs.SetMsgTimeout(value) + retMsgTimeout := rs.GetMsgTimeout() + if retMsgTimeout != value { + t.Fatal("Should be equal (1)") + } + + valueSrvrMsg := (3 * value) / 4 + retSrvrMsgTimeout := rs.GetSrvrMsgTimeout() + if retSrvrMsgTimeout != valueSrvrMsg { + t.Fatal("Should be equal (2)") + } +} + +func TestRawStorageSrvrMsgTimeout(t *testing.T) { + rs := &RawStorage{} + retSrvrMsgTimeout0 := rs.GetSrvrMsgTimeout() + if retSrvrMsgTimeout0 != 0 { + t.Fatal("Should be zero") + } + + value := time.Second + rs.SetMsgTimeout(value) + valueSrvrMsg := (3 * value) / 4 + retSrvrMsgTimeout := rs.GetSrvrMsgTimeout() + if retSrvrMsgTimeout != valueSrvrMsg { + t.Fatal("Should be equal") + } +} + +func TestRawStorageConsensusTimeouts(t *testing.T) { + rs := &RawStorage{} + + retPropTOv0 := rs.GetProposalStepTimeout() + if retPropTOv0 != 0 { + t.Fatal("Should be zero (1)") + } + retPreVoteTOv0 := rs.GetPreVoteStepTimeout() + if retPreVoteTOv0 != 0 { + t.Fatal("Should be zero (2)") + } + retPreCommitTOv0 := rs.GetPreCommitStepTimeout() + if retPreCommitTOv0 != 0 { + t.Fatal("Should be zero (3)") + } + retDownloadTOv0 := rs.GetDownloadTimeout() + if retDownloadTOv0 != 0 { + t.Fatal("Should be zero (4)") + } + retDBRNRTOv0 := rs.GetDeadBlockRoundNextRoundTimeout() + if retDBRNRTOv0 != 0 { + t.Fatal("Should be zero (5)") + } + + propValue := 10 * time.Second + rs.SetProposalStepTimeout(propValue) + + retPropTOv1 := rs.GetProposalStepTimeout() + if retPropTOv1 != propValue { + t.Fatal("Should be equal (1)") + } + retPreVoteTOv1 := rs.GetPreVoteStepTimeout() + if retPreVoteTOv1 != 0 { + t.Fatal("Should be zero (6)") + } + retPreCommitTOv1 := rs.GetPreCommitStepTimeout() + if retPreCommitTOv1 != 0 { + t.Fatal("Should be zero (7)") + } + retDownloadTOv1 := rs.GetDownloadTimeout() + if retDownloadTOv1 != propValue { + t.Fatal("Should be equal (2)") + } + retDBRNRTOv1 := rs.GetDeadBlockRoundNextRoundTimeout() + if retDBRNRTOv1 != ((5 * propValue) / 2) { + t.Fatal("Should be equal (3)") + } + + preVoteValue := 20 * time.Second + rs.SetPreVoteStepTimeout(preVoteValue) + + retPropTOv2 := rs.GetProposalStepTimeout() + if retPropTOv2 != propValue { + t.Fatal("Should be equal (4)") + } + retPreVoteTOv2 := rs.GetPreVoteStepTimeout() + if retPreVoteTOv2 != preVoteValue { + t.Fatal("Should be equal (5)") + } + retPreCommitTOv2 := rs.GetPreCommitStepTimeout() + if retPreCommitTOv2 != 0 { + t.Fatal("Should be zero (8)") + } + retDownloadTOv2 := rs.GetDownloadTimeout() + if retDownloadTOv2 != (propValue + preVoteValue) { + t.Fatal("Should be equal (6)") + } + retDBRNRTOv2 := rs.GetDeadBlockRoundNextRoundTimeout() + if retDBRNRTOv2 != ((5 * (propValue + preVoteValue)) / 2) { + t.Fatal("Should be equal (7)") + } + + preCommitValue := 30 * time.Second + rs.SetPreCommitStepTimeout(preCommitValue) + + retPropTOv3 := rs.GetProposalStepTimeout() + if retPropTOv3 != propValue { + t.Fatal("Should be equal (8)") + } + retPreVoteTOv3 := rs.GetPreVoteStepTimeout() + if retPreVoteTOv3 != preVoteValue { + t.Fatal("Should be equal (9)") + } + retPreCommitTOv3 := rs.GetPreCommitStepTimeout() + if retPreCommitTOv3 != preCommitValue { + t.Fatal("Should be equal (10)") + } + retDownloadTOv3 := rs.GetDownloadTimeout() + if retDownloadTOv3 != (propValue + preVoteValue + preCommitValue) { + t.Fatal("Should be equal (11)") + } + retDBRNRTOv3 := rs.GetDeadBlockRoundNextRoundTimeout() + if retDBRNRTOv3 != ((5 * (propValue + preVoteValue + preCommitValue)) / 2) { + t.Fatal("Should be equal (12)") + } +} + +func TestRawStorageMinTxFee(t *testing.T) { + rs1 := &RawStorage{} + + v1 := rs1.GetMinTxFee() + if v1.Sign() != 0 { + t.Fatal("minTxBurnedFee should be 0") + } + + rs2 := &RawStorage{} + err := rs2.SetMinTxFee(nil) + if !errors.Is(err, ErrInvalidValue) { + t.Fatal("Should have raised ErrInvalidValue") + } + + rs3 := &RawStorage{} + value := new(big.Int).SetInt64(-1) + err = rs3.SetMinTxFee(value) + if !errors.Is(err, ErrInvalidValue) { + t.Fatal("Should have raised ErrInvalidValue") + } + + rs4 := &RawStorage{} + value4int := int64(1234567890) + value4 := new(big.Int).SetInt64(value4int) + err = rs4.SetMinTxFee(value4) + if err != nil { + t.Fatal(err) + } + v4 := rs4.GetMinTxFee() + if v4.Cmp(big.NewInt(value4int)) != 0 { + t.Fatal("incorrect minTxBurnedFee value") + } +} + +func TestRawStorageTxValidVersion(t *testing.T) { + rs1 := &RawStorage{} + v1 := rs1.GetTxValidVersion() + if v1 != 0 { + t.Fatal("invalid TxValidVersion") + } + + rs2 := &RawStorage{} + version2 := uint32(7919) + rs2.SetTxValidVersion(version2) + v2 := rs2.GetTxValidVersion() + if v2 != version2 { + t.Fatal("TxValidVersions do not match") + } +} + +func TestRawStorageValueStoreFee(t *testing.T) { + rs1 := &RawStorage{} + + v1 := rs1.GetValueStoreFee() + if v1.Sign() != 0 { + t.Fatal("minValueStoreBurnedFee should be 0") + } + + rs2 := &RawStorage{} + err := rs2.SetValueStoreFee(nil) + if !errors.Is(err, ErrInvalidValue) { + t.Fatal("Should have raised ErrInvalidValue") + } + + rs3 := &RawStorage{} + value := new(big.Int).SetInt64(-1) + err = rs3.SetValueStoreFee(value) + if !errors.Is(err, ErrInvalidValue) { + t.Fatal("Should have raised ErrInvalidValue") + } + + rs4 := &RawStorage{} + value4int := int64(1234567890) + value4 := new(big.Int).SetInt64(value4int) + err = rs4.SetValueStoreFee(value4) + if err != nil { + t.Fatal(err) + } + v4 := rs4.GetValueStoreFee() + if v4.Cmp(big.NewInt(value4int)) != 0 { + t.Fatal("incorrect minValueStoreBurnedFee value") + } +} + +func TestRawStorageValueStoreValidVersion(t *testing.T) { + rs1 := &RawStorage{} + v1 := rs1.GetValueStoreValidVersion() + if v1 != 0 { + t.Fatal("invalid ValueStoreValidVersion") + } + + rs2 := &RawStorage{} + version2 := uint32(7919) + rs2.SetValueStoreValidVersion(version2) + v2 := rs2.GetValueStoreValidVersion() + if v2 != version2 { + t.Fatal("ValueStoreTxValidVersions do not match") + } +} + +func TestRawStorageAtomicSwapFee(t *testing.T) { + rs1 := &RawStorage{} + + v1 := rs1.GetAtomicSwapFee() + if v1.Sign() != 0 { + t.Fatal("atomicSwapFee should be 0") + } + + rs2 := &RawStorage{} + err := rs2.SetAtomicSwapFee(nil) + if !errors.Is(err, ErrInvalidValue) { + t.Fatal("Should have raised ErrInvalidValue") + } + + rs3 := &RawStorage{} + value := new(big.Int).SetInt64(-1) + err = rs3.SetAtomicSwapFee(value) + if !errors.Is(err, ErrInvalidValue) { + t.Fatal("Should have raised ErrInvalidValue") + } + + rs4 := &RawStorage{} + value4int := int64(1234567890) + value4 := new(big.Int).SetInt64(value4int) + err = rs4.SetAtomicSwapFee(value4) + if err != nil { + t.Fatal(err) + } + v4 := rs4.GetAtomicSwapFee() + if v4.Cmp(big.NewInt(value4int)) != 0 { + t.Fatal("incorrect atomicSwapFee value") + } +} + +func TestRawStorageAtomicSwapValidStopEpoch(t *testing.T) { + rs1 := &RawStorage{} + v1 := rs1.GetAtomicSwapValidStopEpoch() + if v1 != 0 { + t.Fatal("invalid AtomicSwapValidStopEpoch") + } + + rs2 := &RawStorage{} + version2 := uint32(7919) + rs2.SetAtomicSwapValidStopEpoch(version2) + v2 := rs2.GetAtomicSwapValidStopEpoch() + if v2 != version2 { + t.Fatal("AtomicSwapValidStopEpochs do not match") + } +} + +func TestRawStorageDataStoreEpochFee(t *testing.T) { + rs1 := &RawStorage{} + + v1 := rs1.GetDataStoreEpochFee() + if v1.Sign() != 0 { + t.Fatal("dataStoreEpochFee should be 0") + } + + rs2 := &RawStorage{} + err := rs2.SetDataStoreEpochFee(nil) + if !errors.Is(err, ErrInvalidValue) { + t.Fatal("Should have raised ErrInvalidValue") + } + + rs3 := &RawStorage{} + value := new(big.Int).SetInt64(-1) + err = rs3.SetDataStoreEpochFee(value) + if !errors.Is(err, ErrInvalidValue) { + t.Fatal("Should have raised ErrInvalidValue") + } + + rs4 := &RawStorage{} + value4int := int64(1234567890) + value4 := new(big.Int).SetInt64(value4int) + err = rs4.SetDataStoreEpochFee(value4) + if err != nil { + t.Fatal(err) + } + v4 := rs4.GetDataStoreEpochFee() + if v4.Cmp(big.NewInt(value4int)) != 0 { + t.Fatal("incorrect dataStoreEpochFee value") + } +} + +func TestRawStorageDataStoreValidVersion(t *testing.T) { + rs1 := &RawStorage{} + v1 := rs1.GetDataStoreValidVersion() + if v1 != 0 { + t.Fatal("invalid DataStoreTxValidVersion") + } + + rs2 := &RawStorage{} + version2 := uint32(7919) + rs2.SetDataStoreValidVersion(version2) + v2 := rs2.GetDataStoreValidVersion() + if v2 != version2 { + t.Fatal("DataStoreTxValidVersions do not match") + } +} + +func TestRawStorageUpdateValueBad(t *testing.T) { + rs := &RawStorage{} + fieldBad := "invalid" + valueBad := "" + update := &Update{ + name: fieldBad, + value: valueBad, + } + err := rs.UpdateValue(update) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestRawStorageUpdateValueMaxBytes(t *testing.T) { + rs := &RawStorage{} + field := "maxBytes" + valueBad1 := "" + epoch := uint32(1) + update, err := NewUpdate(field, valueBad1, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err == nil { + t.Fatal("Should have raised error (1)") + } + retValue := rs.GetMaxBytes() + if retValue != 0 { + t.Fatal("Incorrect MaxBytes (1)") + } + retValue = rs.GetMaxProposalSize() + if retValue != 0 { + t.Fatal("Incorrect MaxProposalSize (1)") + } + + valueBad2 := "-1" + update, err = NewUpdate(field, valueBad2, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err == nil { + t.Fatal("Should have raised error (2)") + } + retValue = rs.GetMaxBytes() + if retValue != 0 { + t.Fatal("Incorrect MaxBytes (2)") + } + retValue = rs.GetMaxProposalSize() + if retValue != 0 { + t.Fatal("Incorrect MaxProposalSize (2)") + } + + valueGood := "1000" + valueTrue64, err := strconv.ParseUint(valueGood, 10, 32) + if err != nil { + t.Fatal(err) + } + valueTrue := uint32(valueTrue64) + update, err = NewUpdate(field, valueGood, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err != nil { + t.Fatal(err) + } + retValue = rs.GetMaxBytes() + if retValue != valueTrue { + t.Fatal("Incorrect MaxBytes (3)") + } + retValue = rs.GetMaxProposalSize() + if retValue != valueTrue { + t.Fatal("Incorrect MaxProposalSize (3)") + } +} + +func TestRawStorageUpdateValueProposalStepTimeout(t *testing.T) { + rs := &RawStorage{} + + retProposalStepTO := rs.GetProposalStepTimeout() + if retProposalStepTO != 0 { + t.Fatal("Incorrect ProposalStepTO (1)") + } + + field := "proposalStepTimeout" + valueBad1 := "" + epoch := uint32(1) + update, err := NewUpdate(field, valueBad1, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + valueBad2 := "-1" + update, err = NewUpdate(field, valueBad2, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if !errors.Is(err, ErrInvalid) { + t.Fatal("Should have raised error (2)") + } + + valueGood := "1000000000" + update, err = NewUpdate(field, valueGood, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err != nil { + t.Fatal(err) + } + + valueTrue64, err := strconv.ParseInt(valueGood, 10, 64) + if err != nil { + t.Fatal(err) + } + propTrue := time.Duration(valueTrue64) + retProposalStepTO = rs.GetProposalStepTimeout() + if retProposalStepTO != propTrue { + t.Fatal("Incorrect ProposalStepTO (2)") + } +} + +func TestRawStorageUpdateValuePreVoteStepTimeout(t *testing.T) { + rs := &RawStorage{} + + retPreVoteStepTO := rs.GetPreVoteStepTimeout() + if retPreVoteStepTO != 0 { + t.Fatal("Incorrect PreVoteStepTO (1)") + } + + field := "preVoteStepTimeout" + valueBad1 := "" + epoch := uint32(1) + update, err := NewUpdate(field, valueBad1, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + valueBad2 := "-1" + update, err = NewUpdate(field, valueBad2, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if !errors.Is(err, ErrInvalid) { + t.Fatal("Should have raised error (2)") + } + + valueGood := "1000000000" + update, err = NewUpdate(field, valueGood, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err != nil { + t.Fatal(err) + } + + valueTrue64, err := strconv.ParseInt(valueGood, 10, 64) + if err != nil { + t.Fatal(err) + } + preVoteTrue := time.Duration(valueTrue64) + retPreVoteStepTO = rs.GetPreVoteStepTimeout() + if retPreVoteStepTO != preVoteTrue { + t.Fatal("Incorrect PreVoteStepTO (2)") + } +} + +func TestRawStorageUpdateValuePreCommitStepTimeout(t *testing.T) { + rs := &RawStorage{} + + retPreCommitStepTO := rs.GetPreCommitStepTimeout() + if retPreCommitStepTO != 0 { + t.Fatal("Incorrect PreCommitStepTO (1)") + } + + field := "preCommitStepTimeout" + valueBad1 := "" + epoch := uint32(1) + update, err := NewUpdate(field, valueBad1, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + valueBad2 := "-1" + update, err = NewUpdate(field, valueBad2, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if !errors.Is(err, ErrInvalid) { + t.Fatal("Should have raised error (2)") + } + + valueGood := "1000000000" + update, err = NewUpdate(field, valueGood, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err != nil { + t.Fatal(err) + } + + valueTrue64, err := strconv.ParseInt(valueGood, 10, 64) + if err != nil { + t.Fatal(err) + } + preCommitTrue := time.Duration(valueTrue64) + retPreCommitStepTO = rs.GetPreCommitStepTimeout() + if retPreCommitStepTO != preCommitTrue { + t.Fatal("Incorrect PreCommitStepTO (2)") + } +} + +func TestRawStorageUpdateValueMsgTimeout(t *testing.T) { + rs := &RawStorage{} + + retMsgTO := rs.GetMsgTimeout() + if retMsgTO != 0 { + t.Fatal("Incorrect MsgTimeout (1)") + } + + field := "msgTimeout" + valueBad1 := "" + epoch := uint32(1) + update, err := NewUpdate(field, valueBad1, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + valueBad2 := "-1" + update, err = NewUpdate(field, valueBad2, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if !errors.Is(err, ErrInvalid) { + t.Fatal("Should have raised error (2)") + } + + valueGood := "1000000000" + update, err = NewUpdate(field, valueGood, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err != nil { + t.Fatal(err) + } + + valueTrue64, err := strconv.ParseInt(valueGood, 10, 64) + if err != nil { + t.Fatal(err) + } + msgTrue := time.Duration(valueTrue64) + retMsgTO = rs.GetMsgTimeout() + if retMsgTO != msgTrue { + t.Fatal("Incorrect MsgTimeout (2)") + } +} + +func TestRawStorageUpdateMinTxBurnedFee(t *testing.T) { + rs := &RawStorage{} + + retMinTxFee := rs.GetMinTxFee() + if retMinTxFee.Sign() != 0 { + t.Fatal("Incorrect MinTxFee (1)") + } + + field := "minTxFee" + valueBad1 := "" + epoch := uint32(1) + update, err := NewUpdate(field, valueBad1, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + valueBad2 := "-1" + update, err = NewUpdate(field, valueBad2, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if !errors.Is(err, ErrInvalid) { + t.Fatal("Should have raised ErrInvalidUpdateValue error") + } + + valueGood := "1000000000" + update, err = NewUpdate(field, valueGood, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err != nil { + t.Fatal(err) + } + + valueTrue, ok := new(big.Int).SetString(valueGood, 10) + if !ok { + t.Fatal("SetString failed") + } + retMinTxFee = rs.GetMinTxFee() + if retMinTxFee.Cmp(valueTrue) != 0 { + t.Fatal("Incorrect MinTxBurnedFee (2)") + } +} + +func TestRawStorageUpdateTxValidVersion(t *testing.T) { + rs := &RawStorage{} + + retTxValidVersion := rs.GetTxValidVersion() + if retTxValidVersion != 0 { + t.Fatal("Incorrect TxValidVersion (1)") + } + + field := "txValidVersion" + valueBad1 := "" + epoch := uint32(1) + update, err := NewUpdate(field, valueBad1, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + valueBad2 := "-1" + update, err = NewUpdate(field, valueBad2, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err == nil { + t.Fatal("Should have raised error (2)") + } + + valueGood := "1000000000" + update, err = NewUpdate(field, valueGood, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err != nil { + t.Fatal(err) + } + + valueTrue64, err := strconv.ParseInt(valueGood, 10, 32) + if err != nil { + t.Fatal(err) + } + txValidTrue := uint32(valueTrue64) + retTxValidVersion = rs.GetTxValidVersion() + if retTxValidVersion != txValidTrue { + t.Fatal("Incorrect TxValidVersion (2)") + } +} + +func TestRawStorageUpdateValueStoreFee(t *testing.T) { + rs := &RawStorage{} + + retMinVSFee := rs.GetValueStoreFee() + if retMinVSFee.Sign() != 0 { + t.Fatal("Incorrect MinValueStoreBurnedFee (1)") + } + + field := "valueStoreFee" + valueBad1 := "" + epoch := uint32(1) + update, err := NewUpdate(field, valueBad1, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + valueBad2 := "-1" + update, err = NewUpdate(field, valueBad2, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if !errors.Is(err, ErrInvalid) { + t.Fatal("Should have raised ErrInvalidUpdateValue error") + } + + valueGood := "1000000000" + update, err = NewUpdate(field, valueGood, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err != nil { + t.Fatal(err) + } + + valueTrue, ok := new(big.Int).SetString(valueGood, 10) + if !ok { + t.Fatal("SetString failed") + } + retMinVSFee = rs.GetValueStoreFee() + if retMinVSFee.Cmp(valueTrue) != 0 { + t.Fatal("Incorrect MinValueStoreBurnedFee (2)") + } +} + +func TestRawStorageUpdateValueStoreValidVersion(t *testing.T) { + rs := &RawStorage{} + + retVSValidVersion := rs.GetValueStoreValidVersion() + if retVSValidVersion != 0 { + t.Fatal("Incorrect ValueStoreValidVersion (1)") + } + + field := "valueStoreValidVersion" + valueBad1 := "" + epoch := uint32(1) + update, err := NewUpdate(field, valueBad1, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + valueBad2 := "-1" + update, err = NewUpdate(field, valueBad2, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err == nil { + t.Fatal("Should have raised error (2)") + } + + valueGood := "1000000000" + update, err = NewUpdate(field, valueGood, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err != nil { + t.Fatal(err) + } + + valueTrue64, err := strconv.ParseInt(valueGood, 10, 32) + if err != nil { + t.Fatal(err) + } + vsTxValidTrue := uint32(valueTrue64) + retVSValidVersion = rs.GetValueStoreValidVersion() + if retVSValidVersion != vsTxValidTrue { + t.Fatal("Incorrect ValueStoreValidVersion (2)") + } +} + +func TestRawStorageUpdateAtomicSwapFee(t *testing.T) { + rs := &RawStorage{} + + retMinASFee := rs.GetAtomicSwapFee() + if retMinASFee.Sign() != 0 { + t.Fatal("Incorrect AtomicSwapFee (1)") + } + + field := "atomicSwapFee" + valueBad1 := "" + epoch := uint32(1) + update, err := NewUpdate(field, valueBad1, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + valueBad2 := "-1" + update, err = NewUpdate(field, valueBad2, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if !errors.Is(err, ErrInvalid) { + t.Fatal("Should have raised ErrInvalid error") + } + + valueGood := "1000000000" + update, err = NewUpdate(field, valueGood, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err != nil { + t.Fatal(err) + } + + valueTrue, ok := new(big.Int).SetString(valueGood, 10) + if !ok { + t.Fatal("SetString failed") + } + retMinASFee = rs.GetAtomicSwapFee() + if retMinASFee.Cmp(valueTrue) != 0 { + t.Fatal("Incorrect AtomicSwapFee (2)") + } +} + +func TestRawStorageUpdateAtomicSwapStopEpoch(t *testing.T) { + rs := &RawStorage{} + + retAtomicSwapStopEpoch := rs.GetAtomicSwapValidStopEpoch() + if retAtomicSwapStopEpoch != 0 { + t.Fatal("Incorrect AtomicSwapValidStopEpoch (1)") + } + + field := "atomicSwapValidStopEpoch" + valueBad1 := "" + epoch := uint32(1) + update, err := NewUpdate(field, valueBad1, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + valueBad2 := "-1" + update, err = NewUpdate(field, valueBad2, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err == nil { + t.Fatal("Should have raised error (2)") + } + + valueGood := "1000000000" + update, err = NewUpdate(field, valueGood, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err != nil { + t.Fatal(err) + } + + valueTrue64, err := strconv.ParseInt(valueGood, 10, 32) + if err != nil { + t.Fatal(err) + } + asTrue := uint32(valueTrue64) + retAtomicSwapStopEpoch = rs.GetAtomicSwapValidStopEpoch() + if retAtomicSwapStopEpoch != asTrue { + t.Fatal("Incorrect AtomicSwapValidStopEpoch (2)") + } +} + +func TestRawStorageUpdateDataStoreEpochFee(t *testing.T) { + rs := &RawStorage{} + + dsEpochFee := rs.GetDataStoreEpochFee() + if dsEpochFee.Sign() != 0 { + t.Fatal("Incorrect DataStoreEpochFee (1)") + } + + field := "dataStoreEpochFee" + valueBad1 := "" + epoch := uint32(1) + update, err := NewUpdate(field, valueBad1, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + valueBad2 := "-1" + update, err = NewUpdate(field, valueBad2, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if !errors.Is(err, ErrInvalid) { + t.Fatal("Should have raised ErrInvalid error") + } + + valueGood := "1000000000" + update, err = NewUpdate(field, valueGood, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err != nil { + t.Fatal(err) + } + + valueTrue, ok := new(big.Int).SetString(valueGood, 10) + if !ok { + t.Fatal("SetString failed") + } + dsEpochFee = rs.GetDataStoreEpochFee() + if dsEpochFee.Cmp(valueTrue) != 0 { + t.Fatal("Incorrect DataStoreEpochFee (2)") + } +} + +func TestRawStorageUpdateDataStoreValidVersion(t *testing.T) { + rs := &RawStorage{} + + retDSTxValidVersion := rs.GetDataStoreValidVersion() + if retDSTxValidVersion != 0 { + t.Fatal("Incorrect DataStoreValidVersion (1)") + } + + field := "dataStoreValidVersion" + valueBad1 := "" + epoch := uint32(1) + update, err := NewUpdate(field, valueBad1, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + valueBad2 := "-1" + update, err = NewUpdate(field, valueBad2, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err == nil { + t.Fatal("Should have raised error (2)") + } + + valueGood := "1000000000" + update, err = NewUpdate(field, valueGood, epoch) + if err != nil { + t.Fatal(err) + } + err = rs.UpdateValue(update) + if err != nil { + t.Fatal(err) + } + + valueTrue64, err := strconv.ParseInt(valueGood, 10, 32) + if err != nil { + t.Fatal(err) + } + dsTxValidTrue := uint32(valueTrue64) + retDSTxValidVersion = rs.GetDataStoreValidVersion() + if retDSTxValidVersion != dsTxValidTrue { + t.Fatal("Incorrect DataStoreTxValidVersion (2)") + } +} diff --git a/dynamics/storage.go b/dynamics/storage.go new file mode 100644 index 00000000..21293641 --- /dev/null +++ b/dynamics/storage.go @@ -0,0 +1,769 @@ +package dynamics + +import ( + "errors" + "math/big" + "sync" + "time" + + "github.com/MadBase/MadNet/utils" + "github.com/dgraph-io/badger/v2" + "github.com/sirupsen/logrus" +) + +// Ensuring interface check +var _ StorageGetter = (*Storage)(nil) + +/* +PROPOSAL ON CHAIN +PROPOSAL GETS VOTED ON +IF PROPOSAL PASSES IT BECOMES ACTIVE IN FUTURE ( EPOCH OF ACTIVE > EPOCH OF FINAL VOTE + 1 ) +WHEN PROPOSAL PASSES AN EVENT IS EMITTED FROM THE GOVERNANCE CONTRACT +THIS EVENT IS OBSERVED BY THE NODES +THE NODES FETCH THE NEW VALUES AND STORE IN THE DATABASE FOR FUTURE USE +ON THE EPOCH BOUNDARY OF NOT ACTIVE TO ACTIVE, THE STORAGE STRUCT MUST BE UPDATED IN MEMORY FROM + THE VALUES STORED IN THE DB +*/ + +// Dynamics contains the list of "constants" which may be changed +// dynamically to reflect protocol updates. +// The point is that these values are essentially constant but may be changed +// in future. + +// StorageGetter is the interface that all Storage structs must match +// to be valid. These will be used to store the constants which may change +// each epoch as governance determines. +type StorageGetter interface { + GetMaxBytes() uint32 + GetMaxProposalSize() uint32 + + GetProposalStepTimeout() time.Duration + GetPreVoteStepTimeout() time.Duration + GetPreCommitStepTimeout() time.Duration + GetDeadBlockRoundNextRoundTimeout() time.Duration + GetDownloadTimeout() time.Duration + GetSrvrMsgTimeout() time.Duration + GetMsgTimeout() time.Duration + + UpdateStorage(*badger.Txn, Updater) error + LoadStorage(*badger.Txn, uint32) error + + GetDataStoreEpochFee() *big.Int + GetDataStoreValidVersion() uint32 + + GetValueStoreFee() *big.Int + GetValueStoreValidVersion() uint32 + + GetAtomicSwapFee() *big.Int + GetAtomicSwapValidStopEpoch() uint32 + + GetMinTxFee() *big.Int + GetTxValidVersion() uint32 +} + +// Storage is the struct which will implement the StorageGetter interface. +type Storage struct { + sync.RWMutex + database *Database + startChan chan struct{} + startOnce sync.Once + rawStorage *RawStorage + logger *logrus.Logger +} + +// checkUpdate confirms the specified update is valid. +func checkUpdate(update Updater) error { + if update.Epoch() == 0 { + return ErrInvalidUpdateValue + } + rs := &RawStorage{} + err := rs.UpdateValue(update) + if err != nil { + return err + } + return nil +} + +// Init initializes the Storage structure. +func (s *Storage) Init(rawDB rawDataBase, logger *logrus.Logger) error { + // initialize channel + s.startChan = make(chan struct{}) + + // initialize database + s.database = &Database{rawDB: rawDB} + + // initialize logger + s.logger = logger + return nil +} + +// Start allows normal operations to begin. This MUST be called after Init +// and can only be called once. +func (s *Storage) Start() { + s.startOnce.Do(func() { + close(s.startChan) + }) + s.rawStorage = &RawStorage{} + s.rawStorage.standardParameters() +} + +// UpdateStorage updates the database to include changes that must be made +// to the database +func (s *Storage) UpdateStorage(txn *badger.Txn, update Updater) error { + select { + case <-s.startChan: + } + s.Lock() + defer s.Unlock() + + err := checkUpdate(update) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + + // Need to add code to check if initialization has been performed; + // that is, is this the first call to UpdateStorage? + _, err = s.database.GetLinkedList(txn) + if err != nil { + if !errors.Is(err, ErrKeyNotPresent) { + utils.DebugTrace(s.logger, err) + return err + } + rs := &RawStorage{} + rs.standardParameters() + node, ll, err := CreateLinkedList(1, rs) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + err = s.database.SetLinkedList(txn, ll) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + err = s.database.SetNode(txn, node) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + } + + err = s.updateStorageValue(txn, update) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + return nil +} + +// updateStorageValue updates the stored RawStorage values. +// +// We start at the Head of LinkedList and find the farthest point +// at which we need to update nodes. +// Once we find the beginning, we iterate forward and update all forward nodes. +func (s *Storage) updateStorageValue(txn *badger.Txn, update Updater) error { + select { + case <-s.startChan: + } + epoch := update.Epoch() + ll, err := s.database.GetLinkedList(txn) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + elu := ll.GetEpochLastUpdated() + iterNode, err := s.database.GetNode(txn, elu) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + + // firstNode denotes where we will begin looping forward + // including the updated value; + // this will not be used when we have a new Head + firstNode := &Node{} + // duplicateNode is used when we will copy values from the previous node + // and then updating it to form a new node + duplicateNode := &Node{} + // newHead denotes if we need to update the Head of the LinkedList; + // that is, if we need to update EpochLastUpdated + newHead := false + // addNode denotes whether we must add a node. + // This will not occur if our update is on another node, + // which could happen if multiple updates occur on one epoch. + addNode := true + + // Loop backwards through the LinkedList to find firstNode and duplicateNode + for { + if epoch >= iterNode.thisEpoch { + // We will use + // + // I = iterNode + // U = updateNode + // F = firstNode + // D = duplicateNode + // H = Head + // + // in our diagrams below. + // + // the update occurs in the current range + if epoch == iterNode.thisEpoch { + // the update occurs on a node; we do not need to add a node + // + // U + // F + // I + // |---|---|---|---|---|---|---|---|---|---|---|---| + firstNode, err = iterNode.Copy() + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + addNode = false + } else { + // epoch > iterNode.thisEpoch + if iterNode.IsHead() { + // we will add a new node further in the future; + // there will be no iteration. + // + // H + // D + // I U + // |---|---|---|---|---|---|---|---|---|---|---|---| + newHead = true + } else { + // we start iterating at the node ahead. + // + // D + // I U F + // |---|---|---|---|---|---|---|---|---|---|---|---| + firstNode, err = s.database.GetNode(txn, iterNode.nextEpoch) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + } + duplicateNode, err = iterNode.Copy() + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + } + break + } + // If we have reached the tail node, then we do not have a node + // for this specific epoch; we raise an error. + if iterNode.IsTail() { + // We cannot add an update before the first node + return ErrInvalidUpdateValue + } + // We proceed backward in the linked list of nodes + prevEpoch := iterNode.prevEpoch + iterNode, err = s.database.GetNode(txn, prevEpoch) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + } + + if addNode { + // We need to add a new node, so we prepare + node := &Node{ + thisEpoch: epoch, + } + // We compute the correct RawStorage value + // We grab the RawStorage from duplicateNode and then update the value. + rs, err := duplicateNode.rawStorage.Copy() + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + err = rs.UpdateValue(update) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + node.rawStorage = rs + // We add the node to the database + err = s.addNode(txn, node) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + } + + if newHead { + // We added a new Head, so we need to store this information + // before we exit. + err = ll.SetEpochLastUpdated(epoch) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + err = s.database.SetLinkedList(txn, ll) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + return nil + } + + // We now iterate forward from firstNode and update all the nodes + // to reflect the new values. + iterNode, err = firstNode.Copy() + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + + for { + err = iterNode.rawStorage.UpdateValue(update) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + err = s.database.SetNode(txn, iterNode) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + if iterNode.IsHead() { + break + } + nextEpoch := iterNode.nextEpoch + iterNode, err = s.database.GetNode(txn, nextEpoch) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + } + + return nil +} + +// LoadStorage updates RawStorage to the correct value defined by the epoch. +// +// We will attempt to load the correct storage struct. +// If we receive ErrKeyNotPresent, then we return RawStorage +// with the standard parameters. +// +// We use Lock and Unlock rather than RLock and RUnlock because +// we modify Storage. +func (s *Storage) LoadStorage(txn *badger.Txn, epoch uint32) error { + select { + case <-s.startChan: + } + s.Lock() + defer s.Unlock() + rs, err := s.loadStorage(txn, epoch) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + s.rawStorage, err = rs.Copy() + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + return nil +} + +// loadStorage wraps loadRawStorage and ensures that a valid RawStorage +// value is returned if possible. +// +// When loadStorage is called by other functions, we should only need +// those functions to have RLock and RUnlock because we do not modify Storage. +func (s *Storage) loadStorage(txn *badger.Txn, epoch uint32) (*RawStorage, error) { + rs, err := s.loadRawStorage(txn, epoch) + if err != nil { + if !errors.Is(err, ErrKeyNotPresent) { + utils.DebugTrace(s.logger, err) + return nil, err + } + rs = &RawStorage{} + rs.standardParameters() + } + return rs, nil +} + +// loadRawStorage looks for the appropriate RawStorage value in the database +// and returns that value. +// +// We start at the most updated epoch and proceed backwards until we arrive +// at the node with +// epoch >= node.thisEpoch +func (s *Storage) loadRawStorage(txn *badger.Txn, epoch uint32) (*RawStorage, error) { + if epoch == 0 { + return nil, ErrZeroEpoch + } + ll, err := s.database.GetLinkedList(txn) + if err != nil { + utils.DebugTrace(s.logger, err) + return nil, err + } + elu := ll.GetEpochLastUpdated() + currentNode, err := s.database.GetNode(txn, elu) + if err != nil { + utils.DebugTrace(s.logger, err) + return nil, err + } + + // Loop backwards through the LinkedList + for { + if epoch >= currentNode.thisEpoch { + rs, err := currentNode.rawStorage.Copy() + if err != nil { + utils.DebugTrace(s.logger, err) + return nil, err + } + return rs, nil + } + // If we have reached the tail node, then we do not have a node + // for this specific epoch; we raise an error. + if currentNode.IsTail() { + utils.DebugTrace(s.logger, ErrInvalid) + return nil, ErrInvalid + } + // We proceed backward in the linked list of nodes + prevEpoch := currentNode.prevEpoch + currentNode, err = s.database.GetNode(txn, prevEpoch) + if err != nil { + utils.DebugTrace(s.logger, err) + return nil, err + } + } +} + +// addNode adds an additional node to the database. +// This node can be added anywhere. +// If the node is added at the head, then LinkedList must be updated +// to reflect this change. +func (s *Storage) addNode(txn *badger.Txn, node *Node) error { + select { + case <-s.startChan: + } + + // Ensure node.rawStorage and node.thisEpoch are valid; + // other parameters should not be set. + // This ensure that node.thisEpoch != 0 + if !node.IsPreValid() { + return ErrInvalid + } + + // Get LinkedList and Head + ll, err := s.database.GetLinkedList(txn) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + elu := ll.GetEpochLastUpdated() + currentNode, err := s.database.GetNode(txn, elu) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + + if node.thisEpoch > currentNode.thisEpoch { + // node to be added is strictly ahead of ELU + err = s.addNodeHead(txn, node, currentNode) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + return nil + } + + if node.thisEpoch == currentNode.thisEpoch { + // Node is already present; raise error + return ErrInvalid + } + + if currentNode.IsTail() { + // The first node is always at epoch 1; + // we cannot add a node before that. + return ErrInvalid + } + + prevNode := &Node{} + + // Loop backwards through the LinkedList + for { + // Get previous node + prevNode, err = s.database.GetNode(txn, currentNode.prevEpoch) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + if prevNode.thisEpoch < node.thisEpoch && node.thisEpoch < currentNode.thisEpoch { + // We need to add node in between prevNode and currentNode + err = s.addNodeSplit(txn, node, prevNode, currentNode) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + return nil + } + if node.thisEpoch == prevNode.thisEpoch { + // Node is already present; raise error + return ErrInvalid + } + if prevNode.IsTail() { + // The first node is always at epoch 1; + // we cannot add a node before that. + return ErrInvalid + } + currentNode, err = prevNode.Copy() + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + } +} + +func (s *Storage) addNodeHead(txn *badger.Txn, node, headNode *Node) error { + if !node.IsPreValid() || !headNode.IsValid() { + return ErrInvalid + } + if !headNode.IsHead() || node.thisEpoch <= headNode.thisEpoch { + // We require headNode to be head and node.thisEpoch < headNode.thisEpoch + return ErrInvalid + } + err := node.SetEpochs(headNode, nil) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + // Store the nodes after changes have been made + err = s.database.SetNode(txn, headNode) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + err = s.database.SetNode(txn, node) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + + // Update EpochLastUpdated + ll, err := s.database.GetLinkedList(txn) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + // We need to update EpochLastUpdated + err = ll.SetEpochLastUpdated(node.thisEpoch) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + err = s.database.SetLinkedList(txn, ll) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + return nil +} + +func (s *Storage) addNodeSplit(txn *badger.Txn, node, prevNode, nextNode *Node) error { + if !node.IsPreValid() || !prevNode.IsValid() || !nextNode.IsValid() { + return ErrInvalid + } + if (prevNode.thisEpoch >= node.thisEpoch) || (node.thisEpoch >= nextNode.thisEpoch) { + return ErrInvalid + } + err := node.SetEpochs(prevNode, nextNode) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + // Store the nodes after changes have been made + err = s.database.SetNode(txn, prevNode) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + err = s.database.SetNode(txn, nextNode) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + err = s.database.SetNode(txn, node) + if err != nil { + utils.DebugTrace(s.logger, err) + return err + } + return nil +} + +// GetMaxBytes returns the maximum allowed bytes +func (s *Storage) GetMaxBytes() uint32 { + select { + case <-s.startChan: + } + s.RLock() + defer s.RUnlock() + return s.rawStorage.GetMaxBytes() +} + +// GetMaxProposalSize returns the maximum size of bytes allowed in a proposal +func (s *Storage) GetMaxProposalSize() uint32 { + select { + case <-s.startChan: + } + s.RLock() + defer s.RUnlock() + return s.rawStorage.GetMaxProposalSize() +} + +// GetSrvrMsgTimeout returns the time before timeout of server message +func (s *Storage) GetSrvrMsgTimeout() time.Duration { + select { + case <-s.startChan: + } + s.RLock() + defer s.RUnlock() + return s.rawStorage.GetSrvrMsgTimeout() +} + +// GetMsgTimeout returns the timeout to receive a message +func (s *Storage) GetMsgTimeout() time.Duration { + select { + case <-s.startChan: + } + s.RLock() + defer s.RUnlock() + return s.rawStorage.GetMsgTimeout() +} + +// GetProposalStepTimeout returns the proposal step timeout +func (s *Storage) GetProposalStepTimeout() time.Duration { + select { + case <-s.startChan: + } + s.RLock() + defer s.RUnlock() + return s.rawStorage.GetProposalStepTimeout() +} + +// GetPreVoteStepTimeout returns the prevote step timeout +func (s *Storage) GetPreVoteStepTimeout() time.Duration { + select { + case <-s.startChan: + } + s.RLock() + defer s.RUnlock() + return s.rawStorage.GetPreVoteStepTimeout() +} + +// GetPreCommitStepTimeout returns the precommit step timeout +func (s *Storage) GetPreCommitStepTimeout() time.Duration { + select { + case <-s.startChan: + } + s.RLock() + defer s.RUnlock() + return s.rawStorage.GetPreCommitStepTimeout() +} + +// GetDeadBlockRoundNextRoundTimeout returns the timeout required before +// moving into the DeadBlockRound +func (s *Storage) GetDeadBlockRoundNextRoundTimeout() time.Duration { + select { + case <-s.startChan: + } + s.RLock() + defer s.RUnlock() + return s.rawStorage.GetDeadBlockRoundNextRoundTimeout() +} + +// GetDownloadTimeout returns the timeout for downloads +func (s *Storage) GetDownloadTimeout() time.Duration { + select { + case <-s.startChan: + } + s.RLock() + defer s.RUnlock() + return s.rawStorage.GetDownloadTimeout() +} + +// GetMinTxFee returns the minimum transaction fee. +func (s *Storage) GetMinTxFee() *big.Int { + select { + case <-s.startChan: + } + s.RLock() + defer s.RUnlock() + return s.rawStorage.GetMinTxFee() +} + +// GetTxValidVersion returns the transaction valid version +func (s *Storage) GetTxValidVersion() uint32 { + select { + case <-s.startChan: + } + s.RLock() + defer s.RUnlock() + return s.rawStorage.GetTxValidVersion() +} + +// GetValueStoreFee returns the transaction fee for ValueStore +func (s *Storage) GetValueStoreFee() *big.Int { + select { + case <-s.startChan: + } + s.RLock() + defer s.RUnlock() + return s.rawStorage.GetValueStoreFee() +} + +// GetValueStoreValidVersion returns the ValueStore valid version +func (s *Storage) GetValueStoreValidVersion() uint32 { + select { + case <-s.startChan: + } + s.RLock() + defer s.RUnlock() + return s.rawStorage.GetValueStoreValidVersion() +} + +// GetAtomicSwapFee returns the transaction fee for AtomicSwap +func (s *Storage) GetAtomicSwapFee() *big.Int { + select { + case <-s.startChan: + } + s.RLock() + defer s.RUnlock() + return s.rawStorage.GetAtomicSwapFee() +} + +// GetAtomicSwapValidStopEpoch returns the last epoch at which AtomicSwap is valid +func (s *Storage) GetAtomicSwapValidStopEpoch() uint32 { + select { + case <-s.startChan: + } + s.RLock() + defer s.RUnlock() + return s.rawStorage.GetAtomicSwapValidStopEpoch() +} + +// GetDataStoreEpochFee returns the DataStore fee per epoch +func (s *Storage) GetDataStoreEpochFee() *big.Int { + select { + case <-s.startChan: + } + s.RLock() + defer s.RUnlock() + return s.rawStorage.GetDataStoreEpochFee() +} + +// GetDataStoreValidVersion returns the DataStore valid version +func (s *Storage) GetDataStoreValidVersion() uint32 { + select { + case <-s.startChan: + } + s.RLock() + defer s.RUnlock() + return s.rawStorage.GetDataStoreValidVersion() +} diff --git a/dynamics/storage_test.go b/dynamics/storage_test.go new file mode 100644 index 00000000..3af09e50 --- /dev/null +++ b/dynamics/storage_test.go @@ -0,0 +1,1473 @@ +package dynamics + +import ( + "bytes" + "errors" + "strconv" + "testing" + "time" +) + +func initializeStorage() *Storage { + storageLogger := newLogger() + mock := &mockRawDB{} + mock.rawDB = make(map[string]string) + + s := &Storage{} + err := s.Init(mock, storageLogger) + if err != nil { + panic(err) + } + s.Start() + return s +} + +func initializeStorageWithFirstNode() *Storage { + s := initializeStorage() + field := "maxBytes" + value := "3000000" + epoch := uint32(1) + update, err := NewUpdate(field, value, epoch) + if err != nil { + panic(err) + } + err = s.UpdateStorage(nil, update) + if err != nil { + panic(err) + } + return s +} + +// Test Storage Init with nothing initialized +func TestStorageInit1(t *testing.T) { + storageLogger := newLogger() + mock := &mockRawDB{} + mock.rawDB = make(map[string]string) + + s := &Storage{} + err := s.Init(mock, storageLogger) + if err != nil { + t.Fatal(err) + } + s.Start() + + rs := &RawStorage{} + rs.standardParameters() + rsBytes, err := rs.Marshal() + if err != nil { + t.Fatal(err) + } + + // Check rawStorage == standardParameters + storageRSBytes, err := s.rawStorage.Marshal() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(rsBytes, storageRSBytes) { + t.Fatal("rawStorage values do not match") + } +} + +func TestStorageStartGood(t *testing.T) { + storageLogger := newLogger() + mock := &mockRawDB{} + mock.rawDB = make(map[string]string) + + s := &Storage{} + err := s.Init(mock, storageLogger) + if err != nil { + t.Fatal(err) + } + s.Start() +} + +// Test ensures we panic when running Start before Init. +// This happens from attempting to close a closed channel. +func TestStorageStartFail(t *testing.T) { + s := &Storage{} + defer func() { + if r := recover(); r == nil { + t.Fatal("Should panic") + } + }() + s.Start() +} + +// Test ensures storage has is initialized to the correct values. +func TestStorageInitialized(t *testing.T) { + s := initializeStorage() + + maxBytesReturned := s.GetMaxBytes() + if maxBytesReturned != maxBytes { + t.Fatal("Incorrect MaxBytes") + } + + maxProposalSizeReturned := s.GetMaxProposalSize() + if maxProposalSizeReturned != maxProposalSize { + t.Fatal("Incorrect MaxProposalSize") + } + + srvrMsgTimeoutReturned := s.GetSrvrMsgTimeout() + if srvrMsgTimeoutReturned != srvrMsgTimeout { + t.Fatal("Incorrect srvrMsgTimeout") + } + + msgTimeoutReturned := s.GetMsgTimeout() + if msgTimeoutReturned != msgTimeout { + t.Fatal("Incorrect msgTimeout") + } + + proposalStepTimeoutReturned := s.GetProposalStepTimeout() + if proposalStepTimeoutReturned != proposalStepTO { + t.Fatal("Incorrect proposalStepTO") + } + + preVoteStepTimeoutReturned := s.GetPreVoteStepTimeout() + if preVoteStepTimeoutReturned != preVoteStepTO { + t.Fatal("Incorrect preVoteStepTO") + } + + preCommitStepTimeoutReturned := s.GetPreCommitStepTimeout() + if preCommitStepTimeoutReturned != preCommitStepTO { + t.Fatal("Incorrect preCommitStepTO") + } + + deadBlockRoundNextRoundTimeoutReturned := s.GetDeadBlockRoundNextRoundTimeout() + if deadBlockRoundNextRoundTimeoutReturned != dBRNRTO { + t.Fatal("Incorrect deadBlockRoundNextRoundTimeout") + } + + downloadTimeoutReturned := s.GetDownloadTimeout() + if downloadTimeoutReturned != downloadTO { + t.Fatal("Incorrect downloadTimeout") + } + + minTxFee := s.GetMinTxFee() + if minTxFee.Sign() != 0 { + t.Fatal("Incorrect minTxFee") + } + + txValidVersion := s.GetTxValidVersion() + if txValidVersion != 0 { + t.Fatal("Incorrect txValidVersion") + } + + vsFee := s.GetValueStoreFee() + if vsFee.Sign() != 0 { + t.Fatal("Incorrect valueStoreFee") + } + + vsValidVersion := s.GetValueStoreValidVersion() + if vsValidVersion != 0 { + t.Fatal("Incorrect valueStoreValidVersion") + } + + asFee := s.GetAtomicSwapFee() + if asFee.Sign() != 0 { + t.Fatal("Incorrect atomicSwapFee") + } + + asStopEpoch := s.GetAtomicSwapValidStopEpoch() + if asStopEpoch != 0 { + t.Fatal("Incorrect atomicSwapValidStopEpoch") + } + + dsEpochFee := s.GetDataStoreEpochFee() + if dsEpochFee.Sign() != 0 { + t.Fatal("Incorrect dataStoreEpochFee") + } + + dsValidVersion := s.GetDataStoreValidVersion() + if dsValidVersion != 0 { + t.Fatal("Incorrect dataStoreValidVersion") + } +} + +func TestStorageCheckUpdate(t *testing.T) { + fieldBad := "invalid" + valueBad := "invalid" + epochGood := uint32(25519) + _, err := NewUpdate(fieldBad, valueBad, epochGood) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + fieldGood := "maxBytes" + valueGood := "1234567890" + update, err := NewUpdate(fieldGood, valueGood, epochGood) + if err != nil { + t.Fatal(err) + } + err = checkUpdate(update) + if err != nil { + t.Fatal(err) + } + + epochBad := uint32(0) + update, err = NewUpdate(fieldGood, valueGood, epochBad) + if err != nil { + t.Fatal(err) + } + err = checkUpdate(update) + if !errors.Is(err, ErrInvalidUpdateValue) { + t.Fatal("Should have raised error (2)") + } + + update = &Update{epoch: 1} + err = checkUpdate(update) + if !errors.Is(err, ErrInvalidUpdateValue) { + t.Fatal("Should have raised error (3)") + } +} + +// Test success of LoadStorage +func TestStorageLoadStorageGood1(t *testing.T) { + s := initializeStorage() + epoch := uint32(25519) + + rsTrue := &RawStorage{} + rsTrue.standardParameters() + rsTrueBytes, err := rsTrue.Marshal() + if err != nil { + t.Fatal(err) + } + + err = s.LoadStorage(nil, epoch) + if err != nil { + t.Fatal(err) + } + rsBytes, err := s.rawStorage.Marshal() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(rsBytes, rsTrueBytes) { + t.Fatal("rawStorage values do not match") + } +} + +// Test success of LoadStorage again +func TestStorageLoadStorageGood2(t *testing.T) { + s := initializeStorageWithFirstNode() + epoch := uint32(25519) + + rsTrue := &RawStorage{} + rsTrue.standardParameters() + rsTrueBytes, err := rsTrue.Marshal() + if err != nil { + t.Fatal(err) + } + + err = s.LoadStorage(nil, epoch) + if err != nil { + t.Fatal(err) + } + rsBytes, err := s.rawStorage.Marshal() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(rsBytes, rsTrueBytes) { + t.Fatal("rawStorage values do not match") + } +} + +// Test failure of LoadStorage +func TestStorageLoadStorageBad1(t *testing.T) { + s := initializeStorage() + // We attempt to load the zero epoch; + // this should raise an error. + err := s.LoadStorage(nil, 0) + if !errors.Is(err, ErrZeroEpoch) { + t.Fatal("Should have raised ErrZeroEpoch") + } +} + +// Test success of loadRawStorage. +func TestStorageLoadRawStorageGood1(t *testing.T) { + s := initializeStorageWithFirstNode() + rsTrue := &RawStorage{} + rsTrue.standardParameters() + rsTrueBytes, err := rsTrue.Marshal() + if err != nil { + t.Fatal(err) + } + + // We attempt to load an epoch from an empty database; + // this should raise an error. + rs, err := s.loadRawStorage(nil, 1) + if err != nil { + t.Fatal(err) + } + rsBytes, err := rs.Marshal() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(rsBytes, rsTrueBytes) { + t.Fatal("RawStorage values do not match") + } +} + +// Test success of loadRawStorage again +func TestStorageLoadRawStorageGood2(t *testing.T) { + s := initializeStorageWithFirstNode() + rsTrue := &RawStorage{} + rsTrue.standardParameters() + rsTrueBytes, err := rsTrue.Marshal() + if err != nil { + t.Fatal(err) + } + + field := "maxBytes" + value := "123456789" + epoch := uint32(257) + update, err := NewUpdate(field, value, epoch) + if err != nil { + t.Fatal(err) + } + err = s.UpdateStorage(nil, update) + if err != nil { + t.Fatal(err) + } + + // We attempt to load an epoch from an empty database; + // this should raise an error. + rs, err := s.loadRawStorage(nil, 1) + if err != nil { + t.Fatal(err) + } + rsBytes, err := rs.Marshal() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(rsBytes, rsTrueBytes) { + t.Fatal("RawStorage values do not match") + } +} + +// Test failure of loadRawStorage. +// We raise an error for attempting to load epoch 0 +func TestStorageLoadRawStorageBad1(t *testing.T) { + s := initializeStorageWithFirstNode() + + // We attempt to load an epoch from an empty database; + // this should raise an error. + _, err := s.loadRawStorage(nil, 0) + if !errors.Is(err, ErrZeroEpoch) { + t.Fatal("Should have raised ErrZeroEpoch") + } +} + +// Test failure of loadRawStorage. +// We raise an error for not having LinkedList present. +func TestStorageLoadRawStorageBad2(t *testing.T) { + storageLogger := newLogger() + database := initializeDB() + s := &Storage{} + s.startChan = make(chan struct{}) + s.database = database + s.logger = storageLogger + s.Start() + + // We attempt to load an epoch from an empty database; + // this should raise an error. + _, err := s.loadRawStorage(nil, 1) + if !errors.Is(err, ErrKeyNotPresent) { + t.Fatal("Should have raised ErrKeyNotPresent") + } +} + +// Test failure of loadRawStorage again. +// It should not be possible to reach this configuration. +func TestStorageLoadStorageBad3(t *testing.T) { + storageLogger := newLogger() + database := initializeDB() + ll := &LinkedList{ + epochLastUpdated: 1, + } + err := database.SetLinkedList(nil, ll) + if err != nil { + t.Fatal(err) + } + + s := &Storage{} + s.startChan = make(chan struct{}) + s.database = database + s.logger = storageLogger + s.Start() + // We attempt to load an epoch from an empty database (without nodes but LinkedList set); + // this should raise an error. + _, err = s.loadRawStorage(nil, 1) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestStorageAddNodeHeadGood(t *testing.T) { + // Initialize storage and have standard node at epoch 1 + s := initializeStorageWithFirstNode() + epoch := uint32(1) + headNode, err := s.database.GetNode(nil, epoch) + if err != nil { + t.Fatal(err) + } + + newEpoch := epoch + 1 + rsNew := &RawStorage{} + rsNew.standardParameters() + rsBytes, err := rsNew.Marshal() + if err != nil { + t.Fatal(err) + } + newMaxBytes := uint32(1234567) + rsNew.SetMaxBytes(newMaxBytes) + node := &Node{ + thisEpoch: newEpoch, + rawStorage: rsNew, + } + if !node.IsPreValid() { + t.Fatal("node should be prevalid") + } + rsNewBytes, err := rsNew.Marshal() + if err != nil { + t.Fatal(err) + } + + err = s.addNodeHead(nil, node, headNode) + if err != nil { + t.Fatal(err) + } + + origNode, err := s.database.GetNode(nil, epoch) + if err != nil { + t.Fatal(err) + } + if origNode.prevEpoch != epoch || origNode.thisEpoch != epoch || origNode.nextEpoch != newEpoch { + t.Fatal("origNode invalid (1)") + } + rsOrigBytes, err := origNode.rawStorage.Marshal() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(rsOrigBytes, rsBytes) { + t.Fatal("origNode invalid (2)") + } + + retNode, err := s.database.GetNode(nil, newEpoch) + if err != nil { + t.Fatal(err) + } + if retNode.prevEpoch != epoch || retNode.thisEpoch != newEpoch || retNode.nextEpoch != newEpoch { + t.Fatal("retNode invalid (1)") + } + retBytes, err := retNode.rawStorage.Marshal() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(retBytes, rsNewBytes) { + t.Fatal("retNode invalid (2)") + } +} + +func TestStorageAddNodeHeadBad1(t *testing.T) { + origEpoch := uint32(1) + s := initializeStorageWithFirstNode() + headNode, err := s.database.GetNode(nil, origEpoch) + if err != nil { + t.Fatal(err) + } + if !headNode.IsValid() { + t.Fatal("headNode should be valid") + } + + node := &Node{} + if node.IsPreValid() { + t.Fatal("node should not be prevalid") + } + + err = s.addNodeHead(nil, node, headNode) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestStorageAddNodeHeadBad2(t *testing.T) { + origEpoch := uint32(1) + s := initializeStorageWithFirstNode() + headNode, err := s.database.GetNode(nil, origEpoch) + if err != nil { + t.Fatal(err) + } + if !headNode.IsValid() { + t.Fatal("headNode should be valid") + } + + rs := &RawStorage{} + node := &Node{ + thisEpoch: 1, + rawStorage: rs, + } + if !node.IsPreValid() { + t.Fatal("node should be prevalid") + } + + err = s.addNodeHead(nil, node, headNode) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestStorageAddNodeSplitGood(t *testing.T) { + first := uint32(1) + s := initializeStorageWithFirstNode() + prevNode, err := s.database.GetNode(nil, first) + if err != nil { + t.Fatal(err) + } + if !prevNode.IsValid() { + t.Fatal("prevNode should be valid") + } + last := uint32(10) + prevNode.nextEpoch = last + err = s.database.SetNode(nil, prevNode) + if err != nil { + t.Fatal(err) + } + + // Set up nextnode + rs := &RawStorage{} + rs.standardParameters() + rsBytes, err := rs.Marshal() + if err != nil { + t.Fatal(err) + } + nextNode := &Node{ + prevEpoch: first, + thisEpoch: last, + nextEpoch: last, + rawStorage: rs, + } + if !nextNode.IsValid() { + t.Fatal("nextNode should be valid") + } + err = s.database.SetNode(nil, nextNode) + if err != nil { + t.Fatal(err) + } + + // Set up node + rsNew, err := rs.Copy() + if err != nil { + t.Fatal(err) + } + rsNew.MaxBytes = 123456 + rsNewBytes, err := rsNew.Marshal() + if err != nil { + t.Fatal(err) + } + newEpoch := uint32(5) + node := &Node{ + thisEpoch: newEpoch, + rawStorage: rsNew, + } + if !node.IsPreValid() { + t.Fatal("node should be preValid") + } + + err = s.addNodeSplit(nil, node, prevNode, nextNode) + if err != nil { + t.Fatal(err) + } + + // Check everything + firstNode, err := s.database.GetNode(nil, first) + if err != nil { + t.Fatal(err) + } + if firstNode.prevEpoch != first || firstNode.thisEpoch != first || firstNode.nextEpoch != newEpoch { + t.Fatal("firstNode invalid (1)") + } + retBytes, err := firstNode.rawStorage.Marshal() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(retBytes, rsBytes) { + t.Fatal("firstNode invalid (2)") + } + + middleNode, err := s.database.GetNode(nil, newEpoch) + if err != nil { + t.Fatal(err) + } + if middleNode.prevEpoch != first || middleNode.thisEpoch != newEpoch || middleNode.nextEpoch != last { + t.Fatal("middleNode invalid (1)") + } + retBytes, err = middleNode.rawStorage.Marshal() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(retBytes, rsNewBytes) { + t.Fatal("middleNode invalid (2)") + } + + lastNode, err := s.database.GetNode(nil, last) + if err != nil { + t.Fatal(err) + } + if lastNode.prevEpoch != newEpoch || lastNode.thisEpoch != last || lastNode.nextEpoch != last { + t.Fatal("lastNode invalid (1)") + } + retBytes, err = lastNode.rawStorage.Marshal() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(retBytes, rsBytes) { + t.Fatal("lastNode invalid (2)") + } +} + +func TestStorageAddNodeSplitBad1(t *testing.T) { + first := uint32(1) + s := initializeStorageWithFirstNode() + prevNode, err := s.database.GetNode(nil, first) + if err != nil { + t.Fatal(err) + } + if !prevNode.IsValid() { + t.Fatal("prevNode should be valid") + } + last := uint32(10) + prevNode.nextEpoch = last + err = s.database.SetNode(nil, prevNode) + if err != nil { + t.Fatal(err) + } + + // Set up nodes + rs := &RawStorage{} + rs.standardParameters() + nextNode := &Node{ + prevEpoch: first, + thisEpoch: last, + nextEpoch: last, + rawStorage: rs, + } + if !nextNode.IsValid() { + t.Fatal("nextNode should be valid") + } + err = s.database.SetNode(nil, nextNode) + if err != nil { + t.Fatal(err) + } + + node := &Node{} + + err = s.addNodeSplit(nil, node, prevNode, nextNode) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestStorageAddNodeSplitBad2(t *testing.T) { + first := uint32(1) + s := initializeStorageWithFirstNode() + prevNode, err := s.database.GetNode(nil, first) + if err != nil { + t.Fatal(err) + } + if !prevNode.IsValid() { + t.Fatal("prevNode should be valid") + } + last := uint32(10) + prevNode.nextEpoch = last + err = s.database.SetNode(nil, prevNode) + if err != nil { + t.Fatal(err) + } + + // Set up nodes + rs := &RawStorage{} + rs.standardParameters() + nextNode := &Node{ + prevEpoch: first, + thisEpoch: last, + nextEpoch: last, + rawStorage: rs, + } + if !nextNode.IsValid() { + t.Fatal("nextNode should be valid") + } + err = s.database.SetNode(nil, nextNode) + if err != nil { + t.Fatal(err) + } + + rsNew, err := rs.Copy() + if err != nil { + t.Fatal(err) + } + rsNew.MaxBytes = 123456 + newEpoch := uint32(100) + node := &Node{ + thisEpoch: newEpoch, + rawStorage: rsNew, + } + if !node.IsPreValid() { + t.Fatal("node should be preValid") + } + + err = s.addNodeSplit(nil, node, prevNode, nextNode) + if err == nil { + t.Fatal("Should have raised error") + } +} + +// Test addNode when adding to Head +func TestStorageAddNodeGood1(t *testing.T) { + origEpoch := uint32(1) + s := initializeStorageWithFirstNode() + rs := &RawStorage{} + rs.standardParameters() + rsStandardBytes, err := rs.Marshal() + if err != nil { + t.Fatal(err) + } + newMaxBytes := uint32(12345) + rs.MaxBytes = newMaxBytes + epoch := uint32(10) + newNode := &Node{ + prevEpoch: 0, + thisEpoch: epoch, + nextEpoch: 0, + rawStorage: rs, + } + err = s.addNode(nil, newNode) + if err != nil { + t.Fatal(err) + } + rsNewBytes, err := rs.Marshal() + if err != nil { + t.Fatal(err) + } + + // Check everything + origNode, err := s.database.GetNode(nil, origEpoch) + if err != nil { + t.Fatal(err) + } + if origNode.prevEpoch != origEpoch { + t.Fatal("origNode.prevEpoch is invalid") + } + if origNode.thisEpoch != origEpoch { + t.Fatal("origNode.thisEpoch is invalid") + } + if origNode.nextEpoch != epoch { + t.Fatal("origNode.nextEpoch is invalid") + } + retRS, err := origNode.rawStorage.Copy() + if err != nil { + t.Fatal(err) + } + retRSBytes, err := retRS.Marshal() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(retRSBytes, rsStandardBytes) { + t.Fatal("invalid RawStorage") + } + + addedNode, err := s.database.GetNode(nil, epoch) + if err != nil { + t.Fatal(err) + } + if addedNode.prevEpoch != origEpoch { + t.Fatal("addedNode.prevEpoch is invalid") + } + if addedNode.thisEpoch != epoch { + t.Fatal("addedNode.thisEpoch is invalid") + } + if addedNode.nextEpoch != epoch { + t.Fatal("addedNode.nextEpoch is invalid") + } + retRS, err = addedNode.rawStorage.Copy() + if err != nil { + t.Fatal(err) + } + retRSBytes, err = retRS.Marshal() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(retRSBytes, rsNewBytes) { + t.Fatal("invalid RawStorage (2)") + } +} + +// Test addNode when adding to Head and then in between +func TestStorageAddNodeGood2(t *testing.T) { + origEpoch := uint32(1) + s := initializeStorageWithFirstNode() + rs := &RawStorage{} + rs.standardParameters() + rsStandardBytes, err := rs.Marshal() + if err != nil { + t.Fatal(err) + } + newEpoch := uint32(100) + newNode := &Node{ + prevEpoch: 0, + thisEpoch: newEpoch, + nextEpoch: 0, + rawStorage: rs, + } + err = s.addNode(nil, newNode) + if err != nil { + t.Fatal(err) + } + + newEpoch2 := uint32(10) + newMaxBytes := uint32(12345689) + rs.SetMaxBytes(newMaxBytes) + newNode2 := &Node{ + prevEpoch: 0, + thisEpoch: newEpoch2, + nextEpoch: 0, + rawStorage: rs, + } + err = s.addNode(nil, newNode2) + if err != nil { + t.Fatal(err) + } + rsNewBytes, err := rs.Marshal() + if err != nil { + t.Fatal(err) + } + + // Check everything + origNode, err := s.database.GetNode(nil, origEpoch) + if err != nil { + t.Fatal(err) + } + if origNode.prevEpoch != origEpoch { + t.Fatal("origNode.prevEpoch is invalid") + } + if origNode.thisEpoch != origEpoch { + t.Fatal("origNode.thisEpoch is invalid") + } + if origNode.nextEpoch != newEpoch2 { + t.Fatal("origNode.nextEpoch is invalid") + } + retRS, err := origNode.rawStorage.Copy() + if err != nil { + t.Fatal(err) + } + retRSBytes, err := retRS.Marshal() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(retRSBytes, rsStandardBytes) { + t.Fatal("invalid RawStorage") + } + + addedNode, err := s.database.GetNode(nil, newEpoch) + if err != nil { + t.Fatal(err) + } + if addedNode.prevEpoch != newEpoch2 { + t.Fatal("addedNode.prevEpoch is invalid") + } + if addedNode.thisEpoch != newEpoch { + t.Fatal("addedNode.thisEpoch is invalid") + } + if addedNode.nextEpoch != newEpoch { + t.Fatal("addedNode.nextEpoch is invalid") + } + retRS, err = addedNode.rawStorage.Copy() + if err != nil { + t.Fatal(err) + } + retRSBytes, err = retRS.Marshal() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(retRSBytes, rsStandardBytes) { + t.Fatal("invalid RawStorage (2)") + } + + addedNode2, err := s.database.GetNode(nil, newEpoch2) + if err != nil { + t.Fatal(err) + } + if addedNode2.prevEpoch != origEpoch { + t.Fatal("addedNode2.prevEpoch is invalid") + } + if addedNode2.thisEpoch != newEpoch2 { + t.Fatal("addedNode2.thisEpoch is invalid") + } + if addedNode2.nextEpoch != newEpoch { + t.Fatal("addedNode2.nextEpoch is invalid") + } + retRS, err = addedNode2.rawStorage.Copy() + if err != nil { + t.Fatal(err) + } + retRSBytes, err = retRS.Marshal() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(retRSBytes, rsNewBytes) { + t.Fatal("invalid RawStorage (3)") + } +} + +func TestStorageAddNodeBad1(t *testing.T) { + s := initializeStorage() + rs := &RawStorage{} + newNode := &Node{ + prevEpoch: 0, + thisEpoch: 0, + nextEpoch: 0, + rawStorage: rs, + } + err := s.addNode(nil, newNode) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestStorageAddNodeBad2(t *testing.T) { + s := initializeStorage() + rs := &RawStorage{} + newNode := &Node{ + prevEpoch: 0, + thisEpoch: 1, + nextEpoch: 0, + rawStorage: rs, + } + err := s.addNode(nil, newNode) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestStorageAddNodeBad3(t *testing.T) { + s := initializeStorageWithFirstNode() + rs := &RawStorage{} + newNode := &Node{ + prevEpoch: 0, + thisEpoch: 1, + nextEpoch: 0, + rawStorage: rs, + } + err := s.addNode(nil, newNode) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestStorageAddNodeBad4(t *testing.T) { + s := initializeStorageWithFirstNode() + rs := &RawStorage{} + newNode := &Node{ + prevEpoch: 0, + thisEpoch: 257, + nextEpoch: 0, + rawStorage: rs, + } + err := s.addNode(nil, newNode) + if err != nil { + t.Fatal(err) + } + + newNode2 := &Node{ + prevEpoch: 0, + thisEpoch: 1, + nextEpoch: 0, + rawStorage: rs, + } + err = s.addNode(nil, newNode2) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestStorageAddNodeBad5(t *testing.T) { + s := initializeStorageWithFirstNode() + rs := &RawStorage{} + newNode := &Node{ + prevEpoch: 0, + thisEpoch: 257, + nextEpoch: 0, + rawStorage: rs, + } + err := s.addNode(nil, newNode) + if err != nil { + t.Fatal(err) + } + + newNode2 := &Node{ + prevEpoch: 0, + thisEpoch: 25519, + nextEpoch: 0, + rawStorage: rs, + } + err = s.addNode(nil, newNode2) + if err != nil { + t.Fatal(err) + } + + newNode3 := &Node{ + prevEpoch: 0, + thisEpoch: 1, + nextEpoch: 0, + rawStorage: rs, + } + err = s.addNode(nil, newNode3) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestStorageAddNodeBad6(t *testing.T) { + s := initializeStorage() + ll := &LinkedList{25519} + err := s.database.SetLinkedList(nil, ll) + if err != nil { + t.Fatal(err) + } + + rs := &RawStorage{} + newNode := &Node{ + prevEpoch: 0, + thisEpoch: 1, + nextEpoch: 0, + rawStorage: rs, + } + err = s.addNode(nil, newNode) + if err == nil { + t.Fatal("Should have raised error") + } +} + +// Test failure of UpdateStorage +func TestStorageUpdateStorageBad(t *testing.T) { + s := initializeStorage() + epoch := uint32(25519) + field := "invalid" + value := "" + update := &Update{ + name: field, + value: value, + epoch: epoch, + } + err := s.UpdateStorage(nil, update) + if err == nil { + t.Fatal("Should have raised error") + } +} + +// Test success of UpdateStorage +func TestStorageUpdateStorageGood1(t *testing.T) { + s := initializeStorage() + epoch := uint32(1) + field := "maxBytes" + value := "123456789" + update, err := NewUpdate(field, value, epoch) + if err != nil { + t.Fatal(err) + } + err = s.UpdateStorage(nil, update) + if err != nil { + t.Fatal(err) + } + + rs := &RawStorage{} + rs.standardParameters() + i, err := strconv.Atoi(value) + if err != nil { + t.Fatal(err) + } + rs.MaxBytes = uint32(i) + rs.MaxProposalSize = uint32(i) + rsBytes, err := rs.Marshal() + if err != nil { + t.Fatal(err) + } + + err = s.LoadStorage(nil, epoch) + if err != nil { + t.Fatal(err) + } + retRS, err := s.rawStorage.Copy() + if err != nil { + t.Fatal(err) + } + retRSBytes, err := retRS.Marshal() + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(rsBytes, retRSBytes) { + t.Log(string(rsBytes)) + t.Log(string(retRSBytes)) + t.Fatal("invalid RawStorage") + } +} + +// Test success of UpdateStorage +func TestStorageUpdateStorageGood2(t *testing.T) { + s := initializeStorage() + epoch := uint32(25519) + field := "maxBytes" + value := "123456789" + update, err := NewUpdate(field, value, epoch) + if err != nil { + t.Fatal(err) + } + err = s.UpdateStorage(nil, update) + if err != nil { + t.Fatal(err) + } + + rs := &RawStorage{} + rs.standardParameters() + i, err := strconv.Atoi(value) + if err != nil { + t.Fatal(err) + } + rs.SetMaxBytes(uint32(i)) + rsBytes, err := rs.Marshal() + if err != nil { + t.Fatal(err) + } + + err = s.LoadStorage(nil, epoch) + if err != nil { + t.Fatal(err) + } + retRS, err := s.rawStorage.Copy() + if err != nil { + t.Fatal(err) + } + retRSBytes, err := retRS.Marshal() + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(rsBytes, retRSBytes) { + t.Log(string(rsBytes)) + t.Log(string(retRSBytes)) + t.Fatal("invalid RawStorage") + } +} + +// Test success of UpdateStorage +func TestStorageUpdateStorageGood3(t *testing.T) { + s := initializeStorageWithFirstNode() + + // Add another epoch in the future + epoch2 := uint32(25519) + rs2 := &RawStorage{} + rs2.standardParameters() + newPropTO := 13 * time.Second + rs2.SetProposalStepTimeout(newPropTO) + node2 := &Node{ + thisEpoch: epoch2, + rawStorage: rs2, + } + err := s.addNode(nil, node2) + if err != nil { + t.Fatal(err) + } + + // Update initial storage value + epoch := uint32(1) + field := "maxBytes" + value := "123456789" + update, err := NewUpdate(field, value, epoch) + if err != nil { + t.Fatal(err) + } + err = s.UpdateStorage(nil, update) + if err != nil { + t.Fatal(err) + } + rsTrue := &RawStorage{} + rsTrue.standardParameters() + newMaxBytesInt, err := strconv.Atoi(value) + if err != nil { + t.Fatal(err) + } + rsTrue.SetMaxBytes(uint32(newMaxBytesInt)) + rsTrueBytes, err := rsTrue.Marshal() + if err != nil { + t.Fatal(err) + } + + // Test Epoch1 + err = s.LoadStorage(nil, epoch) + if err != nil { + t.Fatal(err) + } + retRS, err := s.rawStorage.Copy() + if err != nil { + t.Fatal(err) + } + retRSBytes, err := retRS.Marshal() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(rsTrueBytes, retRSBytes) { + t.Log(string(rsTrueBytes)) + t.Log(string(retRSBytes)) + t.Fatal("invalid RawStorage (1)") + } + + rsTrue2 := &RawStorage{} + rsTrue2.standardParameters() + rsTrue2.SetMaxBytes(uint32(newMaxBytesInt)) + rsTrue2.SetProposalStepTimeout(newPropTO) + rsTrue2Bytes, err := rsTrue2.Marshal() + if err != nil { + t.Fatal(err) + } + + // Test Epoch2 + err = s.LoadStorage(nil, epoch2) + if err != nil { + t.Fatal(err) + } + retRS, err = s.rawStorage.Copy() + if err != nil { + t.Fatal(err) + } + retRSBytes, err = retRS.Marshal() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(rsTrue2Bytes, retRSBytes) { + t.Log(string(rsTrue2Bytes)) + t.Log(string(retRSBytes)) + t.Fatal("invalid RawStorage (2)") + } +} + +// Test failure of UpdateStorageValue +// Attempt to perform invalid update at future epoch +func TestStorageUpdateStorageValueBad1(t *testing.T) { + s := initializeStorage() + epoch := uint32(25519) + field := "invalid" + value := "" + update := &Update{ + name: field, + value: value, + epoch: epoch, + } + err := s.updateStorageValue(nil, update) + if err == nil { + t.Fatal("Should have raised error") + } +} + +// Test failure of UpdateStorageValue +// Attempt to perform invalid update at current epoch +func TestStorageUpdateStorageValueBad2(t *testing.T) { + s := initializeStorage() + epoch := uint32(1) + field := "invalid" + value := "" + update := &Update{ + name: field, + value: value, + epoch: epoch, + } + err := s.updateStorageValue(nil, update) + if err == nil { + t.Fatal("Should have raised error") + } +} + +// Test failure of UpdateStorageValue +// Attempt to perform invalid update at previous epoch +func TestStorageUpdateStorageValueBad3(t *testing.T) { + s := initializeStorage() + epoch := uint32(1) + field := "invalid" + value := "" + update := &Update{ + name: field, + value: value, + epoch: epoch, + } + err := s.updateStorageValue(nil, update) + if err == nil { + t.Fatal("Should have raised error") + } +} + +// Test failure of UpdateStorageValue +// Attempt to perform invalid update in between two valid storage values +func TestStorageUpdateStorageValueBad4(t *testing.T) { + s := initializeStorageWithFirstNode() + rs := &RawStorage{} + rs.standardParameters() + node := &Node{ + thisEpoch: 25519, + rawStorage: rs, + } + + err := s.addNode(nil, node) + if err != nil { + t.Fatal(err) + } + + epoch := uint32(257) + field := "invalid" + value := "" + update := &Update{ + name: field, + value: value, + epoch: epoch, + } + err = s.updateStorageValue(nil, update) + if err == nil { + t.Fatal("Should have raised error") + } +} + +func TestStorageGetMinTxFee(t *testing.T) { + s := initializeStorageWithFirstNode() + txFee := s.GetMinTxFee() + if txFee.Sign() != 0 { + t.Fatal("txFee should be zero") + } + + epoch := uint32(25519) + field := "minTxFee" + value := "123456789" + update, err := NewUpdate(field, value, epoch) + if err != nil { + t.Fatal(err) + } + err = s.UpdateStorage(nil, update) + if err != nil { + t.Fatal(err) + } + err = s.LoadStorage(nil, epoch) + if err != nil { + t.Fatal(err) + } + + valueTrue, err := stringToBigInt(value) + if err != nil { + t.Fatal(err) + } + + txFee = s.GetMinTxFee() + if err != nil { + t.Fatal(err) + } + if txFee.Cmp(valueTrue) != 0 { + t.Fatal("incorrect txFee") + } +} + +func TestStorageGetDataStoreEpochFee(t *testing.T) { + s := initializeStorageWithFirstNode() + dsEpochFee := s.GetDataStoreEpochFee() + if dsEpochFee.Sign() != 0 { + t.Fatal("dsEpochFee should be zero") + } + + epoch := uint32(25519) + field := "dataStoreEpochFee" + value := "123456789" + update, err := NewUpdate(field, value, epoch) + if err != nil { + t.Fatal(err) + } + err = s.UpdateStorage(nil, update) + if err != nil { + t.Fatal(err) + } + err = s.LoadStorage(nil, epoch) + if err != nil { + t.Fatal(err) + } + + valueTrue, err := stringToBigInt(value) + if err != nil { + t.Fatal(err) + } + + dsEpochFee = s.GetDataStoreEpochFee() + if dsEpochFee.Cmp(valueTrue) != 0 { + t.Fatal("incorrect dataStoreEpochFee") + } +} + +func TestStorageGetValueStoreFee(t *testing.T) { + s := initializeStorageWithFirstNode() + vsFee := s.GetValueStoreFee() + if vsFee.Sign() != 0 { + t.Fatal("vsFee should be zero") + } + + epoch := uint32(25519) + field := "valueStoreFee" + value := "123456789" + update, err := NewUpdate(field, value, epoch) + if err != nil { + t.Fatal(err) + } + err = s.UpdateStorage(nil, update) + if err != nil { + t.Fatal(err) + } + err = s.LoadStorage(nil, epoch) + if err != nil { + t.Fatal(err) + } + + valueTrue, err := stringToBigInt(value) + if err != nil { + t.Fatal(err) + } + + vsFee = s.GetValueStoreFee() + if vsFee.Cmp(valueTrue) != 0 { + t.Fatal("incorrect valueStoreFee") + } +} + +func TestStorageGetAtomicSwapFee(t *testing.T) { + s := initializeStorageWithFirstNode() + asFee := s.GetAtomicSwapFee() + if asFee.Sign() != 0 { + t.Fatal("asFee should be zero") + } + + epoch := uint32(25519) + field := "atomicSwapFee" + value := "123456789" + update, err := NewUpdate(field, value, epoch) + if err != nil { + t.Fatal(err) + } + err = s.UpdateStorage(nil, update) + if err != nil { + t.Fatal(err) + } + err = s.LoadStorage(nil, epoch) + if err != nil { + t.Fatal(err) + } + + valueTrue, err := stringToBigInt(value) + if err != nil { + t.Fatal(err) + } + + asFee = s.GetAtomicSwapFee() + if asFee.Cmp(valueTrue) != 0 { + t.Fatal("incorrect atomicSwapFee") + } +} diff --git a/dynamics/update.go b/dynamics/update.go new file mode 100644 index 00000000..8c1e3091 --- /dev/null +++ b/dynamics/update.go @@ -0,0 +1,192 @@ +package dynamics + +import ( + "math/big" + "strconv" + "time" +) + +// Ensuring interface check +var _ Updater = (*Update)(nil) + +// UpdateType specifies which field will be updated +type UpdateType int + +const ( + // MaxBytesType is the UpdateType for updating MaxBytes and MaxProposalSize + MaxBytesType UpdateType = iota + 1 + + // ProposalStepTimeoutType is the UpdateType for updating ProposalStepTimeout; + // this also parameterizes DownloadTimeout and DeadBlockRoundNextRoundTimeout + ProposalStepTimeoutType + + // PreVoteStepTimeoutType is the UpdateType for updating PreVoteStepTimeout; + // this also parameterizes DownloadTimeout and DeadBlockRoundNextRoundTimeout + PreVoteStepTimeoutType + + // PreCommitStepTimeoutType is the UpdateType for updating PreCommitStepTimeout; + // this also parameterizes DownloadTimeout and DeadBlockRoundNextRoundTimeout + PreCommitStepTimeoutType + + // MsgTimeoutType is the UpdateType for updating MsgTimeout; + // this also parameterizes SrvrMsgTimeout + MsgTimeoutType + + // MinTxFeeType is the UpdateType for updating MinTxFee + MinTxFeeType + + // TxValidVersionType is the UpdateType for updating TxValidVersion + TxValidVersionType + + // ValueStoreFeeType is the UpdateType for updating ValueStoreFee + ValueStoreFeeType + + // ValueStoreValidVersionType is the UpdateType for updating ValueStoreValidVersion + ValueStoreValidVersionType + + // AtomicSwapFeeType is the UpdateType for updating AtomicSwapFee + AtomicSwapFeeType + + // AtomicSwapValidStopEpochType is the UpdateType for updating AtomicSwapValidStopEpoch + AtomicSwapValidStopEpochType + + // DataStoreEpochFeeType is the UpdateType for updating DataStoreEpochFee + DataStoreEpochFeeType + + // DataStoreValidVersionType is the UpdateType for updating DataStoreValidVersion + DataStoreValidVersionType +) + +// Updater specifies the interface we use for updating Storage +type Updater interface { + Name() string + Type() UpdateType + Value() string + Epoch() uint32 +} + +// Update is an implementation of Updater interface +type Update struct { + name string + key UpdateType + value string + epoch uint32 +} + +// Name returns the name of Update +func (u *Update) Name() string { + return u.name +} + +// Type returns the type of Update +func (u *Update) Type() UpdateType { + return u.key +} + +// Value returns the value of Update +func (u *Update) Value() string { + return u.value +} + +// Epoch returns the epoch of Update +func (u *Update) Epoch() uint32 { + return u.epoch +} + +// NewUpdate makes a valid valid Update struct which is then used +func NewUpdate(field, value string, epoch uint32) (*Update, error) { + keyType, err := convertFieldToType(field) + if err != nil { + return nil, err + } + u := &Update{ + name: field, + key: keyType, + value: value, + epoch: epoch, + } + return u, nil +} + +// stringToInt32 converts a string into an int32 +func stringToInt32(value string) (int32, error) { + v64, err := strconv.ParseInt(value, 10, 32) + if err != nil { + return 0, err + } + v := int32(v64) + return v, nil +} + +// stringToUint32 converts a string into a uint32 +func stringToUint32(value string) (uint32, error) { + v64, err := strconv.ParseUint(value, 10, 32) + if err != nil { + return 0, err + } + v := uint32(v64) + return v, nil +} + +// stringToTimeDuration converts a string into time.Duration. +// This conversion is particular for our situation, which is why +// we do not allow negative time.Duration values. +func stringToTimeDuration(value string) (time.Duration, error) { + v64, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return 0, err + } + if v64 < 0 { + return 0, ErrInvalid + } + v := time.Duration(v64) + return v, nil +} + +// stringToBigInt converts a string into *big.Int +// This conversion is particular for our situation, which is why +// we do not allow negative big.Int values. +func stringToBigInt(value string) (*big.Int, error) { + v, valid := new(big.Int).SetString(value, 10) + if !valid { + return nil, ErrInvalid + } + if v.Sign() < 0 { + return nil, ErrInvalid + } + return v, nil +} + +// convertFieldToType returns the type associated types from the field +func convertFieldToType(field string) (UpdateType, error) { + switch field { + case "maxBytes": + return MaxBytesType, nil + case "proposalStepTimeout": + return ProposalStepTimeoutType, nil + case "preVoteStepTimeout": + return PreVoteStepTimeoutType, nil + case "preCommitStepTimeout": + return PreCommitStepTimeoutType, nil + case "msgTimeout": + return MsgTimeoutType, nil + case "minTxFee": + return MinTxFeeType, nil + case "txValidVersion": + return TxValidVersionType, nil + case "valueStoreFee": + return ValueStoreFeeType, nil + case "valueStoreValidVersion": + return ValueStoreValidVersionType, nil + case "atomicSwapFee": + return AtomicSwapFeeType, nil + case "atomicSwapValidStopEpoch": + return AtomicSwapValidStopEpochType, nil + case "dataStoreEpochFee": + return DataStoreEpochFeeType, nil + case "dataStoreValidVersion": + return DataStoreValidVersionType, nil + default: + return UpdateType(0), ErrInvalid + } +} diff --git a/dynamics/update_test.go b/dynamics/update_test.go new file mode 100644 index 00000000..cfa02610 --- /dev/null +++ b/dynamics/update_test.go @@ -0,0 +1,378 @@ +package dynamics + +import ( + "math/big" + "testing" + "time" + + "github.com/MadBase/MadNet/constants" +) + +func TestUpdateGet(t *testing.T) { + update := &Update{} + if update.Name() != "" { + t.Fatal("Should have raised error (1)") + } + if update.Type() != UpdateType(0) { + t.Fatal("Should have raised error (2)") + } + if update.Value() != "" { + t.Fatal("Should have raised error (3)") + } + if update.Epoch() != 0 { + t.Fatal("Should have raised error (4)") + } +} + +func TestUpdateNewUpdate(t *testing.T) { + fieldBad := "" + value := "123456789" + epoch := uint32(1) + _, err := NewUpdate(fieldBad, value, epoch) + if err == nil { + t.Fatal("Should have raised error") + } + + fieldGood := "maxBytes" + update, err := NewUpdate(fieldGood, value, epoch) + if err != nil { + t.Fatal(err) + } + if update.Name() != fieldGood { + t.Fatal("invalid update name") + } + if update.Type() != MaxBytesType { + t.Fatal("invalid update type") + } + if update.Value() != value { + t.Fatal("invalid update value") + } + if update.Epoch() != epoch { + t.Fatal("invalid update epoch") + } +} + +func TestStringToInt32(t *testing.T) { + value := "" + _, err := stringToInt32(value) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + value = "0" + v, err := stringToInt32(value) + if err != nil { + t.Fatal(err) + } + if v != 0 { + t.Fatal("invalid conversion (1)") + } + + value = "1" + v, err = stringToInt32(value) + if err != nil { + t.Fatal(err) + } + if v != 1 { + t.Fatal("invalid conversion (2)") + } + + value = "2147483647" // maxInt32 + v, err = stringToInt32(value) + if err != nil { + t.Fatal(err) + } + if v != 2147483647 { + t.Fatal("invalid conversion (3)") + } + + value = "2147483648" + _, err = stringToInt32(value) + if err == nil { + t.Fatal("Should have raised error (2)") + } +} + +func TestStringToUint32(t *testing.T) { + value := "" + _, err := stringToUint32(value) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + value = "0" + v, err := stringToUint32(value) + if err != nil { + t.Fatal(err) + } + if v != 0 { + t.Fatal("invalid conversion (1)") + } + + value = "1" + v, err = stringToUint32(value) + if err != nil { + t.Fatal(err) + } + if v != 1 { + t.Fatal("invalid conversion (2)") + } + + value = "4294967295" + v, err = stringToUint32(value) + if err != nil { + t.Fatal(err) + } + if v != constants.MaxUint32 { + t.Fatal("invalid conversion (3)") + } + + value = "4294967296" + _, err = stringToUint32(value) + if err == nil { + t.Fatal("Should have raised error (2)") + } +} + +func TestStringToTimeDuration(t *testing.T) { + value := "" + _, err := stringToTimeDuration(value) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + value = "0" + v, err := stringToTimeDuration(value) + if err != nil { + t.Fatal(err) + } + if v != 0*time.Second { + t.Fatal("invalid conversion (1)") + } + + value = "1" + v, err = stringToTimeDuration(value) + if err != nil { + t.Fatal(err) + } + if v != 1*time.Nanosecond { + t.Fatal("invalid conversion (2)") + } + + value = "1000" + v, err = stringToTimeDuration(value) + if err != nil { + t.Fatal(err) + } + if v != 1*time.Microsecond { + t.Fatal("invalid conversion (3)") + } + + value = "1000000" + v, err = stringToTimeDuration(value) + if err != nil { + t.Fatal(err) + } + if v != 1*time.Millisecond { + t.Fatal("invalid conversion (4)") + } + + value = "1000000000" + v, err = stringToTimeDuration(value) + if err != nil { + t.Fatal(err) + } + if v != 1*time.Second { + t.Fatal("invalid conversion (5)") + } + + value = "9223372036854775807" + v, err = stringToTimeDuration(value) + if err != nil { + t.Fatal(err) + } + if v != (9223372036*time.Second + 854775807*time.Nanosecond) { + t.Fatal("invalid conversion (6)") + } + + value = "9223372036854775808" + _, err = stringToTimeDuration(value) + if err == nil { + t.Fatal("Should have raised error (2)") + } + + value = "-1" + _, err = stringToTimeDuration(value) + if err == nil { + t.Fatal("Should have raised error (3)") + } +} + +func TestStringToBigInt(t *testing.T) { + value := "" + _, err := stringToBigInt(value) + if err == nil { + t.Fatal("Should have raised error (1)") + } + + vTrue := big.NewInt(0) + value = "0" + v, err := stringToBigInt(value) + if err != nil { + t.Fatal(err) + } + if v.Cmp(vTrue) != 0 { + t.Fatal("invalid conversion (1)") + } + + vTrue = big.NewInt(1) + value = "1" + v, err = stringToBigInt(value) + if err != nil { + t.Fatal(err) + } + if v.Cmp(vTrue) != 0 { + t.Fatal("invalid conversion (2)") + } + + vTrue = big.NewInt(25519) + value = "25519" + v, err = stringToBigInt(value) + if err != nil { + t.Fatal(err) + } + if v.Cmp(vTrue) != 0 { + t.Fatal("invalid conversion (3)") + } + + value = "-1" + _, err = stringToBigInt(value) + if err == nil { + t.Fatal("Should have raised error (3)") + } +} + +func TestConvertFieldToType(t *testing.T) { + field := "" + _, err := convertFieldToType(field) + if err == nil { + t.Fatal("Should have raised error (0)") + } + + field = "maxBytes" + uType, err := convertFieldToType(field) + if err != nil { + t.Fatal(err) + } + if uType != MaxBytesType { + t.Fatal("Incorrect UpdateType (1)") + } + + field = "proposalStepTimeout" + uType, err = convertFieldToType(field) + if err != nil { + t.Fatal(err) + } + if uType != ProposalStepTimeoutType { + t.Fatal("Incorrect UpdateType (2)") + } + + field = "preVoteStepTimeout" + uType, err = convertFieldToType(field) + if err != nil { + t.Fatal(err) + } + if uType != PreVoteStepTimeoutType { + t.Fatal("Incorrect UpdateType (3)") + } + + field = "preCommitStepTimeout" + uType, err = convertFieldToType(field) + if err != nil { + t.Fatal(err) + } + if uType != PreCommitStepTimeoutType { + t.Fatal("Incorrect UpdateType (4)") + } + + field = "msgTimeout" + uType, err = convertFieldToType(field) + if err != nil { + t.Fatal(err) + } + if uType != MsgTimeoutType { + t.Fatal("Incorrect UpdateType (5)") + } + + field = "minTxFee" + uType, err = convertFieldToType(field) + if err != nil { + t.Fatal(err) + } + if uType != MinTxFeeType { + t.Fatal("Incorrect UpdateType (6)") + } + + field = "txValidVersion" + uType, err = convertFieldToType(field) + if err != nil { + t.Fatal(err) + } + if uType != TxValidVersionType { + t.Fatal("Incorrect UpdateType (7)") + } + + field = "valueStoreFee" + uType, err = convertFieldToType(field) + if err != nil { + t.Fatal(err) + } + if uType != ValueStoreFeeType { + t.Fatal("Incorrect UpdateType (8)") + } + + field = "valueStoreValidVersion" + uType, err = convertFieldToType(field) + if err != nil { + t.Fatal(err) + } + if uType != ValueStoreValidVersionType { + t.Fatal("Incorrect UpdateType (9)") + } + + field = "atomicSwapFee" + uType, err = convertFieldToType(field) + if err != nil { + t.Fatal(err) + } + if uType != AtomicSwapFeeType { + t.Fatal("Incorrect UpdateType (10)") + } + + field = "atomicSwapValidStopEpoch" + uType, err = convertFieldToType(field) + if err != nil { + t.Fatal(err) + } + if uType != AtomicSwapValidStopEpochType { + t.Fatal("Incorrect UpdateType (11)") + } + + field = "dataStoreEpochFee" + uType, err = convertFieldToType(field) + if err != nil { + t.Fatal(err) + } + if uType != DataStoreEpochFeeType { + t.Fatal("Incorrect UpdateType (12)") + } + + field = "dataStoreValidVersion" + uType, err = convertFieldToType(field) + if err != nil { + t.Fatal(err) + } + if uType != DataStoreValidVersionType { + t.Fatal("Incorrect UpdateType (13)") + } +} diff --git a/go.mod b/go.mod index ad1c0bdf..9c3a6251 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.15 require ( github.com/MadBase/bridge v0.7.0 github.com/dgraph-io/badger/v2 v2.0.3 - github.com/dgraph-io/ristretto v0.0.2 // indirect github.com/elazarl/go-bindata-assetfs v1.0.1 github.com/emicklei/proto v1.9.0 github.com/ethereum/go-ethereum v1.10.6 diff --git a/go.sum b/go.sum index bc69c93c..98473de6 100644 --- a/go.sum +++ b/go.sum @@ -124,9 +124,8 @@ github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea h1:j4317fAZh7X github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/dgraph-io/badger/v2 v2.0.3 h1:inzdf6VF/NZ+tJ8RwwYMjJMvsOALTHYdozn0qSl6XJI= github.com/dgraph-io/badger/v2 v2.0.3/go.mod h1:3KY8+bsP8wI0OEnQJAKpd4wIJW/Mm32yw2j/9FUVnIM= +github.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3 h1:MQLRM35Pp0yAyBYksjbj1nZI/w6eyRY/mWoM1sFf4kU= github.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= -github.com/dgraph-io/ristretto v0.0.2 h1:a5WaUrDa0qm0YrAAS1tUykT5El3kt62KNZZeMxQn3po= -github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= diff --git a/localrpc/translateAobjsFwd.go b/localrpc/translateAobjsFwd.go index f48d7ac3..8f34702b 100644 --- a/localrpc/translateAobjsFwd.go +++ b/localrpc/translateAobjsFwd.go @@ -7,6 +7,16 @@ import ( to "github.com/MadBase/MadNet/proto" ) +// TODO: ForwardTranslateTXOut and ReverseTranslateTXOut need to be updated +// to include TxFee option in switch case. There is no option at this +// point. +// +// The challenge is that there is nothing in particular that should +// require this information to be fully transmitted, as anyone is +// able to make a related TxFee object. This is because Tx objects +// will eventually be transmitted and will *include* TxFee objects. +// How this is specified as compactly as possible should be investigated. + func ForwardTranslateDataStore(f *from.DataStore) (*to.DataStore, error) { t := &to.DataStore{} if f == nil { @@ -99,6 +109,10 @@ func ForwardTranslateVSPreImage(f *from.VSPreImage) (*to.VSPreImage, error) { if err != nil { return nil, err } + t.Fee, err = f.Fee.MarshalString() + if err != nil { + return nil, err + } return t, nil } @@ -130,6 +144,10 @@ func ForwardTranslateASPreImage(f *from.ASPreImage) (*to.ASPreImage, error) { if err != nil { return nil, err } + t.Fee, err = f.Fee.MarshalString() + if err != nil { + return nil, err + } return t, nil } @@ -291,6 +309,10 @@ func ForwardTranslateDSPreImage(f *from.DSPreImage) (*to.DSPreImage, error) { if err != nil { return nil, err } + t.Fee, err = f.Fee.MarshalString() + if err != nil { + return nil, err + } newIndex, err := ForwardTranslateByte(f.Index) if err != nil { return nil, err diff --git a/localrpc/translateAobjsRev.go b/localrpc/translateAobjsRev.go index 654215fc..7fa34cfa 100644 --- a/localrpc/translateAobjsRev.go +++ b/localrpc/translateAobjsRev.go @@ -86,6 +86,11 @@ func ReverseTranslateVSPreImage(f *from.VSPreImage) (*to.VSPreImage, error) { if err != nil { return nil, err } + t.Fee = &uint256.Uint256{} + err = t.Fee.UnmarshalString(f.Fee) + if err != nil { + return nil, err + } b, err := t.MarshalBinary() if err != nil { return nil, err @@ -120,6 +125,11 @@ func ReverseTranslateASPreImage(f *from.ASPreImage) (*to.ASPreImage, error) { if err != nil { return nil, err } + t.Fee = &uint256.Uint256{} + err = t.Fee.UnmarshalString(f.Fee) + if err != nil { + return nil, err + } b, err := t.MarshalBinary() if err != nil { return nil, err @@ -283,6 +293,11 @@ func ReverseTranslateDSPreImage(f *from.DSPreImage) (*to.DSPreImage, error) { if err != nil { return nil, err } + t.Fee = &uint256.Uint256{} + err = t.Fee.UnmarshalString(f.Fee) + if err != nil { + return nil, err + } newIndex, err := ReverseTranslateByte(f.Index) if err != nil { return nil, err diff --git a/proto/aobjs.pb.go b/proto/aobjs.pb.go index a2f2cc9a..b39eee91 100644 --- a/proto/aobjs.pb.go +++ b/proto/aobjs.pb.go @@ -1,13 +1,12 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 +// protoc-gen-go v1.26.0 // protoc v3.11.2 // source: aobjs.proto package proto import ( - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -21,10 +20,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - // Protobuf message implementation for struct Tx type Tx struct { state protoimpl.MessageState @@ -91,6 +86,7 @@ type TXOut struct { // *TXOut_AtomicSwap // *TXOut_ValueStore // *TXOut_DataStore + // *TXOut_TxFee Utxo isTXOut_Utxo `protobuf_oneof:"utxo"` } @@ -154,6 +150,13 @@ func (x *TXOut) GetDataStore() *DataStore { return nil } +func (x *TXOut) GetTxFee() *TxFee { + if x, ok := x.GetUtxo().(*TXOut_TxFee); ok { + return x.TxFee + } + return nil +} + type isTXOut_Utxo interface { isTXOut_Utxo() } @@ -170,12 +173,18 @@ type TXOut_DataStore struct { DataStore *DataStore `protobuf:"bytes,3,opt,name=DataStore,proto3,oneof"` } +type TXOut_TxFee struct { + TxFee *TxFee `protobuf:"bytes,4,opt,name=TxFee,proto3,oneof"` +} + func (*TXOut_AtomicSwap) isTXOut_Utxo() {} func (*TXOut_ValueStore) isTXOut_Utxo() {} func (*TXOut_DataStore) isTXOut_Utxo() {} +func (*TXOut_TxFee) isTXOut_Utxo() {} + // Protobuf message implementation for struct TXIn type TXIn struct { state protoimpl.MessageState @@ -420,6 +429,7 @@ type ASPreImage struct { IssuedAt uint32 `protobuf:"varint,4,opt,name=IssuedAt,proto3" json:"IssuedAt,omitempty"` Exp uint32 `protobuf:"varint,5,opt,name=Exp,proto3" json:"Exp,omitempty"` Owner string `protobuf:"bytes,6,opt,name=Owner,proto3" json:"Owner,omitempty"` + Fee string `protobuf:"bytes,7,opt,name=Fee,proto3" json:"Fee,omitempty"` } func (x *ASPreImage) Reset() { @@ -496,6 +506,13 @@ func (x *ASPreImage) GetOwner() string { return "" } +func (x *ASPreImage) GetFee() string { + if x != nil { + return x.Fee + } + return "" +} + // Protobuf message implementation for struct ValueStore type ValueStore struct { state protoimpl.MessageState @@ -562,6 +579,7 @@ type VSPreImage struct { Value string `protobuf:"bytes,2,opt,name=Value,proto3" json:"Value,omitempty"` TXOutIdx uint32 `protobuf:"varint,3,opt,name=TXOutIdx,proto3" json:"TXOutIdx,omitempty"` Owner string `protobuf:"bytes,4,opt,name=Owner,proto3" json:"Owner,omitempty"` + Fee string `protobuf:"bytes,5,opt,name=Fee,proto3" json:"Fee,omitempty"` } func (x *VSPreImage) Reset() { @@ -624,6 +642,13 @@ func (x *VSPreImage) GetOwner() string { return "" } +func (x *VSPreImage) GetFee() string { + if x != nil { + return x.Fee + } + return "" +} + // Protobuf message implementation for struct DataStore type DataStore struct { state protoimpl.MessageState @@ -749,6 +774,7 @@ type DSPreImage struct { RawData string `protobuf:"bytes,5,opt,name=RawData,proto3" json:"RawData,omitempty"` TXOutIdx uint32 `protobuf:"varint,6,opt,name=TXOutIdx,proto3" json:"TXOutIdx,omitempty"` Owner string `protobuf:"bytes,7,opt,name=Owner,proto3" json:"Owner,omitempty"` + Fee string `protobuf:"bytes,8,opt,name=Fee,proto3" json:"Fee,omitempty"` } func (x *DSPreImage) Reset() { @@ -832,6 +858,133 @@ func (x *DSPreImage) GetOwner() string { return "" } +func (x *DSPreImage) GetFee() string { + if x != nil { + return x.Fee + } + return "" +} + +// Protobuf message implementation for struct TxFee +type TxFee struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TFPreImage *TFPreImage `protobuf:"bytes,1,opt,name=TFPreImage,proto3" json:"TFPreImage,omitempty"` + TxHash string `protobuf:"bytes,2,opt,name=TxHash,proto3" json:"TxHash,omitempty"` +} + +func (x *TxFee) Reset() { + *x = TxFee{} + if protoimpl.UnsafeEnabled { + mi := &file_aobjs_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TxFee) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TxFee) ProtoMessage() {} + +func (x *TxFee) ProtoReflect() protoreflect.Message { + mi := &file_aobjs_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TxFee.ProtoReflect.Descriptor instead. +func (*TxFee) Descriptor() ([]byte, []int) { + return file_aobjs_proto_rawDescGZIP(), []int{12} +} + +func (x *TxFee) GetTFPreImage() *TFPreImage { + if x != nil { + return x.TFPreImage + } + return nil +} + +func (x *TxFee) GetTxHash() string { + if x != nil { + return x.TxHash + } + return "" +} + +// Protobuf message implementation for struct TFPreImage +type TFPreImage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ChainID uint32 `protobuf:"varint,1,opt,name=ChainID,proto3" json:"ChainID,omitempty"` + TXOutIdx uint32 `protobuf:"varint,2,opt,name=TXOutIdx,proto3" json:"TXOutIdx,omitempty"` + Fee string `protobuf:"bytes,3,opt,name=Fee,proto3" json:"Fee,omitempty"` +} + +func (x *TFPreImage) Reset() { + *x = TFPreImage{} + if protoimpl.UnsafeEnabled { + mi := &file_aobjs_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TFPreImage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TFPreImage) ProtoMessage() {} + +func (x *TFPreImage) ProtoReflect() protoreflect.Message { + mi := &file_aobjs_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TFPreImage.ProtoReflect.Descriptor instead. +func (*TFPreImage) Descriptor() ([]byte, []int) { + return file_aobjs_proto_rawDescGZIP(), []int{13} +} + +func (x *TFPreImage) GetChainID() uint32 { + if x != nil { + return x.ChainID + } + return 0 +} + +func (x *TFPreImage) GetTXOutIdx() uint32 { + if x != nil { + return x.TXOutIdx + } + return 0 +} + +func (x *TFPreImage) GetFee() string { + if x != nil { + return x.Fee + } + return "" +} + var File_aobjs_proto protoreflect.FileDescriptor var file_aobjs_proto_rawDesc = []byte{ @@ -840,7 +993,7 @@ var file_aobjs_proto_rawDesc = []byte{ 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x58, 0x49, 0x6e, 0x52, 0x03, 0x56, 0x69, 0x6e, 0x12, 0x20, 0x0a, 0x04, 0x56, 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x54, 0x58, 0x4f, 0x75, 0x74, 0x52, 0x04, 0x56, 0x6f, 0x75, 0x74, 0x22, 0xab, 0x01, 0x0a, 0x05, + 0x54, 0x58, 0x4f, 0x75, 0x74, 0x52, 0x04, 0x56, 0x6f, 0x75, 0x74, 0x22, 0xd1, 0x01, 0x0a, 0x05, 0x54, 0x58, 0x4f, 0x75, 0x74, 0x12, 0x33, 0x0a, 0x0a, 0x41, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x53, 0x77, 0x61, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x53, 0x77, 0x61, 0x70, 0x48, 0x00, 0x52, 0x0a, @@ -851,78 +1004,96 @@ var file_aobjs_proto_rawDesc = []byte{ 0x30, 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x48, 0x00, 0x52, 0x09, 0x44, 0x61, 0x74, 0x61, 0x53, 0x74, 0x6f, 0x72, - 0x65, 0x42, 0x06, 0x0a, 0x04, 0x75, 0x74, 0x78, 0x6f, 0x22, 0x57, 0x0a, 0x04, 0x54, 0x58, 0x49, - 0x6e, 0x12, 0x31, 0x0a, 0x0a, 0x54, 0x58, 0x49, 0x6e, 0x4c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x58, - 0x49, 0x6e, 0x4c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x52, 0x0a, 0x54, 0x58, 0x49, 0x6e, 0x4c, 0x69, - 0x6e, 0x6b, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x22, 0x5d, 0x0a, 0x0a, 0x54, 0x58, 0x49, 0x6e, 0x4c, 0x69, 0x6e, 0x6b, 0x65, 0x72, - 0x12, 0x37, 0x0a, 0x0c, 0x54, 0x58, 0x49, 0x6e, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, - 0x58, 0x49, 0x6e, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x0c, 0x54, 0x58, 0x49, - 0x6e, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x54, 0x78, 0x48, - 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x54, 0x78, 0x48, 0x61, 0x73, - 0x68, 0x22, 0x76, 0x0a, 0x0c, 0x54, 0x58, 0x49, 0x6e, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, - 0x65, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x07, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0x12, 0x24, 0x0a, 0x0d, 0x43, - 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x54, 0x78, 0x49, 0x64, 0x78, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x0d, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x54, 0x78, 0x49, 0x64, - 0x78, 0x12, 0x26, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x54, 0x78, 0x48, - 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x43, 0x6f, 0x6e, 0x73, 0x75, - 0x6d, 0x65, 0x64, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x22, 0x57, 0x0a, 0x0a, 0x41, 0x74, 0x6f, - 0x6d, 0x69, 0x63, 0x53, 0x77, 0x61, 0x70, 0x12, 0x31, 0x0a, 0x0a, 0x41, 0x53, 0x50, 0x72, 0x65, + 0x65, 0x12, 0x24, 0x0a, 0x05, 0x54, 0x78, 0x46, 0x65, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x78, 0x46, 0x65, 0x65, 0x48, 0x00, + 0x52, 0x05, 0x54, 0x78, 0x46, 0x65, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x75, 0x74, 0x78, 0x6f, 0x22, + 0x57, 0x0a, 0x04, 0x54, 0x58, 0x49, 0x6e, 0x12, 0x31, 0x0a, 0x0a, 0x54, 0x58, 0x49, 0x6e, 0x4c, + 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x58, 0x49, 0x6e, 0x4c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x52, 0x0a, + 0x54, 0x58, 0x49, 0x6e, 0x4c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x53, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x5d, 0x0a, 0x0a, 0x54, 0x58, 0x49, 0x6e, + 0x4c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x12, 0x37, 0x0a, 0x0c, 0x54, 0x58, 0x49, 0x6e, 0x50, 0x72, + 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x58, 0x49, 0x6e, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, + 0x65, 0x52, 0x0c, 0x54, 0x58, 0x49, 0x6e, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, + 0x16, 0x0a, 0x06, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x22, 0x76, 0x0a, 0x0c, 0x54, 0x58, 0x49, 0x6e, 0x50, + 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x68, 0x61, 0x69, 0x6e, + 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x49, + 0x44, 0x12, 0x24, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x54, 0x78, 0x49, + 0x64, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, + 0x65, 0x64, 0x54, 0x78, 0x49, 0x64, 0x78, 0x12, 0x26, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x73, 0x75, + 0x6d, 0x65, 0x64, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x22, + 0x57, 0x0a, 0x0a, 0x41, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x53, 0x77, 0x61, 0x70, 0x12, 0x31, 0x0a, + 0x0a, 0x41, 0x53, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x53, 0x50, 0x72, 0x65, 0x49, + 0x6d, 0x61, 0x67, 0x65, 0x52, 0x0a, 0x41, 0x53, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x22, 0xae, 0x01, 0x0a, 0x0a, 0x41, 0x53, 0x50, + 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x68, 0x61, 0x69, 0x6e, + 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x49, + 0x44, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x54, 0x58, 0x4f, 0x75, 0x74, + 0x49, 0x64, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x54, 0x58, 0x4f, 0x75, 0x74, + 0x49, 0x64, 0x78, 0x12, 0x1a, 0x0a, 0x08, 0x49, 0x73, 0x73, 0x75, 0x65, 0x64, 0x41, 0x74, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x49, 0x73, 0x73, 0x75, 0x65, 0x64, 0x41, 0x74, 0x12, + 0x10, 0x0a, 0x03, 0x45, 0x78, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x45, 0x78, + 0x70, 0x12, 0x14, 0x0a, 0x05, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x46, 0x65, 0x65, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x46, 0x65, 0x65, 0x22, 0x57, 0x0a, 0x0a, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x31, 0x0a, 0x0a, 0x56, 0x53, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x53, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x0a, - 0x41, 0x53, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x54, 0x78, + 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x53, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x0a, + 0x56, 0x53, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x54, 0x78, 0x48, 0x61, - 0x73, 0x68, 0x22, 0x9c, 0x01, 0x0a, 0x0a, 0x41, 0x53, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, + 0x73, 0x68, 0x22, 0x80, 0x01, 0x0a, 0x0a, 0x56, 0x53, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x54, 0x58, 0x4f, 0x75, 0x74, 0x49, 0x64, 0x78, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x08, 0x54, 0x58, 0x4f, 0x75, 0x74, 0x49, 0x64, 0x78, 0x12, 0x1a, 0x0a, - 0x08, 0x49, 0x73, 0x73, 0x75, 0x65, 0x64, 0x41, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x08, 0x49, 0x73, 0x73, 0x75, 0x65, 0x64, 0x41, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x45, 0x78, 0x70, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x45, 0x78, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x4f, - 0x77, 0x6e, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x4f, 0x77, 0x6e, 0x65, - 0x72, 0x22, 0x57, 0x0a, 0x0a, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, - 0x31, 0x0a, 0x0a, 0x56, 0x53, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x53, 0x50, 0x72, - 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x0a, 0x56, 0x53, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, - 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x22, 0x6e, 0x0a, 0x0a, 0x56, 0x53, - 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x68, 0x61, 0x69, - 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x43, 0x68, 0x61, 0x69, 0x6e, - 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x54, 0x58, 0x4f, 0x75, - 0x74, 0x49, 0x64, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x54, 0x58, 0x4f, 0x75, - 0x74, 0x49, 0x64, 0x78, 0x12, 0x14, 0x0a, 0x05, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x22, 0x56, 0x0a, 0x09, 0x44, 0x61, - 0x74, 0x61, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x2b, 0x0a, 0x08, 0x44, 0x53, 0x4c, 0x69, 0x6e, - 0x6b, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x44, 0x53, 0x4c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x52, 0x08, 0x44, 0x53, 0x4c, 0x69, - 0x6e, 0x6b, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x22, 0x55, 0x0a, 0x08, 0x44, 0x53, 0x4c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x12, 0x31, - 0x0a, 0x0a, 0x44, 0x53, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x53, 0x50, 0x72, 0x65, - 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x0a, 0x44, 0x53, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, - 0x65, 0x12, 0x16, 0x0a, 0x06, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x22, 0xbe, 0x01, 0x0a, 0x0a, 0x44, 0x53, - 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x68, 0x61, 0x69, - 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x43, 0x68, 0x61, 0x69, 0x6e, - 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1a, 0x0a, 0x08, 0x49, 0x73, 0x73, 0x75, - 0x65, 0x64, 0x41, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x49, 0x73, 0x73, 0x75, - 0x65, 0x64, 0x41, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x12, 0x18, - 0x0a, 0x07, 0x52, 0x61, 0x77, 0x44, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x52, 0x61, 0x77, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x54, 0x58, 0x4f, 0x75, - 0x74, 0x49, 0x64, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x54, 0x58, 0x4f, 0x75, - 0x74, 0x49, 0x64, 0x78, 0x12, 0x14, 0x0a, 0x05, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x01, 0x28, 0x0d, 0x52, 0x08, 0x54, 0x58, 0x4f, 0x75, 0x74, 0x49, 0x64, 0x78, 0x12, 0x14, 0x0a, + 0x05, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x4f, 0x77, + 0x6e, 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x46, 0x65, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x46, 0x65, 0x65, 0x22, 0x56, 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61, 0x53, 0x74, 0x6f, + 0x72, 0x65, 0x12, 0x2b, 0x0a, 0x08, 0x44, 0x53, 0x4c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x53, 0x4c, + 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x52, 0x08, 0x44, 0x53, 0x4c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x12, + 0x1c, 0x0a, 0x09, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x55, 0x0a, + 0x08, 0x44, 0x53, 0x4c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x12, 0x31, 0x0a, 0x0a, 0x44, 0x53, 0x50, + 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x53, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, + 0x52, 0x0a, 0x44, 0x53, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, + 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x54, 0x78, + 0x48, 0x61, 0x73, 0x68, 0x22, 0xd0, 0x01, 0x0a, 0x0a, 0x44, 0x53, 0x50, 0x72, 0x65, 0x49, 0x6d, + 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x44, 0x12, 0x14, 0x0a, + 0x05, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x49, 0x6e, + 0x64, 0x65, 0x78, 0x12, 0x1a, 0x0a, 0x08, 0x49, 0x73, 0x73, 0x75, 0x65, 0x64, 0x41, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x49, 0x73, 0x73, 0x75, 0x65, 0x64, 0x41, 0x74, 0x12, + 0x18, 0x0a, 0x07, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x52, 0x61, 0x77, + 0x44, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x52, 0x61, 0x77, 0x44, + 0x61, 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x54, 0x58, 0x4f, 0x75, 0x74, 0x49, 0x64, 0x78, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x54, 0x58, 0x4f, 0x75, 0x74, 0x49, 0x64, 0x78, 0x12, + 0x14, 0x0a, 0x05, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x46, 0x65, 0x65, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x46, 0x65, 0x65, 0x22, 0x52, 0x0a, 0x05, 0x54, 0x78, 0x46, 0x65, 0x65, + 0x12, 0x31, 0x0a, 0x0a, 0x54, 0x46, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x46, 0x50, + 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x0a, 0x54, 0x46, 0x50, 0x72, 0x65, 0x49, 0x6d, + 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x22, 0x54, 0x0a, 0x0a, 0x54, + 0x46, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x68, 0x61, + 0x69, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x43, 0x68, 0x61, 0x69, + 0x6e, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x54, 0x58, 0x4f, 0x75, 0x74, 0x49, 0x64, 0x78, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x54, 0x58, 0x4f, 0x75, 0x74, 0x49, 0x64, 0x78, 0x12, + 0x10, 0x0a, 0x03, 0x46, 0x65, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x46, 0x65, + 0x65, 0x42, 0x21, 0x5a, 0x1f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x4d, 0x61, 0x64, 0x42, 0x61, 0x73, 0x65, 0x2f, 0x4d, 0x61, 0x64, 0x4e, 0x65, 0x74, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -937,7 +1108,7 @@ func file_aobjs_proto_rawDescGZIP() []byte { return file_aobjs_proto_rawDescData } -var file_aobjs_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_aobjs_proto_msgTypes = make([]protoimpl.MessageInfo, 14) var file_aobjs_proto_goTypes = []interface{}{ (*Tx)(nil), // 0: proto.Tx (*TXOut)(nil), // 1: proto.TXOut @@ -951,6 +1122,8 @@ var file_aobjs_proto_goTypes = []interface{}{ (*DataStore)(nil), // 9: proto.DataStore (*DSLinker)(nil), // 10: proto.DSLinker (*DSPreImage)(nil), // 11: proto.DSPreImage + (*TxFee)(nil), // 12: proto.TxFee + (*TFPreImage)(nil), // 13: proto.TFPreImage } var file_aobjs_proto_depIdxs = []int32{ 2, // 0: proto.Tx.Vin:type_name -> proto.TXIn @@ -958,17 +1131,19 @@ var file_aobjs_proto_depIdxs = []int32{ 5, // 2: proto.TXOut.AtomicSwap:type_name -> proto.AtomicSwap 7, // 3: proto.TXOut.ValueStore:type_name -> proto.ValueStore 9, // 4: proto.TXOut.DataStore:type_name -> proto.DataStore - 3, // 5: proto.TXIn.TXInLinker:type_name -> proto.TXInLinker - 4, // 6: proto.TXInLinker.TXInPreImage:type_name -> proto.TXInPreImage - 6, // 7: proto.AtomicSwap.ASPreImage:type_name -> proto.ASPreImage - 8, // 8: proto.ValueStore.VSPreImage:type_name -> proto.VSPreImage - 10, // 9: proto.DataStore.DSLinker:type_name -> proto.DSLinker - 11, // 10: proto.DSLinker.DSPreImage:type_name -> proto.DSPreImage - 11, // [11:11] is the sub-list for method output_type - 11, // [11:11] is the sub-list for method input_type - 11, // [11:11] is the sub-list for extension type_name - 11, // [11:11] is the sub-list for extension extendee - 0, // [0:11] is the sub-list for field type_name + 12, // 5: proto.TXOut.TxFee:type_name -> proto.TxFee + 3, // 6: proto.TXIn.TXInLinker:type_name -> proto.TXInLinker + 4, // 7: proto.TXInLinker.TXInPreImage:type_name -> proto.TXInPreImage + 6, // 8: proto.AtomicSwap.ASPreImage:type_name -> proto.ASPreImage + 8, // 9: proto.ValueStore.VSPreImage:type_name -> proto.VSPreImage + 10, // 10: proto.DataStore.DSLinker:type_name -> proto.DSLinker + 11, // 11: proto.DSLinker.DSPreImage:type_name -> proto.DSPreImage + 13, // 12: proto.TxFee.TFPreImage:type_name -> proto.TFPreImage + 13, // [13:13] is the sub-list for method output_type + 13, // [13:13] is the sub-list for method input_type + 13, // [13:13] is the sub-list for extension type_name + 13, // [13:13] is the sub-list for extension extendee + 0, // [0:13] is the sub-list for field type_name } func init() { file_aobjs_proto_init() } @@ -1121,11 +1296,36 @@ func file_aobjs_proto_init() { return nil } } + file_aobjs_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TxFee); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_aobjs_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TFPreImage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_aobjs_proto_msgTypes[1].OneofWrappers = []interface{}{ (*TXOut_AtomicSwap)(nil), (*TXOut_ValueStore)(nil), (*TXOut_DataStore)(nil), + (*TXOut_TxFee)(nil), } type x struct{} out := protoimpl.TypeBuilder{ @@ -1133,7 +1333,7 @@ func file_aobjs_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_aobjs_proto_rawDesc, NumEnums: 0, - NumMessages: 12, + NumMessages: 14, NumExtensions: 0, NumServices: 0, }, diff --git a/proto/aobjs.proto b/proto/aobjs.proto index ac1b294c..c0129aa4 100644 --- a/proto/aobjs.proto +++ b/proto/aobjs.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package proto; -//option go_package = "github.com/MadBase/MadNet/proto"; +option go_package = "github.com/MadBase/MadNet/proto"; // Protobuf message implementation for struct Tx message Tx { @@ -16,6 +16,7 @@ message TXOut { AtomicSwap AtomicSwap = 1; ValueStore ValueStore = 2; DataStore DataStore = 3; + TxFee TxFee = 4; } } @@ -57,6 +58,7 @@ message ASPreImage { uint32 IssuedAt = 4; uint32 Exp = 5; string Owner = 6; + string Fee = 7; } // Protobuf message implementation for struct ValueStore @@ -71,7 +73,8 @@ message VSPreImage { uint32 ChainID = 1; string Value = 2; uint32 TXOutIdx = 3; - string Owner = 4; + string Owner = 4; + string Fee = 5; } @@ -98,4 +101,20 @@ message DSPreImage { string RawData = 5; uint32 TXOutIdx = 6; string Owner = 7; + string Fee = 8; +} + + +// Protobuf message implementation for struct TxFee +message TxFee { + TFPreImage TFPreImage = 1; + string TxHash = 2; +} + + +// Protobuf message implementation for struct TFPreImage +message TFPreImage { + uint32 ChainID = 1; + uint32 TXOutIdx = 2; + string Fee = 3; }