From 53784d9c76f1056423b57915f7e064a6f551100c Mon Sep 17 00:00:00 2001 From: wz Date: Thu, 16 May 2019 14:37:07 +0800 Subject: [PATCH 01/16] Add validate votetx (#64) * Add validate votetx * delete uint test * fix review * recover code * recover code * fix * fix --- protocol/bc/tx.go | 9 ++++++++ protocol/txpool.go | 15 +++++++++--- protocol/txpool_test.go | 58 +++++++++++++++++++++++++++++++++++++++++++++++ protocol/validation/tx.go | 50 +++++++++++++++++----------------------- 4 files changed, 100 insertions(+), 32 deletions(-) diff --git a/protocol/bc/tx.go b/protocol/bc/tx.go index cf5f763b..9b00d390 100644 --- a/protocol/bc/tx.go +++ b/protocol/bc/tx.go @@ -59,6 +59,15 @@ func (tx *Tx) CrossChainOutput(id Hash) (*CrossChainOutput, error) { return o, nil } +// Entry try to get the entry by given hash +func (tx *Tx) Entry(id Hash) (Entry, error) { + e, ok := tx.Entries[id] + if !ok || e == nil { + return nil, errors.Wrapf(ErrMissingEntry, "id %x", id.Bytes()) + } + return e, nil +} + // Spend try to get the spend entry by given hash func (tx *Tx) Spend(id Hash) (*Spend, error) { e, ok := tx.Entries[id] diff --git a/protocol/txpool.go b/protocol/txpool.go index 7d6bf9ff..957ab6af 100644 --- a/protocol/txpool.go +++ b/protocol/txpool.go @@ -277,12 +277,21 @@ func (tp *TxPool) addTransaction(txD *TxDesc) error { txD.Added = time.Now() tp.pool[tx.ID] = txD for _, id := range tx.ResultIds { - output, err := tx.IntraChainOutput(*id) + var assetID bc.AssetID + outputEntry, err := tx.Entry(*id) if err != nil { - // error due to it's a retirement, utxo doesn't care this output type so skip it + return err + } + switch output := outputEntry.(type) { + case *bc.IntraChainOutput: + assetID = *output.Source.Value.AssetId + case *bc.VoteOutput: + assetID = *output.Source.Value.AssetId + default: continue } - if !txD.StatusFail || *output.Source.Value.AssetId == *consensus.BTMAssetID { + + if !txD.StatusFail || assetID == *consensus.BTMAssetID { tp.utxo[*id] = tx } } diff --git a/protocol/txpool_test.go b/protocol/txpool_test.go index 9db8aa8c..05eff7f4 100644 --- a/protocol/txpool_test.go +++ b/protocol/txpool_test.go @@ -94,6 +94,19 @@ var testTxs = []*types.Tx{ types.NewIntraChainOutput(bc.NewAssetID([32]byte{0xa1}), 0, []byte{0x65}), }, }), + //tx7 + types.NewTx(types.TxData{ + SerializedSize: 150, + TimeRange: 0, + Inputs: []*types.TxInput{ + types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}), + types.NewSpendInput(nil, bc.NewHash([32]byte{0x02}), bc.NewAssetID([32]byte{0xa1}), 4, 1, []byte{0x51}), + }, + Outputs: []*types.TxOutput{ + types.NewIntraChainOutput(*consensus.BTMAssetID, 1, []byte{0x6b}), + types.NewVoteOutput(bc.NewAssetID([32]byte{0xa1}), 4, []byte{0x61}, []byte("a8f410b9f7cd9ce352d215ed17c85559c351dc8d18ed89ad403ca28cfc423f612e04a1c9584f945c286c47ec1e5b8405c65ff56e31f44a2627aca4f77e03936f")), + }, + }), } type mockStore struct{} @@ -287,6 +300,51 @@ func TestAddTransaction(t *testing.T) { StatusFail: true, }, }, + { + before: &TxPool{ + pool: map[bc.Hash]*TxDesc{}, + utxo: map[bc.Hash]*types.Tx{}, + eventDispatcher: dispatcher, + }, + after: &TxPool{ + pool: map[bc.Hash]*TxDesc{ + testTxs[7].ID: { + Tx: testTxs[7], + StatusFail: false, + }, + }, + utxo: map[bc.Hash]*types.Tx{ + *testTxs[7].ResultIds[0]: testTxs[7], + *testTxs[7].ResultIds[1]: testTxs[7], + }, + }, + addTx: &TxDesc{ + Tx: testTxs[7], + StatusFail: false, + }, + }, + { + before: &TxPool{ + pool: map[bc.Hash]*TxDesc{}, + utxo: map[bc.Hash]*types.Tx{}, + eventDispatcher: dispatcher, + }, + after: &TxPool{ + pool: map[bc.Hash]*TxDesc{ + testTxs[7].ID: { + Tx: testTxs[7], + StatusFail: true, + }, + }, + utxo: map[bc.Hash]*types.Tx{ + *testTxs[7].ResultIds[0]: testTxs[7], + }, + }, + addTx: &TxDesc{ + Tx: testTxs[7], + StatusFail: true, + }, + }, } for i, c := range cases { diff --git a/protocol/validation/tx.go b/protocol/validation/tx.go index c12c04f3..1e2467b5 100644 --- a/protocol/validation/tx.go +++ b/protocol/validation/tx.go @@ -224,6 +224,13 @@ func checkValid(vs *validationState, e bc.Entry) (err error) { return errors.Wrap(err, "checking output source") } + case *bc.VoteOutput: + vs2 := *vs + vs2.sourcePos = 0 + if err = checkValidSrc(&vs2, e.Source); err != nil { + return errors.Wrap(err, "checking output source") + } + case *bc.Retirement: vs2 := *vs vs2.sourcePos = 0 @@ -417,6 +424,12 @@ func checkValidDest(vs *validationState, vd *bc.ValueDestination) error { } src = ref.Source + case *bc.VoteOutput: + if vd.Position != 0 { + return errors.Wrapf(ErrPosition, "invalid position %d for output destination", vd.Position) + } + src = ref.Source + case *bc.Retirement: if vd.Position != 0 { return errors.Wrapf(ErrPosition, "invalid position %d for retirement destination", vd.Position) @@ -465,45 +478,24 @@ func checkStandardTx(tx *bc.Tx, blockHeight uint64) error { continue } - intraChainSpentOutput, err := tx.IntraChainOutput(*spend.SpentOutputId) + code := []byte{} + outputEntry, err := tx.Entry(*spend.SpentOutputId) if err != nil { return err } - - if !segwit.IsP2WScript(intraChainSpentOutput.ControlProgram.Code) { - return ErrNotStandardTx - } - } - - for _, id := range tx.ResultIds { - e, ok := tx.Entries[*id] - if !ok { - return errors.Wrapf(bc.ErrMissingEntry, "id %x", id.Bytes()) - } - - var prog []byte - switch e := e.(type) { + switch output := outputEntry.(type) { case *bc.IntraChainOutput: - if *e.Source.Value.AssetId != *consensus.BTMAssetID { - continue - } - prog = e.ControlProgram.Code - - case *bc.CrossChainOutput: - if *e.Source.Value.AssetId != *consensus.BTMAssetID { - continue - } - prog = e.ControlProgram.Code - + code = output.ControlProgram.Code + case *bc.VoteOutput: + code = output.ControlProgram.Code default: - continue + return errors.Wrapf(bc.ErrEntryType, "entry %x has unexpected type %T", id.Bytes(), outputEntry) } - if !segwit.IsP2WScript(prog) { + if !segwit.IsP2WScript(code) { return ErrNotStandardTx } } - return nil } -- 2.11.0 From 089cb9074ed375e28850d2ff8b5e91164a04046d Mon Sep 17 00:00:00 2001 From: Paladz Date: Thu, 16 May 2019 14:46:15 +0800 Subject: [PATCH 02/16] init for remove issue (#63) * init for remove issue * keep remove issue * delete the issuance * remove issue related --- api/api.go | 1 - api/assets.go | 42 --- api/transact.go | 1 - api/wallet.go | 10 - asset/annotate.go | 13 - asset/asset.go | 87 ------ asset/asset_test.go | 188 ------------- asset/builder.go | 72 ----- asset/image.go | 65 ----- blockchain/query/annotated.go | 13 - blockchain/txbuilder/estimate.go | 36 +-- blockchain/txbuilder/finalize.go | 2 - blockchain/txbuilder/txbuilder_test.go | 94 ------- blockchain/txfeed/txfeed.go | 3 - netsync/tool_test.go | 11 +- protocol/bc/asset.go | 23 -- protocol/bc/asset_test.go | 77 ------ protocol/bc/bc.pb.go | 224 +++++---------- protocol/bc/bc.proto | 14 - protocol/bc/entry_test.go | 5 - protocol/bc/issuance.go | 30 -- protocol/bc/tx.go | 13 - protocol/bc/types/block_test.go | 223 --------------- protocol/bc/types/issuance.go | 59 ---- protocol/bc/types/map.go | 33 +-- protocol/bc/types/map_test.go | 22 -- protocol/bc/types/merkle_test.go | 49 +--- protocol/bc/types/transaction.go | 2 - protocol/bc/types/transaction_test.go | 145 ---------- protocol/bc/types/txinput.go | 89 ------ protocol/bc/types/txinput_test.go | 55 ---- protocol/validation/test/tx_ugly_test.go | 301 --------------------- protocol/validation/tx.go | 26 -- protocol/validation/tx_scene_test.go | 64 ----- protocol/validation/tx_test.go | 73 +---- protocol/validation/vmcontext.go | 18 -- protocol/validation/vmcontext_test.go | 1 - protocol/vm/vmutil/script.go | 19 -- protocol/vm/vmutil/script_test.go | 32 --- test/chain_test.go | 15 - test/testdata/chain_tests/ct_dependency_tx.json | 74 ----- test/testdata/chain_tests/ct_double_spend.json | 47 ---- test/testdata/chain_tests/ct_normal.json | 46 ---- test/testdata/chain_tests/ct_rollback.json | 75 ----- test/testdata/tx_tests/tx_tests.json | 229 ---------------- test/testdata/wallet_tests/wt_asset.json | 94 ------- test/testdata/wallet_tests/wt_btm.json | 39 --- test/testdata/wallet_tests/wt_invalid_txs.json | 113 -------- test/testdata/wallet_tests/wt_multi_sig_asset.json | 97 ------- test/testdata/wallet_tests/wt_retire_asset.json | 118 -------- test/testdata/wallet_tests/wt_rollback.json | 98 ------- test/tx_test.go | 264 ------------------ test/tx_test_util.go | 29 -- test/wallet_test.go | 18 -- test/wallet_test_util.go | 16 -- wallet/annotated.go | 13 - wallet/indexer.go | 12 +- wallet/unconfirmed_test.go | 8 +- wallet/utxo_test.go | 12 - wallet/wallet_test.go | 14 +- 60 files changed, 92 insertions(+), 3574 deletions(-) delete mode 100644 asset/asset_test.go delete mode 100644 asset/builder.go delete mode 100644 asset/image.go delete mode 100644 protocol/bc/asset_test.go delete mode 100644 protocol/bc/issuance.go delete mode 100644 protocol/bc/types/block_test.go delete mode 100644 protocol/bc/types/issuance.go delete mode 100644 test/chain_test.go delete mode 100644 test/testdata/chain_tests/ct_dependency_tx.json delete mode 100644 test/testdata/chain_tests/ct_double_spend.json delete mode 100644 test/testdata/chain_tests/ct_normal.json delete mode 100644 test/testdata/chain_tests/ct_rollback.json delete mode 100644 test/testdata/tx_tests/tx_tests.json delete mode 100644 test/testdata/wallet_tests/wt_asset.json delete mode 100644 test/testdata/wallet_tests/wt_btm.json delete mode 100644 test/testdata/wallet_tests/wt_invalid_txs.json delete mode 100644 test/testdata/wallet_tests/wt_multi_sig_asset.json delete mode 100644 test/testdata/wallet_tests/wt_retire_asset.json delete mode 100644 test/testdata/wallet_tests/wt_rollback.json delete mode 100644 test/tx_test.go delete mode 100644 test/wallet_test.go diff --git a/api/api.go b/api/api.go index cc32e6e5..23967033 100644 --- a/api/api.go +++ b/api/api.go @@ -223,7 +223,6 @@ func (a *API) buildHandler() { m.Handle("/get-coinbase-arbitrary", jsonHandler(a.getCoinbaseArbitrary)) m.Handle("/set-coinbase-arbitrary", jsonHandler(a.setCoinbaseArbitrary)) - m.Handle("/create-asset", jsonHandler(a.createAsset)) m.Handle("/update-asset-alias", jsonHandler(a.updateAssetAlias)) m.Handle("/get-asset", jsonHandler(a.getAsset)) m.Handle("/list-assets", jsonHandler(a.listAssets)) diff --git a/api/assets.go b/api/assets.go index a1958c01..cecc583c 100644 --- a/api/assets.go +++ b/api/assets.go @@ -1,47 +1,5 @@ package api -import ( - "context" - "strings" - - "github.com/vapor/asset" - "github.com/vapor/crypto/ed25519/chainkd" - chainjson "github.com/vapor/encoding/json" - - log "github.com/sirupsen/logrus" -) - -// POST /create-asset -func (a *API) createAsset(ctx context.Context, ins struct { - Alias string `json:"alias"` - RootXPubs []chainkd.XPub `json:"root_xpubs"` - Quorum int `json:"quorum"` - Definition map[string]interface{} `json:"definition"` - LimitHeight int64 `json:"limit_height"` - IssuanceProgram chainjson.HexBytes `json:"issuance_program"` -}) Response { - ass, err := a.wallet.AssetReg.Define( - ins.RootXPubs, - ins.Quorum, - ins.Definition, - ins.LimitHeight, - strings.ToUpper(strings.TrimSpace(ins.Alias)), - ins.IssuanceProgram, - ) - if err != nil { - return NewErrorResponse(err) - } - - annotatedAsset, err := asset.Annotated(ass) - if err != nil { - return NewErrorResponse(err) - } - - log.WithField("asset ID", annotatedAsset.ID.String()).Info("Created asset") - - return NewSuccessResponse(annotatedAsset) -} - // POST /update-asset-alias func (a *API) updateAssetAlias(updateAlias struct { ID string `json:"id"` diff --git a/api/transact.go b/api/transact.go index 87a75e29..25d61bca 100644 --- a/api/transact.go +++ b/api/transact.go @@ -25,7 +25,6 @@ func (a *API) actionDecoder(action string) (func([]byte) (txbuilder.Action, erro decoders := map[string]func([]byte) (txbuilder.Action, error){ "control_address": txbuilder.DecodeControlAddressAction, "control_program": txbuilder.DecodeControlProgramAction, - "issue": a.wallet.AssetReg.DecodeIssueAction, "retire": txbuilder.DecodeRetireAction, "spend_account": a.wallet.AccountMgr.DecodeSpendAction, "spend_account_unspent_output": a.wallet.AccountMgr.DecodeSpendUTXOAction, diff --git a/api/wallet.go b/api/wallet.go index e78c68bd..c59109a1 100644 --- a/api/wallet.go +++ b/api/wallet.go @@ -4,7 +4,6 @@ import ( "context" "github.com/vapor/account" - "github.com/vapor/asset" "github.com/vapor/blockchain/pseudohsm" "github.com/vapor/crypto/ed25519/chainkd" "github.com/vapor/errors" @@ -18,7 +17,6 @@ func (a *API) walletError() Response { // WalletImage hold the ziped wallet data type WalletImage struct { AccountImage *account.Image `json:"account_image"` - AssetImage *asset.Image `json:"asset_image"` KeyImages *pseudohsm.KeyImage `json:"key_images"` } @@ -26,9 +24,6 @@ func (a *API) restoreWalletImage(ctx context.Context, image WalletImage) Respons if err := a.wallet.Hsm.Restore(image.KeyImages); err != nil { return NewErrorResponse(errors.Wrap(err, "restore key images")) } - if err := a.wallet.AssetReg.Restore(image.AssetImage); err != nil { - return NewErrorResponse(errors.Wrap(err, "restore asset image")) - } if err := a.wallet.AccountMgr.Restore(image.AccountImage); err != nil { return NewErrorResponse(errors.Wrap(err, "restore account image")) } @@ -51,10 +46,6 @@ func (a *API) backupWalletImage() Response { if err != nil { return NewErrorResponse(errors.Wrap(err, "backup key images")) } - assetImage, err := a.wallet.AssetReg.Backup() - if err != nil { - return NewErrorResponse(errors.Wrap(err, "backup asset image")) - } accountImage, err := a.wallet.AccountMgr.Backup() if err != nil { return NewErrorResponse(errors.Wrap(err, "backup account image")) @@ -62,7 +53,6 @@ func (a *API) backupWalletImage() Response { image := &WalletImage{ KeyImages: keyImages, - AssetImage: assetImage, AccountImage: accountImage, } return NewSuccessResponse(image) diff --git a/asset/annotate.go b/asset/annotate.go index 514166eb..41562026 100644 --- a/asset/annotate.go +++ b/asset/annotate.go @@ -4,8 +4,6 @@ import ( "encoding/json" "github.com/vapor/blockchain/query" - chainjson "github.com/vapor/encoding/json" - "github.com/vapor/protocol/vm/vmutil" ) func isValidJSON(b []byte) bool { @@ -30,18 +28,7 @@ func Annotated(a *Asset) (*query.AnnotatedAsset, error) { VMVersion: a.VMVersion, RawDefinitionByte: a.RawDefinitionByte, Definition: &jsonDefinition, - IssuanceProgram: chainjson.HexBytes(a.IssuanceProgram), } - annotatedAsset.LimitHeight = vmutil.GetIssuanceProgramRestrictHeight(a.IssuanceProgram) - if a.Signer != nil { - annotatedAsset.AnnotatedSigner = query.AnnotatedSigner{ - Type: a.Signer.Type, - XPubs: a.Signer.XPubs, - Quorum: a.Signer.Quorum, - KeyIndex: a.Signer.KeyIndex, - DeriveRule: a.Signer.DeriveRule, - } - } return annotatedAsset, nil } diff --git a/asset/asset.go b/asset/asset.go index cf3fef54..12ae60b3 100644 --- a/asset/asset.go +++ b/asset/asset.go @@ -7,19 +7,13 @@ import ( "sync" "github.com/golang/groupcache/lru" - "golang.org/x/crypto/sha3" - "github.com/vapor/blockchain/signers" - "github.com/vapor/common" "github.com/vapor/consensus" - "github.com/vapor/crypto/ed25519" - "github.com/vapor/crypto/ed25519/chainkd" dbm "github.com/vapor/database/leveldb" chainjson "github.com/vapor/encoding/json" "github.com/vapor/errors" "github.com/vapor/protocol" "github.com/vapor/protocol/bc" - "github.com/vapor/protocol/vm/vmutil" ) // DefaultNativeAsset native BTM asset @@ -37,12 +31,10 @@ var ( ) func initNativeAsset() { - signer := &signers.Signer{Type: "internal"} alias := consensus.BTMAlias definitionBytes, _ := serializeAssetDef(consensus.BTMDefinitionMap) DefaultNativeAsset = &Asset{ - Signer: signer, AssetID: *consensus.BTMAssetID, Alias: &alias, VMVersion: 1, @@ -103,81 +95,13 @@ type Registry struct { //Asset describe asset on bytom chain type Asset struct { - *signers.Signer AssetID bc.AssetID `json:"id"` Alias *string `json:"alias"` VMVersion uint64 `json:"vm_version"` - IssuanceProgram chainjson.HexBytes `json:"issue_program"` RawDefinitionByte chainjson.HexBytes `json:"raw_definition_byte"` DefinitionMap map[string]interface{} `json:"definition"` } -func (reg *Registry) getNextAssetIndex() uint64 { - reg.assetIndexMu.Lock() - defer reg.assetIndexMu.Unlock() - - nextIndex := uint64(1) - if rawIndex := reg.db.Get(assetIndexKey); rawIndex != nil { - nextIndex = common.BytesToUnit64(rawIndex) + 1 - } - - reg.db.Set(assetIndexKey, common.Unit64ToBytes(nextIndex)) - return nextIndex -} - -// Define defines a new Asset. -func (reg *Registry) Define(xpubs []chainkd.XPub, quorum int, definition map[string]interface{}, limitHeight int64, alias string, issuanceProgram chainjson.HexBytes) (*Asset, error) { - var err error - var assetSigner *signers.Signer - - alias = strings.ToUpper(strings.TrimSpace(alias)) - if alias == "" { - return nil, errors.Wrap(ErrNullAlias) - } - - if alias == consensus.BTMAlias { - return nil, ErrInternalAsset - } - - rawDefinition, err := serializeAssetDef(definition) - if err != nil { - return nil, ErrSerializing - } - - vmver := uint64(1) - if len(issuanceProgram) == 0 { - if len(xpubs) == 0 { - return nil, errors.Wrap(signers.ErrNoXPubs) - } - - nextAssetIndex := reg.getNextAssetIndex() - assetSigner, err = signers.Create("asset", xpubs, quorum, nextAssetIndex, signers.BIP0032) - if err != nil { - return nil, err - } - - path := signers.GetBip0032Path(assetSigner, signers.AssetKeySpace) - derivedXPubs := chainkd.DeriveXPubs(assetSigner.XPubs, path) - derivedPKs := chainkd.XPubKeys(derivedXPubs) - issuanceProgram, vmver, err = multisigIssuanceProgram(derivedPKs, assetSigner.Quorum, limitHeight) - if err != nil { - return nil, err - } - } - - defHash := bc.NewHash(sha3.Sum256(rawDefinition)) - a := &Asset{ - DefinitionMap: definition, - RawDefinitionByte: rawDefinition, - VMVersion: vmver, - IssuanceProgram: issuanceProgram, - AssetID: bc.ComputeAssetID(issuanceProgram, vmver, &defHash), - Signer: assetSigner, - Alias: &alias, - } - return a, reg.SaveAsset(a, alias) -} - // SaveAsset store asset func (reg *Registry) SaveAsset(a *Asset, alias string) error { reg.assetMu.Lock() @@ -363,17 +287,6 @@ func serializeAssetDef(def map[string]interface{}) ([]byte, error) { return json.MarshalIndent(def, "", " ") } -func multisigIssuanceProgram(pubkeys []ed25519.PublicKey, nrequired int, blockHeight int64) (program []byte, vmversion uint64, err error) { - issuanceProg, err := vmutil.P2SPMultiSigProgramWithHeight(pubkeys, nrequired, blockHeight) - if err != nil { - return nil, 0, err - } - builder := vmutil.NewBuilder() - builder.AddRawBytes(issuanceProg) - prog, err := builder.Build() - return prog, 1, err -} - //UpdateAssetAlias updates asset alias func (reg *Registry) UpdateAssetAlias(id, newAlias string) error { oldAlias := reg.GetAliasByID(id) diff --git a/asset/asset_test.go b/asset/asset_test.go deleted file mode 100644 index 844e074a..00000000 --- a/asset/asset_test.go +++ /dev/null @@ -1,188 +0,0 @@ -package asset - -import ( - "context" - "io/ioutil" - "os" - "reflect" - "sort" - "strings" - "testing" - - "github.com/vapor/consensus" - "github.com/vapor/crypto/ed25519/chainkd" - "github.com/vapor/database" - dbm "github.com/vapor/database/leveldb" - "github.com/vapor/event" - "github.com/vapor/protocol" - "github.com/vapor/testutil" -) - -func TestDefineAssetWithLowercase(t *testing.T) { - reg := mockNewRegistry(t) - alias := "lower" - asset, err := reg.Define([]chainkd.XPub{testutil.TestXPub}, 1, nil, 0, alias, nil) - if err != nil { - t.Fatal(err) - } - if *asset.Alias != strings.ToUpper(alias) { - t.Fatal("created asset alias should be uppercase") - } -} - -func TestDefineAssetWithSpaceTrimed(t *testing.T) { - reg := mockNewRegistry(t) - alias := " WITH SPACE " - asset, err := reg.Define([]chainkd.XPub{testutil.TestXPub}, 1, nil, 0, alias, nil) - if err != nil { - t.Fatal(err) - } - if *asset.Alias != strings.TrimSpace(alias) { - t.Fatal("created asset alias should be uppercase") - } -} - -func TestDefineAsset(t *testing.T) { - ctx := context.Background() - reg := mockNewRegistry(t) - asset, err := reg.Define([]chainkd.XPub{testutil.TestXPub}, 1, nil, 0, "asset-alias", nil) - if err != nil { - testutil.FatalErr(t, err) - } - - limitAsset, err := reg.Define([]chainkd.XPub{testutil.TestXPub}, 1, nil, 100, "limit-asset", nil) - if err != nil { - testutil.FatalErr(t, err) - } - - assets := []*Asset{asset, limitAsset} - for _, ass := range assets { - found, err := reg.FindByID(ctx, &ass.AssetID) - if err != nil { - t.Errorf("unexpected error %v", err) - } - - if !testutil.DeepEqual(ass, found) { - t.Errorf("expected asset %v to be recorded as %v", ass, found) - } - } -} - -func TestDefineBtmAsset(t *testing.T) { - reg := mockNewRegistry(t) - _, err := reg.Define([]chainkd.XPub{testutil.TestXPub}, 1, nil, 0, consensus.BTMAlias, nil) - if err == nil { - testutil.FatalErr(t, err) - } -} - -func TestFindAssetByID(t *testing.T) { - ctx := context.Background() - reg := mockNewRegistry(t) - keys := []chainkd.XPub{testutil.TestXPub} - asset, err := reg.Define(keys, 1, nil, 0, "TESTASSET", nil) - if err != nil { - testutil.FatalErr(t, err) - - } - found, err := reg.FindByID(ctx, &asset.AssetID) - if err != nil { - testutil.FatalErr(t, err) - } - - if !testutil.DeepEqual(asset, found) { - t.Errorf("expected %v and %v to match", asset, found) - } -} - -func TestUpdateAssetAlias(t *testing.T) { - reg := mockNewRegistry(t) - - oldAlias := "OLD_ALIAS" - newAlias := "NEW_ALIAS" - - asset, err := reg.Define([]chainkd.XPub{testutil.TestXPub}, 1, nil, 0, oldAlias, nil) - if err != nil { - testutil.FatalErr(t, err) - } - - if reg.UpdateAssetAlias(asset.AssetID.String(), newAlias) != nil { - testutil.FatalErr(t, err) - } - - asset1, err := reg.FindByAlias(newAlias) - if err != nil { - testutil.FatalErr(t, err) - } - - gotAlias := *asset1.Alias - if !reflect.DeepEqual(gotAlias, newAlias) { - t.Fatalf("alias:\ngot: %v\nwant: %v", gotAlias, newAlias) - } -} - -type SortByAssetsAlias []*Asset - -func (a SortByAssetsAlias) Len() int { return len(a) } -func (a SortByAssetsAlias) Less(i, j int) bool { - return strings.Compare(*a[i].Alias, *a[j].Alias) <= 0 -} -func (a SortByAssetsAlias) Swap(i, j int) { a[i], a[j] = a[j], a[i] } - -func TestListAssets(t *testing.T) { - reg := mockNewRegistry(t) - - firstAlias := "FIRST_ALIAS" - secondAlias := "SECOND_ALIAS" - - firstAsset, err := reg.Define([]chainkd.XPub{testutil.TestXPub}, 1, nil, 0, firstAlias, nil) - if err != nil { - testutil.FatalErr(t, err) - } - - secondAsset, err := reg.Define([]chainkd.XPub{testutil.TestXPub}, 1, nil, 0, secondAlias, nil) - if err != nil { - testutil.FatalErr(t, err) - } - - wantAssets := []*Asset{DefaultNativeAsset, firstAsset, secondAsset} - - gotAssets, err := reg.ListAssets("") - if err != nil { - testutil.FatalErr(t, err) - } - sort.Sort(SortByAssetsAlias(wantAssets)) - sort.Sort(SortByAssetsAlias(gotAssets)) - if !testutil.DeepEqual(gotAssets, wantAssets) { - t.Fatalf("got:\ngot: %v\nwant: %v", gotAssets, wantAssets) - } -} - -func mockChain(testDB dbm.DB) (*protocol.Chain, error) { - store := database.NewStore(testDB) - dispatcher := event.NewDispatcher() - txPool := protocol.NewTxPool(store, dispatcher) - chain, err := protocol.NewChain(store, txPool) - if err != nil { - return nil, err - } - return chain, nil -} - -func mockNewRegistry(t *testing.T) *Registry { - dirPath, err := ioutil.TempDir(".", "") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dirPath) - - testDB := dbm.NewDB("testdb", "leveldb", "temp") - defer os.RemoveAll("temp") - - chain, err := mockChain(testDB) - if err != nil { - t.Fatal(err) - } - - return NewRegistry(testDB, chain) -} diff --git a/asset/builder.go b/asset/builder.go deleted file mode 100644 index 44f94418..00000000 --- a/asset/builder.go +++ /dev/null @@ -1,72 +0,0 @@ -package asset - -import ( - "context" - "crypto/rand" - "encoding/json" - "time" - - log "github.com/sirupsen/logrus" - - "github.com/vapor/blockchain/signers" - "github.com/vapor/blockchain/txbuilder" - "github.com/vapor/protocol/bc" - "github.com/vapor/protocol/bc/types" -) - -//NewIssueAction create a new asset issue action -func (reg *Registry) NewIssueAction(assetAmount bc.AssetAmount) txbuilder.Action { - return &issueAction{ - assets: reg, - AssetAmount: assetAmount, - } -} - -//DecodeIssueAction unmarshal JSON-encoded data of asset issue action -func (reg *Registry) DecodeIssueAction(data []byte) (txbuilder.Action, error) { - a := &issueAction{assets: reg} - err := json.Unmarshal(data, a) - return a, err -} - -type issueAction struct { - assets *Registry - bc.AssetAmount - Arguments []txbuilder.ContractArgument `json:"arguments"` -} - -func (a *issueAction) Build(ctx context.Context, builder *txbuilder.TemplateBuilder) error { - if a.AssetId.IsZero() { - return txbuilder.MissingFieldsError("asset_id") - } - - asset, err := a.assets.FindByID(ctx, a.AssetId) - if err != nil { - return err - } - - var nonce [8]byte - _, err = rand.Read(nonce[:]) - if err != nil { - return err - } - - txin := types.NewIssuanceInput(nonce[:], a.Amount, asset.IssuanceProgram, nil, asset.RawDefinitionByte) - tplIn := &txbuilder.SigningInstruction{} - if asset.Signer != nil { - path := signers.GetBip0032Path(asset.Signer, signers.AssetKeySpace) - tplIn.AddRawWitnessKeys(asset.Signer.XPubs, path, asset.Signer.Quorum) - } else if a.Arguments != nil { - if err := txbuilder.AddContractArgs(tplIn, a.Arguments); err != nil { - return err - } - } - - log.Info("Issue action build") - builder.RestrictMinTime(time.Now()) - return builder.AddInput(txin, tplIn) -} - -func (a *issueAction) ActionType() string { - return "issue" -} diff --git a/asset/image.go b/asset/image.go deleted file mode 100644 index 838bf578..00000000 --- a/asset/image.go +++ /dev/null @@ -1,65 +0,0 @@ -package asset - -import ( - "encoding/json" - - log "github.com/sirupsen/logrus" - - "github.com/vapor/common" -) - -// Image is the struct for hold export asset data -type Image struct { - Assets []*Asset `json:"assets"` -} - -// Backup export all the asset info into image -func (reg *Registry) Backup() (*Image, error) { - assetImage := &Image{ - Assets: []*Asset{}, - } - - assetIter := reg.db.IteratorPrefix([]byte(assetPrefix)) - defer assetIter.Release() - for assetIter.Next() { - asset := &Asset{} - if err := json.Unmarshal(assetIter.Value(), asset); err != nil { - return nil, err - } - assetImage.Assets = append(assetImage.Assets, asset) - } - - return assetImage, nil -} - -// Restore load the image data into asset manage -func (reg *Registry) Restore(image *Image) error { - maxAssetIndex := uint64(0) - storeBatch := reg.db.NewBatch() - for _, asset := range image.Assets { - if existed := reg.db.Get(Key(&asset.AssetID)); existed != nil { - log.WithFields(log.Fields{"alias": asset.Alias, "id": asset.AssetID}).Warning("skip restore asset due to already existed") - continue - } - if existed := reg.db.Get(aliasKey(*asset.Alias)); existed != nil { - return ErrDuplicateAlias - } - - rawAsset, err := json.Marshal(asset) - if err != nil { - return err - } - - if asset.Signer.KeyIndex > maxAssetIndex { - maxAssetIndex = asset.Signer.KeyIndex - } - storeBatch.Set(aliasKey(*asset.Alias), []byte(asset.AssetID.String())) - storeBatch.Set(Key(&asset.AssetID), rawAsset) - } - - if localIndex := reg.getNextAssetIndex(); localIndex < maxAssetIndex { - storeBatch.Set(assetIndexKey, common.Unit64ToBytes(maxAssetIndex)) - } - storeBatch.Write() - return nil -} diff --git a/blockchain/query/annotated.go b/blockchain/query/annotated.go index 12060cc9..1696b0e9 100644 --- a/blockchain/query/annotated.go +++ b/blockchain/query/annotated.go @@ -29,7 +29,6 @@ type AnnotatedInput struct { AssetAlias string `json:"asset_alias,omitempty"` AssetDefinition *json.RawMessage `json:"asset_definition,omitempty"` Amount uint64 `json:"amount"` - IssuanceProgram chainjson.HexBytes `json:"issuance_program,omitempty"` ControlProgram chainjson.HexBytes `json:"control_program,omitempty"` Address string `json:"address,omitempty"` SpentOutputID *bc.Hash `json:"spent_output_id,omitempty"` @@ -68,23 +67,11 @@ type AnnotatedAccount struct { //AnnotatedAsset means an annotated asset. type AnnotatedAsset struct { - AnnotatedSigner ID bc.AssetID `json:"id"` Alias string `json:"alias"` VMVersion uint64 `json:"vm_version"` - IssuanceProgram chainjson.HexBytes `json:"issue_program"` RawDefinitionByte chainjson.HexBytes `json:"raw_definition_byte"` Definition *json.RawMessage `json:"definition"` - LimitHeight int64 `json:"limit_height"` -} - -//AnnotatedSigner means an annotated signer for asset. -type AnnotatedSigner struct { - Type string `json:"type"` - XPubs []chainkd.XPub `json:"xpubs"` - Quorum int `json:"quorum"` - KeyIndex uint64 `json:"key_index"` - DeriveRule uint8 `json:"derive_rule"` } //AnnotatedUTXO means an annotated utxo. diff --git a/blockchain/txbuilder/estimate.go b/blockchain/txbuilder/estimate.go index ea205a86..b769435f 100644 --- a/blockchain/txbuilder/estimate.go +++ b/blockchain/txbuilder/estimate.go @@ -4,7 +4,6 @@ import ( "github.com/vapor/consensus" "github.com/vapor/consensus/segwit" "github.com/vapor/protocol/bc/types" - "github.com/vapor/protocol/vm/vmutil" ) // EstimateTxGasInfo estimate transaction consumed gas @@ -17,7 +16,7 @@ type EstimateTxGasInfo struct { // EstimateTxGas estimate consumed neu for transaction func EstimateTxGas(template Template) (*EstimateTxGasInfo, error) { - var baseP2WSHSize, totalWitnessSize, baseP2WSHGas, totalP2WPKHGas, totalP2WSHGas, totalIssueGas int64 + var baseP2WSHSize, totalWitnessSize, baseP2WSHGas, totalP2WPKHGas, totalP2WSHGas int64 baseSize := int64(176) // inputSize(112) + outputSize(64) baseP2WPKHSize := int64(98) baseP2WPKHGas := int64(1409) @@ -33,16 +32,6 @@ func EstimateTxGas(template Template) (*EstimateTxGasInfo, error) { totalWitnessSize += baseP2WSHSize totalP2WSHGas += baseP2WSHGas } - - case types.IssuanceInputType: - issuanceProgram := input.IssuanceProgram() - if height := vmutil.GetIssuanceProgramRestrictHeight(issuanceProgram); height > 0 { - // the gas for issue program with checking block height - totalIssueGas += 5 - } - baseIssueSize, baseIssueGas := estimateIssueGas(template.SigningInstructions[pos]) - totalWitnessSize += baseIssueSize - totalIssueGas += baseIssueGas } } @@ -51,21 +40,18 @@ func EstimateTxGas(template Template) (*EstimateTxGasInfo, error) { flexibleGas += baseP2WPKHGas + (baseSize+baseP2WPKHSize)*consensus.StorageGasRate } else if totalP2WSHGas > 0 { flexibleGas += baseP2WSHGas + (baseSize+baseP2WSHSize)*consensus.StorageGasRate - } else if totalIssueGas > 0 { - totalIssueGas += baseP2WPKHGas - totalWitnessSize += baseSize + baseP2WPKHSize } // the total transaction storage gas totalTxSizeGas := (int64(template.Transaction.TxData.SerializedSize) + totalWitnessSize) * consensus.StorageGasRate // the total transaction gas is composed of storage and virtual machines - totalGas := totalTxSizeGas + totalP2WPKHGas + totalP2WSHGas + totalIssueGas + flexibleGas + totalGas := totalTxSizeGas + totalP2WPKHGas + totalP2WSHGas + flexibleGas return &EstimateTxGasInfo{ TotalNeu: totalGas * consensus.VMGasRate, FlexibleNeu: flexibleGas * consensus.VMGasRate, StorageNeu: totalTxSizeGas * consensus.VMGasRate, - VMNeu: (totalP2WPKHGas + totalP2WSHGas + totalIssueGas) * consensus.VMGasRate, + VMNeu: (totalP2WPKHGas + totalP2WSHGas) * consensus.VMGasRate, }, nil } @@ -90,19 +76,3 @@ func estimateP2WSHGas(sigInst *SigningInstruction) (int64, int64) { } return witnessSize, gas } - -// estimateIssueGas return the witness size and the gas consumed to execute the virtual machine for issuance program -func estimateIssueGas(sigInst *SigningInstruction) (int64, int64) { - var witnessSize, gas int64 - for _, witness := range sigInst.WitnessComponents { - switch t := witness.(type) { - case *SignatureWitness: - witnessSize += 65 * int64(t.Quorum) - gas += 1065*int64(len(t.Keys)) + 72*int64(t.Quorum) + 316 - case *RawTxSigWitness: - witnessSize += 65 * int64(t.Quorum) - gas += 1065*int64(len(t.Keys)) + 72*int64(t.Quorum) + 316 - } - } - return witnessSize, gas -} diff --git a/blockchain/txbuilder/finalize.go b/blockchain/txbuilder/finalize.go index a00440f9..b9e85bb7 100644 --- a/blockchain/txbuilder/finalize.go +++ b/blockchain/txbuilder/finalize.go @@ -91,8 +91,6 @@ func checkTxSighashCommitment(tx *types.Tx) error { switch t := inp.TypedInput.(type) { case *types.SpendInput: args = t.Arguments - case *types.IssuanceInput: - args = t.Arguments } // Note: These numbers will need to change if more args are added such that the minimum length changes switch { diff --git a/blockchain/txbuilder/txbuilder_test.go b/blockchain/txbuilder/txbuilder_test.go index fe69536c..2fcd6a6a 100644 --- a/blockchain/txbuilder/txbuilder_test.go +++ b/blockchain/txbuilder/txbuilder_test.go @@ -9,18 +9,15 @@ import ( "time" "github.com/davecgh/go-spew/spew" - "golang.org/x/crypto/sha3" "github.com/vapor/common" "github.com/vapor/consensus" "github.com/vapor/crypto" - "github.com/vapor/crypto/ed25519" "github.com/vapor/crypto/ed25519/chainkd" chainjson "github.com/vapor/encoding/json" "github.com/vapor/errors" "github.com/vapor/protocol/bc" "github.com/vapor/protocol/bc/types" - "github.com/vapor/protocol/vm" "github.com/vapor/protocol/vm/vmutil" "github.com/vapor/testutil" ) @@ -90,97 +87,6 @@ func TestBuild(t *testing.T) { } } -func TestSignatureWitnessMaterialize(t *testing.T) { - privkey1, pubkey1, err := chainkd.NewXKeys(nil) - if err != nil { - t.Fatal(err) - } - privkey2, pubkey2, err := chainkd.NewXKeys(nil) - if err != nil { - t.Fatal(err) - } - privkey3, pubkey3, err := chainkd.NewXKeys(nil) - if err != nil { - t.Fatal(err) - } - issuanceProg, _ := vmutil.P2SPMultiSigProgram([]ed25519.PublicKey{pubkey1.PublicKey(), pubkey2.PublicKey(), pubkey3.PublicKey()}, 2) - assetID := bc.ComputeAssetID(issuanceProg, 1, &bc.EmptyStringHash) - outscript := mustDecodeHex("76a914c5d128911c28776f56baaac550963f7b88501dc388c0") - unsigned := types.NewTx(types.TxData{ - Version: 1, - Inputs: []*types.TxInput{ - types.NewIssuanceInput([]byte{1}, 100, issuanceProg, nil, nil), - }, - Outputs: []*types.TxOutput{ - types.NewIntraChainOutput(assetID, 100, outscript), - }, - }) - - tpl := &Template{ - Transaction: unsigned, - } - h := tpl.Hash(0) - builder := vmutil.NewBuilder() - builder.AddData(h.Bytes()) - builder.AddOp(vm.OP_TXSIGHASH).AddOp(vm.OP_EQUAL) - prog, _ := builder.Build() - msg := sha3.Sum256(prog) - sig1 := privkey1.Sign(msg[:]) - sig2 := privkey2.Sign(msg[:]) - sig3 := privkey3.Sign(msg[:]) - want := [][]byte{ - vm.Int64Bytes(0), - sig1, - sig2, - prog, - } - - // Test with more signatures than required, in correct order - tpl.SigningInstructions = []*SigningInstruction{{ - WitnessComponents: []witnessComponent{ - &SignatureWitness{ - Quorum: 2, - Keys: []keyID{ - { - XPub: pubkey1, - DerivationPath: []chainjson.HexBytes{{0, 0, 0, 0}}, - }, - { - XPub: pubkey2, - DerivationPath: []chainjson.HexBytes{{0, 0, 0, 0}}, - }, - { - XPub: pubkey3, - DerivationPath: []chainjson.HexBytes{{0, 0, 0, 0}}, - }, - }, - Program: prog, - Sigs: []chainjson.HexBytes{sig1, sig2, sig3}, - }, - }, - }} - err = materializeWitnesses(tpl) - if err != nil { - testutil.FatalErr(t, err) - } - got := tpl.Transaction.Inputs[0].Arguments() - if !testutil.DeepEqual(got, want) { - t.Errorf("got input witness %v, want input witness %v", got, want) - } - - // Test with exact amount of signatures required, in correct order - component := tpl.SigningInstructions[0].WitnessComponents[0].(*SignatureWitness) - component.Sigs = []chainjson.HexBytes{sig1, sig2} - err = materializeWitnesses(tpl) - if err != nil { - testutil.FatalErr(t, err) - } - got = tpl.Transaction.Inputs[0].Arguments() - if !testutil.DeepEqual(got, want) { - t.Errorf("got input witness %v, want input witness %v", got, want) - } -} - func mustDecodeHex(str string) []byte { data, err := hex.DecodeString(str) if err != nil { diff --git a/blockchain/txfeed/txfeed.go b/blockchain/txfeed/txfeed.go index 48067a51..5a0396f7 100644 --- a/blockchain/txfeed/txfeed.go +++ b/blockchain/txfeed/txfeed.go @@ -353,9 +353,6 @@ func buildAnnotatedInput(tx *types.Tx, i uint32) *query.AnnotatedInput { in.Type = "spend" in.ControlProgram = orig.ControlProgram() in.SpentOutputID = e.SpentOutputId - case *bc.Issuance: - in.Type = "issue" - in.IssuanceProgram = orig.IssuanceProgram() } return in diff --git a/netsync/tool_test.go b/netsync/tool_test.go index d25e37a1..69de67ef 100644 --- a/netsync/tool_test.go +++ b/netsync/tool_test.go @@ -4,7 +4,6 @@ import ( "errors" "math/rand" "net" - "time" wire "github.com/tendermint/go-wire" "github.com/tendermint/tmlibs/flowrate" @@ -170,14 +169,12 @@ func mockSync(blocks []*types.Block) *SyncManager { func mockTxs(txCount int) ([]*types.Tx, []*bc.Tx) { var txs []*types.Tx var bcTxs []*bc.Tx - for i := 0; i < txCount; i++ { - trueProg := mockControlProgram(60) - assetID := bc.ComputeAssetID(trueProg, 1, &bc.EmptyStringHash) - now := []byte(time.Now().String()) - issuanceInp := types.NewIssuanceInput(now, 1, trueProg, nil, nil) + trueProg := mockControlProgram(60) + assetID := bc.AssetID{V0: 9999} + for i := uint64(0); i < uint64(txCount); i++ { tx := types.NewTx(types.TxData{ Version: 1, - Inputs: []*types.TxInput{issuanceInp}, + Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.Hash{V0: i + 1}, assetID, i, i, trueProg)}, Outputs: []*types.TxOutput{types.NewIntraChainOutput(assetID, 1, trueProg)}, }) txs = append(txs, tx) diff --git a/protocol/bc/asset.go b/protocol/bc/asset.go index 553cd710..91285fa6 100644 --- a/protocol/bc/asset.go +++ b/protocol/bc/asset.go @@ -5,7 +5,6 @@ import ( "errors" "io" - "github.com/vapor/crypto/sha3pool" "github.com/vapor/encoding/blockchain" ) @@ -43,28 +42,6 @@ func (a *AssetID) ReadFrom(r io.Reader) (int64, error) { return (*Hash)(a).ReadF // IsZero tells whether a Asset pointer is nil or points to an all-zero hash. func (a *AssetID) IsZero() bool { return (*Hash)(a).IsZero() } -// ComputeAssetID calculate the asset id from AssetDefinition -func (ad *AssetDefinition) ComputeAssetID() (assetID AssetID) { - h := sha3pool.Get256() - defer sha3pool.Put256(h) - writeForHash(h, *ad) // error is impossible - var b [32]byte - h.Read(b[:]) // error is impossible - return NewAssetID(b) -} - -// ComputeAssetID implement the assetID calculate logic -func ComputeAssetID(prog []byte, vmVersion uint64, data *Hash) AssetID { - def := &AssetDefinition{ - IssuanceProgram: &Program{ - VmVersion: vmVersion, - Code: prog, - }, - Data: data, - } - return def.ComputeAssetID() -} - // ReadFrom read the AssetAmount from the bytes func (a *AssetAmount) ReadFrom(r *blockchain.Reader) (err error) { var assetID AssetID diff --git a/protocol/bc/asset_test.go b/protocol/bc/asset_test.go deleted file mode 100644 index 422e1a35..00000000 --- a/protocol/bc/asset_test.go +++ /dev/null @@ -1,77 +0,0 @@ -package bc - -import ( - "testing" - "encoding/hex" - - "golang.org/x/crypto/sha3" -) - -func TestComputeAssetID(t *testing.T) { - issuanceScript := []byte{1} - assetID := ComputeAssetID(issuanceScript, 1, &EmptyStringHash) - - unhashed := append([]byte{}) - unhashed = append(unhashed, []byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}...) // vmVersion - unhashed = append(unhashed, 0x01) // length of issuanceScript - unhashed = append(unhashed, issuanceScript...) - unhashed = append(unhashed, EmptyStringHash.Bytes()...) - - if want := NewAssetID(sha3.Sum256(unhashed)); assetID != want { - t.Errorf("asset id = %x want %x", assetID.Bytes(), want.Bytes()) - } -} - -func TestComputeAssetIDReally(t *testing.T) { - cases := []struct { - program string - rawDefinition string - wantAssetID string - }{ - { - program: "ae2039294f652632eee970765550c245f0b0314256b4b93aadc86279fdb45db3b70e5151ad", - rawDefinition: "7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d", - wantAssetID: "07c7ced3f37f48ea39da6971c89f90e9cff3202d54b0a911f12ace8501f3834e", - }, - { - program: "ae20620b1755451738b04f42822f4b37186563f824c9c30d485987298918f96395fe5151ad", - rawDefinition: "7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d6f626f6c223a2022220a7d", - wantAssetID: "0dafd0f0e42f06f3bf9a8cf5787519d3860650f27a2b3393d34e1fe06e89b469", - }, - { - program: "ae20db11f9dfa39c9e66421c530fe027218edd3d5b1cd98f24c826f4d9c0cd131a475151ad", - rawDefinition: "7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d", - wantAssetID: "a5bc30d8d0ad051e6e352ebc21d79ba798cd8c436e89f4149969c2c562371791", - }, - } - - for _, c := range cases { - progBytes, err := hex.DecodeString(c.program) - if err != nil { - t.Fatal(err) - } - - defBytes, err := hex.DecodeString(c.rawDefinition) - if err != nil { - t.Fatal(err) - } - - defHash := NewHash(sha3.Sum256(defBytes)) - assetID := ComputeAssetID(progBytes, 1, &defHash) - if assetID.String() != c.wantAssetID { - t.Errorf("got asset id:%s, want asset id:%s", assetID.String(), c.wantAssetID) - } - } -} - -var assetIDSink AssetID - -func BenchmarkComputeAssetID(b *testing.B) { - var ( - issuanceScript = []byte{5} - ) - - for i := 0; i < b.N; i++ { - assetIDSink = ComputeAssetID(issuanceScript, 1, &EmptyStringHash) - } -} diff --git a/protocol/bc/bc.pb.go b/protocol/bc/bc.pb.go index e42656d7..619de902 100644 --- a/protocol/bc/bc.pb.go +++ b/protocol/bc/bc.pb.go @@ -12,7 +12,6 @@ It has these top-level messages: Program AssetID AssetAmount - AssetDefinition ValueSource ValueDestination BlockHeader @@ -25,7 +24,6 @@ It has these top-level messages: CrossChainOutput VoteOutput Retirement - Issuance Spend */ package bc @@ -178,30 +176,6 @@ func (m *AssetAmount) GetAmount() uint64 { return 0 } -type AssetDefinition struct { - IssuanceProgram *Program `protobuf:"bytes,1,opt,name=issuance_program,json=issuanceProgram" json:"issuance_program,omitempty"` - Data *Hash `protobuf:"bytes,2,opt,name=data" json:"data,omitempty"` -} - -func (m *AssetDefinition) Reset() { *m = AssetDefinition{} } -func (m *AssetDefinition) String() string { return proto.CompactTextString(m) } -func (*AssetDefinition) ProtoMessage() {} -func (*AssetDefinition) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } - -func (m *AssetDefinition) GetIssuanceProgram() *Program { - if m != nil { - return m.IssuanceProgram - } - return nil -} - -func (m *AssetDefinition) GetData() *Hash { - if m != nil { - return m.Data - } - return nil -} - type ValueSource struct { Ref *Hash `protobuf:"bytes,1,opt,name=ref" json:"ref,omitempty"` Value *AssetAmount `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` @@ -211,7 +185,7 @@ type ValueSource struct { func (m *ValueSource) Reset() { *m = ValueSource{} } func (m *ValueSource) String() string { return proto.CompactTextString(m) } func (*ValueSource) ProtoMessage() {} -func (*ValueSource) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } +func (*ValueSource) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } func (m *ValueSource) GetRef() *Hash { if m != nil { @@ -243,7 +217,7 @@ type ValueDestination struct { func (m *ValueDestination) Reset() { *m = ValueDestination{} } func (m *ValueDestination) String() string { return proto.CompactTextString(m) } func (*ValueDestination) ProtoMessage() {} -func (*ValueDestination) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } +func (*ValueDestination) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } func (m *ValueDestination) GetRef() *Hash { if m != nil { @@ -280,7 +254,7 @@ type BlockHeader struct { func (m *BlockHeader) Reset() { *m = BlockHeader{} } func (m *BlockHeader) String() string { return proto.CompactTextString(m) } func (*BlockHeader) ProtoMessage() {} -func (*BlockHeader) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } +func (*BlockHeader) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } func (m *BlockHeader) GetVersion() uint64 { if m != nil { @@ -348,7 +322,7 @@ type TxHeader struct { func (m *TxHeader) Reset() { *m = TxHeader{} } func (m *TxHeader) String() string { return proto.CompactTextString(m) } func (*TxHeader) ProtoMessage() {} -func (*TxHeader) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } +func (*TxHeader) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } func (m *TxHeader) GetVersion() uint64 { if m != nil { @@ -385,7 +359,7 @@ type TxVerifyResult struct { func (m *TxVerifyResult) Reset() { *m = TxVerifyResult{} } func (m *TxVerifyResult) String() string { return proto.CompactTextString(m) } func (*TxVerifyResult) ProtoMessage() {} -func (*TxVerifyResult) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} } +func (*TxVerifyResult) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } func (m *TxVerifyResult) GetStatusFail() bool { if m != nil { @@ -402,7 +376,7 @@ type TransactionStatus struct { func (m *TransactionStatus) Reset() { *m = TransactionStatus{} } func (m *TransactionStatus) String() string { return proto.CompactTextString(m) } func (*TransactionStatus) ProtoMessage() {} -func (*TransactionStatus) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} } +func (*TransactionStatus) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} } func (m *TransactionStatus) GetVersion() uint64 { if m != nil { @@ -428,7 +402,7 @@ type Mux struct { func (m *Mux) Reset() { *m = Mux{} } func (m *Mux) String() string { return proto.CompactTextString(m) } func (*Mux) ProtoMessage() {} -func (*Mux) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} } +func (*Mux) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} } func (m *Mux) GetSources() []*ValueSource { if m != nil { @@ -466,7 +440,7 @@ type Coinbase struct { func (m *Coinbase) Reset() { *m = Coinbase{} } func (m *Coinbase) String() string { return proto.CompactTextString(m) } func (*Coinbase) ProtoMessage() {} -func (*Coinbase) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} } +func (*Coinbase) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} } func (m *Coinbase) GetWitnessDestination() *ValueDestination { if m != nil { @@ -491,7 +465,7 @@ type IntraChainOutput struct { func (m *IntraChainOutput) Reset() { *m = IntraChainOutput{} } func (m *IntraChainOutput) String() string { return proto.CompactTextString(m) } func (*IntraChainOutput) ProtoMessage() {} -func (*IntraChainOutput) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} } +func (*IntraChainOutput) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} } func (m *IntraChainOutput) GetSource() *ValueSource { if m != nil { @@ -523,7 +497,7 @@ type CrossChainOutput struct { func (m *CrossChainOutput) Reset() { *m = CrossChainOutput{} } func (m *CrossChainOutput) String() string { return proto.CompactTextString(m) } func (*CrossChainOutput) ProtoMessage() {} -func (*CrossChainOutput) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} } +func (*CrossChainOutput) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} } func (m *CrossChainOutput) GetSource() *ValueSource { if m != nil { @@ -556,7 +530,7 @@ type VoteOutput struct { func (m *VoteOutput) Reset() { *m = VoteOutput{} } func (m *VoteOutput) String() string { return proto.CompactTextString(m) } func (*VoteOutput) ProtoMessage() {} -func (*VoteOutput) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} } +func (*VoteOutput) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} } func (m *VoteOutput) GetSource() *ValueSource { if m != nil { @@ -594,7 +568,7 @@ type Retirement struct { func (m *Retirement) Reset() { *m = Retirement{} } func (m *Retirement) String() string { return proto.CompactTextString(m) } func (*Retirement) ProtoMessage() {} -func (*Retirement) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{16} } +func (*Retirement) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} } func (m *Retirement) GetSource() *ValueSource { if m != nil { @@ -610,62 +584,6 @@ func (m *Retirement) GetOrdinal() uint64 { return 0 } -type Issuance struct { - NonceHash *Hash `protobuf:"bytes,1,opt,name=nonce_hash,json=nonceHash" json:"nonce_hash,omitempty"` - Value *AssetAmount `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` - WitnessDestination *ValueDestination `protobuf:"bytes,3,opt,name=witness_destination,json=witnessDestination" json:"witness_destination,omitempty"` - WitnessAssetDefinition *AssetDefinition `protobuf:"bytes,4,opt,name=witness_asset_definition,json=witnessAssetDefinition" json:"witness_asset_definition,omitempty"` - WitnessArguments [][]byte `protobuf:"bytes,5,rep,name=witness_arguments,json=witnessArguments,proto3" json:"witness_arguments,omitempty"` - Ordinal uint64 `protobuf:"varint,6,opt,name=ordinal" json:"ordinal,omitempty"` -} - -func (m *Issuance) Reset() { *m = Issuance{} } -func (m *Issuance) String() string { return proto.CompactTextString(m) } -func (*Issuance) ProtoMessage() {} -func (*Issuance) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{17} } - -func (m *Issuance) GetNonceHash() *Hash { - if m != nil { - return m.NonceHash - } - return nil -} - -func (m *Issuance) GetValue() *AssetAmount { - if m != nil { - return m.Value - } - return nil -} - -func (m *Issuance) GetWitnessDestination() *ValueDestination { - if m != nil { - return m.WitnessDestination - } - return nil -} - -func (m *Issuance) GetWitnessAssetDefinition() *AssetDefinition { - if m != nil { - return m.WitnessAssetDefinition - } - return nil -} - -func (m *Issuance) GetWitnessArguments() [][]byte { - if m != nil { - return m.WitnessArguments - } - return nil -} - -func (m *Issuance) GetOrdinal() uint64 { - if m != nil { - return m.Ordinal - } - return 0 -} - type Spend struct { SpentOutputId *Hash `protobuf:"bytes,1,opt,name=spent_output_id,json=spentOutputId" json:"spent_output_id,omitempty"` WitnessDestination *ValueDestination `protobuf:"bytes,2,opt,name=witness_destination,json=witnessDestination" json:"witness_destination,omitempty"` @@ -676,7 +594,7 @@ type Spend struct { func (m *Spend) Reset() { *m = Spend{} } func (m *Spend) String() string { return proto.CompactTextString(m) } func (*Spend) ProtoMessage() {} -func (*Spend) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18} } +func (*Spend) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{16} } func (m *Spend) GetSpentOutputId() *Hash { if m != nil { @@ -711,7 +629,6 @@ func init() { proto.RegisterType((*Program)(nil), "bc.Program") proto.RegisterType((*AssetID)(nil), "bc.AssetID") proto.RegisterType((*AssetAmount)(nil), "bc.AssetAmount") - proto.RegisterType((*AssetDefinition)(nil), "bc.AssetDefinition") proto.RegisterType((*ValueSource)(nil), "bc.ValueSource") proto.RegisterType((*ValueDestination)(nil), "bc.ValueDestination") proto.RegisterType((*BlockHeader)(nil), "bc.BlockHeader") @@ -724,71 +641,64 @@ func init() { proto.RegisterType((*CrossChainOutput)(nil), "bc.CrossChainOutput") proto.RegisterType((*VoteOutput)(nil), "bc.VoteOutput") proto.RegisterType((*Retirement)(nil), "bc.Retirement") - proto.RegisterType((*Issuance)(nil), "bc.Issuance") proto.RegisterType((*Spend)(nil), "bc.Spend") } func init() { proto.RegisterFile("bc.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 943 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0xcd, 0x6e, 0x23, 0x45, - 0x10, 0x96, 0xc7, 0x13, 0xdb, 0x29, 0x67, 0xe3, 0xb8, 0xb3, 0xbb, 0x8c, 0x56, 0x8b, 0x88, 0x46, - 0x5a, 0xb2, 0x08, 0x29, 0x4a, 0x9c, 0x05, 0x2e, 0x1c, 0x08, 0x09, 0xcb, 0xfa, 0x10, 0x2d, 0xea, - 0x44, 0xb9, 0x8e, 0xda, 0x9e, 0xb6, 0xdd, 0x62, 0x3c, 0x6d, 0xba, 0x7b, 0x86, 0x6c, 0x5e, 0x81, - 0x33, 0x07, 0x9e, 0x84, 0x47, 0xe0, 0xc4, 0x33, 0x81, 0xba, 0xa6, 0xc7, 0x1e, 0xff, 0x64, 0x7f, - 0x84, 0x10, 0xdc, 0xa6, 0x7e, 0xfa, 0xab, 0xaa, 0xaf, 0xab, 0xaa, 0x07, 0x5a, 0x83, 0xe1, 0xd1, - 0x4c, 0x49, 0x23, 0x89, 0x37, 0x18, 0x86, 0x2f, 0xc1, 0x7f, 0xc5, 0xf4, 0x84, 0xec, 0x82, 0x97, - 0x1f, 0x07, 0xb5, 0x83, 0xda, 0xf3, 0x06, 0xf5, 0xf2, 0x63, 0x94, 0x4f, 0x02, 0xcf, 0xc9, 0x27, - 0x28, 0xf7, 0x82, 0xba, 0x93, 0x7b, 0x28, 0x9f, 0x06, 0xbe, 0x93, 0x4f, 0xc3, 0xaf, 0xa1, 0xf9, - 0x83, 0x92, 0x63, 0xc5, 0xa6, 0xe4, 0x63, 0x80, 0x7c, 0x1a, 0xe5, 0x5c, 0x69, 0x21, 0x53, 0x84, - 0xf4, 0xe9, 0x76, 0x3e, 0xbd, 0x29, 0x14, 0x84, 0x80, 0x3f, 0x94, 0x31, 0x47, 0xec, 0x1d, 0x8a, - 0xdf, 0x61, 0x1f, 0x9a, 0x67, 0x5a, 0x73, 0xd3, 0xbf, 0xf8, 0xc7, 0x89, 0x5c, 0x42, 0x1b, 0xa1, - 0xce, 0xa6, 0x32, 0x4b, 0x0d, 0xf9, 0x14, 0x5a, 0xcc, 0x8a, 0x91, 0x88, 0x11, 0xb4, 0xdd, 0x6b, - 0x1f, 0x0d, 0x86, 0x47, 0x2e, 0x1a, 0x6d, 0xa2, 0xb1, 0x1f, 0x93, 0xc7, 0xd0, 0x60, 0x78, 0x02, - 0x43, 0xf9, 0xd4, 0x49, 0xe1, 0x18, 0x3a, 0xe8, 0x7b, 0xc1, 0x47, 0x22, 0x15, 0xc6, 0x16, 0xf0, - 0x25, 0xec, 0x09, 0xad, 0x33, 0x96, 0x0e, 0x79, 0x34, 0x2b, 0x6a, 0xae, 0x42, 0x3b, 0x1a, 0x68, - 0xa7, 0x74, 0x2a, 0x79, 0x79, 0x0a, 0x7e, 0xcc, 0x0c, 0xc3, 0x00, 0xed, 0x5e, 0xcb, 0xfa, 0x5a, - 0xea, 0x29, 0x6a, 0xc3, 0x04, 0xda, 0x37, 0x2c, 0xc9, 0xf8, 0x95, 0xcc, 0xd4, 0x90, 0x93, 0x27, - 0x50, 0x57, 0x7c, 0xe4, 0x70, 0x17, 0xbe, 0x56, 0x49, 0x9e, 0xc1, 0x56, 0x6e, 0x5d, 0x1d, 0x52, - 0x67, 0x5e, 0x50, 0x51, 0x33, 0x2d, 0xac, 0xe4, 0x09, 0xb4, 0x66, 0x52, 0x63, 0xce, 0xc8, 0x97, - 0x4f, 0xe7, 0x72, 0xf8, 0x13, 0xec, 0x61, 0xb4, 0x0b, 0xae, 0x8d, 0x48, 0x19, 0xd6, 0xf5, 0x2f, - 0x87, 0xfc, 0xcb, 0x83, 0xf6, 0xb7, 0x89, 0x1c, 0xfe, 0xf8, 0x8a, 0xb3, 0x98, 0x2b, 0x12, 0x40, - 0x73, 0xb9, 0x47, 0x4a, 0xd1, 0xde, 0xc5, 0x84, 0x8b, 0xf1, 0x64, 0x7e, 0x17, 0x85, 0x44, 0x5e, - 0x40, 0x77, 0xa6, 0x78, 0x2e, 0x64, 0xa6, 0xa3, 0x81, 0x45, 0xb2, 0x97, 0x5a, 0x5f, 0x49, 0xb7, - 0x53, 0xba, 0x60, 0xac, 0x7e, 0x4c, 0x9e, 0xc2, 0xb6, 0x11, 0x53, 0xae, 0x0d, 0x9b, 0xce, 0xb0, - 0x4f, 0x7c, 0xba, 0x50, 0x90, 0x2f, 0xa0, 0x6b, 0x14, 0x4b, 0x35, 0x1b, 0xda, 0x24, 0x75, 0xa4, - 0xa4, 0x34, 0xc1, 0xd6, 0x0a, 0xe6, 0x5e, 0xd5, 0x85, 0x4a, 0x69, 0xc8, 0x37, 0xf0, 0x51, 0x45, - 0x17, 0x69, 0xc3, 0x4c, 0xa6, 0xa3, 0x09, 0xd3, 0x93, 0xa0, 0xb1, 0x72, 0xf8, 0x51, 0xc5, 0xf1, - 0x0a, 0xfd, 0x70, 0xe0, 0x2e, 0x80, 0xac, 0x23, 0x04, 0x4d, 0x3c, 0xfc, 0xc8, 0x1e, 0xbe, 0x5e, - 0x3d, 0x46, 0xbb, 0x6b, 0x48, 0xe4, 0x73, 0xe8, 0xfe, 0x2c, 0x4c, 0xca, 0xb5, 0x8e, 0x98, 0x1a, - 0x67, 0x53, 0x9e, 0x1a, 0x1d, 0xb4, 0x0e, 0xea, 0xcf, 0x77, 0xe8, 0x9e, 0x33, 0x9c, 0x95, 0xfa, - 0xf0, 0xd7, 0x1a, 0xb4, 0xae, 0x6f, 0xdf, 0x49, 0xff, 0x21, 0x74, 0x34, 0x57, 0x82, 0x25, 0xe2, - 0x8e, 0xc7, 0x91, 0x16, 0x77, 0xdc, 0xdd, 0xc3, 0xee, 0x42, 0x7d, 0x25, 0xee, 0xb8, 0x1d, 0x74, - 0x4b, 0x64, 0xa4, 0x58, 0x3a, 0xe6, 0xee, 0xbe, 0x91, 0x5a, 0x6a, 0x15, 0xe4, 0x10, 0x40, 0x71, - 0x9d, 0x25, 0x76, 0xf6, 0x74, 0xe0, 0x1f, 0xd4, 0x97, 0x68, 0xd9, 0x2e, 0x6c, 0xfd, 0x58, 0x87, - 0x27, 0xb0, 0x7b, 0x7d, 0x7b, 0xc3, 0x95, 0x18, 0xbd, 0xa1, 0xa8, 0x24, 0x9f, 0x40, 0xdb, 0x51, - 0x3a, 0x62, 0x22, 0xc1, 0x04, 0x5b, 0x14, 0x0a, 0xd5, 0x4b, 0x26, 0x92, 0x70, 0x04, 0xdd, 0x35, - 0x7e, 0xde, 0x52, 0xd2, 0x57, 0xf0, 0x20, 0x47, 0xfc, 0x92, 0x67, 0x0f, 0xb3, 0x21, 0xc8, 0xf3, - 0x52, 0x68, 0xba, 0x53, 0x38, 0x16, 0x90, 0xe1, 0x9f, 0x35, 0xa8, 0x5f, 0x66, 0xb7, 0xe4, 0x33, - 0x68, 0x6a, 0x1c, 0x4c, 0x1d, 0xd4, 0xf0, 0x28, 0x4e, 0x40, 0x65, 0x60, 0x69, 0x69, 0x27, 0xcf, - 0xa0, 0x59, 0x6e, 0x05, 0x6f, 0x7d, 0x2b, 0x94, 0x36, 0xf2, 0x3d, 0x3c, 0x2c, 0x6f, 0x2e, 0x5e, - 0x0c, 0xa1, 0x0e, 0xea, 0x08, 0xff, 0x70, 0x0e, 0x5f, 0x99, 0x50, 0xba, 0xef, 0x4e, 0x54, 0x74, - 0xf7, 0xb4, 0x80, 0x7f, 0x4f, 0x0b, 0x48, 0x68, 0x9d, 0x4b, 0x91, 0x0e, 0x98, 0xe6, 0xe4, 0x3b, - 0xd8, 0xdf, 0x90, 0x81, 0x9b, 0xff, 0xcd, 0x09, 0x90, 0xf5, 0x04, 0xec, 0x7c, 0x31, 0x35, 0x10, - 0x46, 0x31, 0xf5, 0xc6, 0x2d, 0xf5, 0x85, 0x22, 0xfc, 0xa5, 0x06, 0x7b, 0xfd, 0xd4, 0x28, 0x76, - 0x3e, 0x61, 0x22, 0x7d, 0x9d, 0x99, 0x59, 0x66, 0xc8, 0x21, 0x34, 0x0a, 0xb6, 0x5c, 0xb0, 0x35, - 0x32, 0x9d, 0x99, 0xbc, 0x80, 0xce, 0x50, 0xa6, 0x46, 0xc9, 0x24, 0x7a, 0x0b, 0xa7, 0xbb, 0xce, - 0xa7, 0x5c, 0xb4, 0x01, 0x34, 0xa5, 0x8a, 0x45, 0xca, 0x12, 0xd7, 0x94, 0xa5, 0x88, 0xd9, 0x9c, - 0x2b, 0xa9, 0xf5, 0xff, 0x22, 0x9b, 0xdf, 0x6a, 0x00, 0x37, 0xd2, 0xf0, 0xff, 0x38, 0x0f, 0xfb, - 0x22, 0xe7, 0xd2, 0x70, 0x5c, 0x8e, 0x3b, 0x14, 0xbf, 0xc3, 0xd7, 0x00, 0x94, 0x1b, 0xa1, 0xb8, - 0xed, 0x9b, 0xf7, 0x4f, 0xad, 0x12, 0xc4, 0x5b, 0x2e, 0xf6, 0x77, 0x0f, 0x5a, 0x7d, 0xf7, 0x22, - 0xda, 0xd5, 0x90, 0x4a, 0xfb, 0x7e, 0xe2, 0xc6, 0x5c, 0x7d, 0x71, 0xb6, 0xd1, 0x86, 0x5b, 0xf2, - 0x3d, 0xdf, 0x9d, 0x7b, 0x5a, 0xb9, 0xfe, 0x81, 0xad, 0x7c, 0x09, 0xc1, 0x7c, 0x94, 0xf0, 0xa7, - 0x21, 0x9e, 0xbf, 0xfa, 0x48, 0x4e, 0xbb, 0xb7, 0x3f, 0x4f, 0x60, 0xf1, 0x43, 0x40, 0x1f, 0x97, - 0x63, 0xb6, 0xf2, 0xa3, 0xb0, 0x71, 0x32, 0xb7, 0x36, 0x4f, 0x66, 0x95, 0xb9, 0xc6, 0x32, 0x73, - 0x7f, 0xd4, 0x60, 0xeb, 0x6a, 0xc6, 0xd3, 0x98, 0x1c, 0x43, 0x47, 0xcf, 0x78, 0x6a, 0x22, 0x89, - 0x1d, 0xb3, 0xf8, 0xa7, 0x59, 0x70, 0xf7, 0x00, 0x1d, 0x8a, 0x8e, 0xea, 0xc7, 0xf7, 0x11, 0xe3, - 0x7d, 0x20, 0x31, 0x1b, 0x2b, 0xa9, 0xbf, 0xbb, 0x12, 0x7f, 0xa9, 0x92, 0x41, 0x03, 0xff, 0x3b, - 0x4f, 0xff, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x9e, 0xe2, 0x40, 0x89, 0x83, 0x0a, 0x00, 0x00, + // 835 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0xcf, 0x6f, 0xe4, 0x34, + 0x14, 0xd6, 0x4c, 0xd2, 0x49, 0xfa, 0xa6, 0xdb, 0xe9, 0x78, 0x77, 0x21, 0x5a, 0x81, 0xa8, 0x22, + 0x2d, 0x5d, 0x84, 0x54, 0xf5, 0xc7, 0x22, 0x2e, 0x1c, 0x28, 0x2d, 0xcb, 0xce, 0x61, 0xb5, 0xc8, + 0xad, 0x7a, 0x8d, 0x3c, 0x89, 0xdb, 0xb1, 0xc8, 0xc4, 0xc1, 0x76, 0x42, 0xb7, 0xff, 0x02, 0x67, + 0x0e, 0xfc, 0x45, 0x9c, 0xf8, 0x9b, 0x40, 0x7e, 0x71, 0x3a, 0x99, 0x4e, 0x5b, 0x40, 0x08, 0xb1, + 0xb7, 0x79, 0xcf, 0xef, 0x7d, 0xef, 0xf3, 0x67, 0x7f, 0xce, 0x40, 0x38, 0x4d, 0x77, 0x4b, 0x25, + 0x8d, 0x24, 0xfd, 0x69, 0x1a, 0xbf, 0x02, 0xff, 0x35, 0xd3, 0x33, 0xb2, 0x09, 0xfd, 0x7a, 0x2f, + 0xea, 0x6d, 0xf7, 0x5e, 0x0c, 0x68, 0xbf, 0xde, 0xc3, 0x78, 0x3f, 0xea, 0xbb, 0x78, 0x1f, 0xe3, + 0x83, 0xc8, 0x73, 0xf1, 0x01, 0xc6, 0x87, 0x91, 0xef, 0xe2, 0xc3, 0xf8, 0x2b, 0x08, 0xbe, 0x57, + 0xf2, 0x52, 0xb1, 0x39, 0xf9, 0x18, 0xa0, 0x9e, 0x27, 0x35, 0x57, 0x5a, 0xc8, 0x02, 0x21, 0x7d, + 0xba, 0x5e, 0xcf, 0xcf, 0x9b, 0x04, 0x21, 0xe0, 0xa7, 0x32, 0xe3, 0x88, 0xbd, 0x41, 0xf1, 0x77, + 0x3c, 0x81, 0xe0, 0x48, 0x6b, 0x6e, 0x26, 0x27, 0xff, 0x9a, 0xc8, 0x1b, 0x18, 0x22, 0xd4, 0xd1, + 0x5c, 0x56, 0x85, 0x21, 0x9f, 0x42, 0xc8, 0x6c, 0x98, 0x88, 0x0c, 0x41, 0x87, 0x07, 0xc3, 0xdd, + 0x69, 0xba, 0xeb, 0xa6, 0xd1, 0x00, 0x17, 0x27, 0x19, 0xf9, 0x00, 0x06, 0x0c, 0x3b, 0x70, 0x94, + 0x4f, 0x5d, 0x14, 0xe7, 0x30, 0x3c, 0x67, 0x79, 0xc5, 0x4f, 0x65, 0xa5, 0x52, 0x4e, 0x9e, 0x81, + 0xa7, 0xf8, 0x85, 0x43, 0x0a, 0x2d, 0x92, 0x55, 0x8f, 0xda, 0x24, 0x79, 0x0e, 0x6b, 0xb5, 0x2d, + 0x45, 0x84, 0xe1, 0xc1, 0xe8, 0x66, 0x4e, 0x43, 0x85, 0x36, 0xab, 0xe4, 0x19, 0x84, 0xa5, 0xd4, + 0xc2, 0x58, 0x71, 0x3c, 0x9c, 0x75, 0x13, 0xc7, 0x3f, 0xc2, 0x16, 0x4e, 0x3b, 0xe1, 0xda, 0x88, + 0x82, 0xd9, 0xdc, 0x7f, 0x3d, 0xf2, 0x8f, 0x3e, 0x0c, 0xbf, 0xc9, 0x65, 0xfa, 0xc3, 0x6b, 0xce, + 0x32, 0xae, 0x48, 0x04, 0xc1, 0xf2, 0xd1, 0xb5, 0xa1, 0x95, 0x68, 0xc6, 0xc5, 0xe5, 0xec, 0x46, + 0xa2, 0x26, 0x22, 0x2f, 0x61, 0x5c, 0x2a, 0x5e, 0x0b, 0x59, 0xe9, 0x64, 0x6a, 0x91, 0xac, 0xd6, + 0xde, 0x2d, 0xba, 0xa3, 0xb6, 0x04, 0x67, 0x4d, 0x32, 0xf2, 0x11, 0xac, 0x1b, 0x31, 0xe7, 0xda, + 0xb0, 0x79, 0x89, 0xc7, 0xe7, 0xd3, 0x45, 0x82, 0x7c, 0x01, 0x63, 0xa3, 0x58, 0xa1, 0x59, 0x6a, + 0x49, 0xea, 0x44, 0x49, 0x69, 0xa2, 0xb5, 0x5b, 0x98, 0x5b, 0xdd, 0x12, 0x2a, 0xa5, 0x21, 0x5f, + 0xc3, 0x87, 0x9d, 0x5c, 0xa2, 0x0d, 0x33, 0x95, 0x4e, 0x66, 0x4c, 0xcf, 0xa2, 0xc1, 0xad, 0xe6, + 0xa7, 0x9d, 0xc2, 0x53, 0xac, 0x43, 0x1f, 0x9c, 0x00, 0x59, 0x45, 0x88, 0x02, 0x6c, 0x7e, 0x6a, + 0x9b, 0xcf, 0x6e, 0xb7, 0xd1, 0xf1, 0x0a, 0x12, 0xf9, 0x1c, 0xc6, 0x3f, 0x09, 0x53, 0x70, 0xad, + 0x13, 0xa6, 0x2e, 0xab, 0x39, 0x2f, 0x8c, 0x8e, 0xc2, 0x6d, 0xef, 0xc5, 0x06, 0xdd, 0x72, 0x0b, + 0x47, 0x6d, 0x3e, 0xfe, 0xa5, 0x07, 0xe1, 0xd9, 0xd5, 0x5f, 0xca, 0xbf, 0x03, 0x23, 0xcd, 0x95, + 0x60, 0xb9, 0xb8, 0xe6, 0x59, 0xa2, 0xc5, 0x35, 0x77, 0xe7, 0xb0, 0xb9, 0x48, 0x9f, 0x8a, 0x6b, + 0x6e, 0xfd, 0x67, 0x85, 0x4c, 0x14, 0x2b, 0x2e, 0xb9, 0x3b, 0x6f, 0x94, 0x96, 0xda, 0x04, 0xd9, + 0x01, 0x50, 0x5c, 0x57, 0xb9, 0xb5, 0x84, 0x8e, 0xfc, 0x6d, 0x6f, 0x49, 0x96, 0xf5, 0x66, 0x6d, + 0x92, 0xe9, 0x78, 0x1f, 0x36, 0xcf, 0xae, 0xce, 0xb9, 0x12, 0x17, 0xef, 0x28, 0x26, 0xc9, 0x27, + 0x30, 0x74, 0x92, 0x5e, 0x30, 0x91, 0x23, 0xc1, 0x90, 0x42, 0x93, 0x7a, 0xc5, 0x44, 0x1e, 0x5f, + 0xc0, 0x78, 0x45, 0x9f, 0x07, 0xb6, 0xf4, 0x25, 0x3c, 0xaa, 0x11, 0xbf, 0xd5, 0xb9, 0x8f, 0x6c, + 0x08, 0xea, 0xbc, 0x34, 0x9a, 0x6e, 0x34, 0x85, 0x0d, 0x64, 0xfc, 0x7b, 0x0f, 0xbc, 0x37, 0xd5, + 0x15, 0xf9, 0x0c, 0x02, 0x8d, 0xc6, 0xd4, 0x51, 0x0f, 0x5b, 0xd1, 0x01, 0x1d, 0xc3, 0xd2, 0x76, + 0x9d, 0x3c, 0x87, 0xa0, 0x6c, 0x1e, 0x28, 0x67, 0x16, 0x7c, 0x07, 0xdc, 0x9b, 0x45, 0xdb, 0x35, + 0xf2, 0x1d, 0x3c, 0x69, 0x4f, 0x2e, 0x5b, 0x98, 0x50, 0x47, 0x1e, 0xc2, 0x3f, 0xb9, 0x81, 0xef, + 0x38, 0x94, 0x3e, 0x76, 0x1d, 0x9d, 0xdc, 0x3d, 0x57, 0xc0, 0xbf, 0xe7, 0x0a, 0x48, 0x08, 0x8f, + 0xa5, 0x28, 0xa6, 0x4c, 0x73, 0xf2, 0x2d, 0x3c, 0xbe, 0x83, 0x81, 0xf3, 0xff, 0xdd, 0x04, 0xc8, + 0x2a, 0x01, 0xeb, 0x2f, 0xa6, 0xa6, 0xc2, 0x28, 0xa6, 0xde, 0xb9, 0xb7, 0x76, 0x91, 0x88, 0x7f, + 0xee, 0xc1, 0xd6, 0xa4, 0x30, 0x8a, 0x1d, 0xcf, 0x98, 0x28, 0xde, 0x56, 0xa6, 0xac, 0x0c, 0xd9, + 0x81, 0x41, 0xa3, 0x96, 0x1b, 0xb6, 0x22, 0xa6, 0x5b, 0x26, 0x2f, 0x61, 0x94, 0xca, 0xc2, 0x28, + 0x99, 0x27, 0x0f, 0x68, 0xba, 0xe9, 0x6a, 0xda, 0xef, 0x42, 0x04, 0x81, 0x54, 0x99, 0x28, 0x58, + 0xee, 0x2e, 0x65, 0x1b, 0x22, 0x9b, 0x63, 0x25, 0xb5, 0x7e, 0x2f, 0xd8, 0xfc, 0xda, 0x03, 0x38, + 0x97, 0x86, 0xff, 0xcf, 0x3c, 0xec, 0x87, 0xb2, 0x96, 0x86, 0xe3, 0xe3, 0xb8, 0x41, 0xf1, 0x77, + 0xfc, 0x16, 0x80, 0x72, 0x23, 0x14, 0xb7, 0xf7, 0xe6, 0xef, 0x53, 0xeb, 0x0c, 0xe9, 0x2f, 0x6f, + 0xf6, 0xb7, 0x1e, 0xac, 0x9d, 0x96, 0xbc, 0xc8, 0xc8, 0x1e, 0x8c, 0x74, 0xc9, 0x0b, 0x93, 0x48, + 0xdc, 0xf7, 0xe2, 0x83, 0xb9, 0x78, 0x1c, 0x1e, 0x61, 0x41, 0xa3, 0xcb, 0x24, 0xbb, 0xef, 0xa6, + 0xf6, 0xff, 0xe1, 0x4d, 0xbd, 0xd3, 0x29, 0xde, 0xdd, 0x4e, 0xe9, 0xee, 0xc4, 0x5f, 0xda, 0xc9, + 0x74, 0x80, 0x7f, 0x6a, 0x0e, 0xff, 0x0c, 0x00, 0x00, 0xff, 0xff, 0xc7, 0x32, 0xe6, 0x29, 0xe0, + 0x08, 0x00, 0x00, } diff --git a/protocol/bc/bc.proto b/protocol/bc/bc.proto index 0aba4b7b..254285ff 100644 --- a/protocol/bc/bc.proto +++ b/protocol/bc/bc.proto @@ -31,11 +31,6 @@ message AssetAmount { uint64 amount = 2; } -message AssetDefinition { - Program issuance_program = 1; - Hash data = 2; -} - message ValueSource { Hash ref = 1; AssetAmount value = 2; @@ -111,15 +106,6 @@ message Retirement { uint64 ordinal = 2; } -message Issuance { - Hash nonce_hash = 1; - AssetAmount value = 2; - ValueDestination witness_destination = 3; - AssetDefinition witness_asset_definition = 4; - repeated bytes witness_arguments = 5; - uint64 ordinal = 6; -} - message Spend { Hash spent_output_id = 1; ValueDestination witness_destination = 2; diff --git a/protocol/bc/entry_test.go b/protocol/bc/entry_test.go index 80e4d51c..3bcc9e13 100644 --- a/protocol/bc/entry_test.go +++ b/protocol/bc/entry_test.go @@ -9,7 +9,6 @@ func BenchmarkEntryID(b *testing.B) { m := NewMux([]*ValueSource{{Position: 1}}, &Program{Code: []byte{1}, VmVersion: 1}) entries := []Entry{ - NewIssuance(nil, &AssetAmount{}, 0), m, NewTxHeader(1, 1, 0, nil), NewIntraChainOutput(&ValueSource{}, &Program{Code: []byte{1}, VmVersion: 1}, 0), @@ -33,10 +32,6 @@ func TestEntryID(t *testing.T) { expectEntryID string }{ { - entry: NewIssuance(&Hash{V0: 0, V1: 1, V2: 2, V3: 3}, &AssetAmount{&AssetID{V0: 1, V1: 2, V2: 3, V3: 4}, 100}, 1), - expectEntryID: "3012b9b6da3962bb2388cdf5db7f3b93a2b696fcc70e79bc5da1238a6d66ae73", - }, - { entry: NewMux( []*ValueSource{ { diff --git a/protocol/bc/issuance.go b/protocol/bc/issuance.go deleted file mode 100644 index 34811de9..00000000 --- a/protocol/bc/issuance.go +++ /dev/null @@ -1,30 +0,0 @@ -package bc - -import "io" - -// Issuance is a source of new value on a blockchain. It satisfies the -// Entry interface. - -func (Issuance) typ() string { return "issuance1" } -func (iss *Issuance) writeForHash(w io.Writer) { - mustWriteForHash(w, iss.NonceHash) - mustWriteForHash(w, iss.Value) -} - -// SetDestination will link the issuance to the output -func (iss *Issuance) SetDestination(id *Hash, val *AssetAmount, pos uint64) { - iss.WitnessDestination = &ValueDestination{ - Ref: id, - Value: val, - Position: pos, - } -} - -// NewIssuance creates a new Issuance. -func NewIssuance(nonceHash *Hash, value *AssetAmount, ordinal uint64) *Issuance { - return &Issuance{ - NonceHash: nonceHash, - Value: value, - Ordinal: ordinal, - } -} diff --git a/protocol/bc/tx.go b/protocol/bc/tx.go index 9b00d390..a01eea50 100644 --- a/protocol/bc/tx.go +++ b/protocol/bc/tx.go @@ -81,19 +81,6 @@ func (tx *Tx) Spend(id Hash) (*Spend, error) { return sp, nil } -// Issuance try to get the issuance entry by given hash -func (tx *Tx) Issuance(id Hash) (*Issuance, error) { - e, ok := tx.Entries[id] - if !ok || e == nil { - return nil, errors.Wrapf(ErrMissingEntry, "id %x", id.Bytes()) - } - iss, ok := e.(*Issuance) - if !ok { - return nil, errors.Wrapf(ErrEntryType, "entry %x has unexpected type %T", id.Bytes(), e) - } - return iss, nil -} - // VoteOutput try to get the vote output entry by given hash func (tx *Tx) VoteOutput(id Hash) (*VoteOutput, error) { e, ok := tx.Entries[id] diff --git a/protocol/bc/types/block_test.go b/protocol/bc/types/block_test.go deleted file mode 100644 index 16c0070d..00000000 --- a/protocol/bc/types/block_test.go +++ /dev/null @@ -1,223 +0,0 @@ -package types - -import ( - "bytes" - "encoding/hex" - "encoding/json" - "strings" - "testing" - - "github.com/davecgh/go-spew/spew" - - "github.com/vapor/consensus" - "github.com/vapor/encoding/blockchain" - "github.com/vapor/protocol/bc" - "github.com/vapor/testutil" -) - -func TestBlock(t *testing.T) { - cases := []struct { - block *Block - hex string - hash bc.Hash - }{ - { - block: &Block{ - BlockHeader: BlockHeader{ - Version: 1, - Height: 1, - }, - Transactions: []*Tx{}, - }, - hex: strings.Join([]string{ - "03", // serialization flags - "01", // version - "01", // block height - "0000000000000000000000000000000000000000000000000000000000000000", // prev block hash - "00", // timestamp - "40", // commitment extensible field length - "0000000000000000000000000000000000000000000000000000000000000000", // transactions merkle root - "0000000000000000000000000000000000000000000000000000000000000000", // tx status hash - "0100", //BlockWitness - "00", // num transactions - }, ""), - hash: testutil.MustDecodeHash("ba63a0f8e9a7e5f93e3ec7ce49f07276c065bdf75e270984d9390bee0b3de027"), - }, - { - block: &Block{ - BlockHeader: BlockHeader{ - Version: 1, - Height: 432234, - PreviousBlockHash: testutil.MustDecodeHash("c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0"), - Timestamp: 1522908275, - BlockCommitment: BlockCommitment{ - TransactionStatusHash: testutil.MustDecodeHash("b94301ea4e316bee00109f68d25beaca90aeff08e9bf439a37d91d7a3b5a1470"), - TransactionsMerkleRoot: testutil.MustDecodeHash("ad9ac003d08ff305181a345d64fe0b02311cc1a6ec04ab73f3318d90139bfe03"), - }, - BlockWitness: BlockWitness{Witness: [][]byte{[]byte{0xbe, 0xef}}}, - }, - Transactions: []*Tx{ - NewTx(TxData{ - Version: 1, - SerializedSize: uint64(263), - TimeRange: 654, - Inputs: []*TxInput{ - NewIssuanceInput([]byte("nonce"), 254354, []byte("issuanceProgram"), [][]byte{[]byte("arguments1"), []byte("arguments2")}, []byte("assetDefinition")), - NewSpendInput([][]byte{[]byte("arguments3"), []byte("arguments4")}, testutil.MustDecodeHash("fad5195a0c8e3b590b86a3c0a95e7529565888508aecca96e9aeda633002f409"), *consensus.BTMAssetID, 254354, 3, []byte("spendProgram")), - }, - Outputs: []*TxOutput{ - NewIntraChainOutput(testutil.MustDecodeAsset("a69849e11add96ac7053aad22ba2349a4abf5feb0475a0afcadff4e128be76cf"), 254354, []byte("true")), - }, - }), - NewTx(TxData{ - Version: 1, - SerializedSize: uint64(112), - Inputs: []*TxInput{ - NewCoinbaseInput([]byte("arbitrary")), - }, - Outputs: []*TxOutput{ - NewIntraChainOutput(*consensus.BTMAssetID, 254354, []byte("true")), - NewIntraChainOutput(*consensus.BTMAssetID, 254354, []byte("false")), - }, - }), - }, - }, - hex: strings.Join([]string{ - "03", // serialization flags - "01", // version - "eab01a", // block height - "c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0", // prev block hash - "f3f896d605", // timestamp - "40", // commitment extensible field length - "ad9ac003d08ff305181a345d64fe0b02311cc1a6ec04ab73f3318d90139bfe03", // transactions merkle root - "b94301ea4e316bee00109f68d25beaca90aeff08e9bf439a37d91d7a3b5a1470", // tx status hash - "040102beef", //BlockWitness - "02", // num transactions - "07018e0502012a00056e6f6e6365a69849e11add96ac7053aad22ba2349a4abf5feb0475a0afcadff4e128be76cf92c30f380f6173736574446566696e6974696f6e010f69737375616e636550726f6772616d020a617267756d656e7473310a617267756d656e74733201540152fad5195a0c8e3b590b86a3c0a95e7529565888508aecca96e9aeda633002f409ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff92c30f03010c7370656e6450726f6772616d17020a617267756d656e7473330a617267756d656e74733401012b0029a69849e11add96ac7053aad22ba2349a4abf5feb0475a0afcadff4e128be76cf92c30f01047472756500", - "07010001010b02096172626974726172790002012b0029ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff92c30f01047472756500012c002affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff92c30f010566616c736500", - }, ""), - hash: testutil.MustDecodeHash("fca0cfd96604b0b28e4a16286974db155d0bbd42dd729d2e2ba058d09a963016"), - }, - } - - for i, test := range cases { - got := testutil.Serialize(t, test.block) - want, err := hex.DecodeString(test.hex) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(got, want) { - t.Errorf("test %d: bytes = %x want %x", i, got, want) - } - - blockHash := test.block.Hash() - if blockHash != test.hash { - t.Errorf("test %d: hash = %s want %s", i, blockHash.String(), test.hash.String()) - } - - blockJSON, err := json.Marshal(test.block) - if err != nil { - t.Errorf("test %d: error marshaling block to json: %s", i, err) - } - - blockFromJSON := Block{} - if err := json.Unmarshal(blockJSON, &blockFromJSON); err != nil { - t.Errorf("test %d: error unmarshaling block from json: %s", i, err) - } - if !testutil.DeepEqual(*test.block, blockFromJSON) { - t.Errorf("test %d: got:\n%s\nwant:\n%s", i, spew.Sdump(blockFromJSON), spew.Sdump(*test.block)) - } - } -} - -func TestReadFrom(t *testing.T) { - btmAssetID := testutil.MustDecodeAsset("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") - - cases := []struct { - rawBlock string - wantBlock Block - }{ - { - rawBlock: "03018b5f3077f24528e94ecfc4491bb2e9ed6264a632a9a4b86b00c88093ca545d14a137d4f5e1e4054035a2d11158f47a5c5267630b2b6cf9e9a5f79a598085a2572a68defeb8013ad26978a65b4ee5b6f4914fe5c05000459a803ecf59132604e5d334d64249c5e50a010002070100010108020600313231373100010140003effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff809df3b49a010116001437e1aec83a4e6587ca9609e4e5aa728db700744900070100020160015e4b5cb973f5bef4eadde4c89b92ee73312b940e84164da0594149554cc8a2adeaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80c480c1240201160014cb9f2391bafe2bc1159b2c4c8a0f17ba1b4dd94e6302405760b15cc09e543437c4e3aad05bf073e82ebdb214beccb5f4473653dfc0a9d5ae59fb149de19eb71c1c1399594757aeea4dd6327ca2790ef919bd20caa86104201381d35e235813ad1e62f9a602c82abee90565639cc4573568206b55bcd2aed90130000840142084606f20ca7b38dc897329a288ea31031724f5c55bcafec80468a546955023380af2faad1480d0dbc3f402b001467b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d0125ae2054a71277cc162eb3eb21b5bd9fe54402829a53b294deaed91692a2cd8a081f9c5151ad0140621c2c3554da50d2a492d9d78be7c6159359d8f5f0b93a054ce0133617a61d85c532aff449b97a3ec2804ca5fe12b4d54aa6e8c3215c33d04abee9c9abdfdb0302013f003dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80c0d1e123011600144b61da45324299e40dacc255e2ea07dfce3a56d2000140003e7b38dc897329a288ea31031724f5c55bcafec80468a546955023380af2faad1480d0dbc3f4020116001437e1aec83a4e6587ca9609e4e5aa728db700744900", - wantBlock: Block{ - BlockHeader: BlockHeader{ - Version: 1, - Height: 12171, - PreviousBlockHash: testutil.MustDecodeHash("3077f24528e94ecfc4491bb2e9ed6264a632a9a4b86b00c88093ca545d14a137"), - Timestamp: 1553496788, - BlockCommitment: BlockCommitment{ - TransactionsMerkleRoot: testutil.MustDecodeHash("35a2d11158f47a5c5267630b2b6cf9e9a5f79a598085a2572a68defeb8013ad2"), - TransactionStatusHash: testutil.MustDecodeHash("6978a65b4ee5b6f4914fe5c05000459a803ecf59132604e5d334d64249c5e50a"), - }, - }, - Transactions: []*Tx{ - { - TxData: TxData{ - Version: 1, - SerializedSize: 83, - TimeRange: 0, - Inputs: []*TxInput{ - NewCoinbaseInput(testutil.MustDecodeHexString("003132313731")), - }, - Outputs: []*TxOutput{ - NewIntraChainOutput(btmAssetID, 41450000000, testutil.MustDecodeHexString("001437e1aec83a4e6587ca9609e4e5aa728db7007449")), - }, - }, - }, - { - TxData: TxData{ - Version: 1, - SerializedSize: 564, - TimeRange: 0, - Inputs: []*TxInput{ - NewSpendInput( - [][]byte{ - testutil.MustDecodeHexString("5760b15cc09e543437c4e3aad05bf073e82ebdb214beccb5f4473653dfc0a9d5ae59fb149de19eb71c1c1399594757aeea4dd6327ca2790ef919bd20caa86104"), - testutil.MustDecodeHexString("1381d35e235813ad1e62f9a602c82abee90565639cc4573568206b55bcd2aed9"), - }, - testutil.MustDecodeHash("4b5cb973f5bef4eadde4c89b92ee73312b940e84164da0594149554cc8a2adea"), - btmAssetID, - 9800000000, - 2, - testutil.MustDecodeHexString("0014cb9f2391bafe2bc1159b2c4c8a0f17ba1b4dd94e"), - ), - NewIssuanceInput( - testutil.MustDecodeHexString("40142084606f20ca"), - 100000000000, - testutil.MustDecodeHexString("ae2054a71277cc162eb3eb21b5bd9fe54402829a53b294deaed91692a2cd8a081f9c5151ad"), - [][]byte{testutil.MustDecodeHexString("621c2c3554da50d2a492d9d78be7c6159359d8f5f0b93a054ce0133617a61d85c532aff449b97a3ec2804ca5fe12b4d54aa6e8c3215c33d04abee9c9abdfdb03")}, - testutil.MustDecodeHexString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"), - ), - }, - Outputs: []*TxOutput{ - NewIntraChainOutput(btmAssetID, 9600000000, testutil.MustDecodeHexString("00144b61da45324299e40dacc255e2ea07dfce3a56d2")), - NewIntraChainOutput(testutil.MustDecodeAsset("7b38dc897329a288ea31031724f5c55bcafec80468a546955023380af2faad14"), 100000000000, testutil.MustDecodeHexString("001437e1aec83a4e6587ca9609e4e5aa728db7007449")), - }, - }, - }, - }, - }, - }, - } - - for _, c := range cases { - blockBytes, err := hex.DecodeString(c.rawBlock) - if err != nil { - t.Fatal(err) - } - - block := &Block{} - if err := block.readFrom(blockchain.NewReader(blockBytes)); err != nil { - t.Fatal(err) - } - - for _, tx := range c.wantBlock.Transactions { - tx.Tx = MapTx(&tx.TxData) - } - - if !testutil.DeepEqual(*block, c.wantBlock) { - t.Errorf("test block read from fail, got:%v, want:%v", *block, c.wantBlock) - } - } -} diff --git a/protocol/bc/types/issuance.go b/protocol/bc/types/issuance.go deleted file mode 100644 index e171fe14..00000000 --- a/protocol/bc/types/issuance.go +++ /dev/null @@ -1,59 +0,0 @@ -package types - -import ( - "github.com/vapor/crypto/sha3pool" - "github.com/vapor/protocol/bc" -) - -// IssuanceInput satisfies the TypedInput interface and represents a issuance. -type IssuanceInput struct { - Nonce []byte - Amount uint64 - - AssetDefinition []byte - VMVersion uint64 - IssuanceProgram []byte - Arguments [][]byte -} - -// NewIssuanceInput create a new IssuanceInput struct. -func NewIssuanceInput(nonce []byte, amount uint64, issuanceProgram []byte, arguments [][]byte, assetDefinition []byte) *TxInput { - return &TxInput{ - AssetVersion: 1, - TypedInput: &IssuanceInput{ - Nonce: nonce, - Amount: amount, - AssetDefinition: assetDefinition, - VMVersion: 1, - IssuanceProgram: issuanceProgram, - Arguments: arguments, - }, - } -} - -// InputType is the interface function for return the input type. -func (ii *IssuanceInput) InputType() uint8 { return IssuanceInputType } - -// AssetID calculate the assetID of the issuance input. -func (ii *IssuanceInput) AssetID() bc.AssetID { - defhash := ii.AssetDefinitionHash() - return bc.ComputeAssetID(ii.IssuanceProgram, ii.VMVersion, &defhash) -} - -// AssetDefinitionHash return the hash of the issuance asset definition. -func (ii *IssuanceInput) AssetDefinitionHash() (defhash bc.Hash) { - sha := sha3pool.Get256() - defer sha3pool.Put256(sha) - sha.Write(ii.AssetDefinition) - defhash.ReadFrom(sha) - return defhash -} - -// NonceHash return the hash of the issuance asset definition. -func (ii *IssuanceInput) NonceHash() (hash bc.Hash) { - sha := sha3pool.Get256() - defer sha3pool.Put256(sha) - sha.Write(ii.Nonce) - hash.ReadFrom(sha) - return hash -} diff --git a/protocol/bc/types/map.go b/protocol/bc/types/map.go index 34ba49cb..b4a4ff07 100644 --- a/protocol/bc/types/map.go +++ b/protocol/bc/types/map.go @@ -24,9 +24,6 @@ func MapTx(oldTx *TxData) *bc.Tx { for id, e := range entries { var ord uint64 switch e := e.(type) { - case *bc.Issuance: - ord = e.Ordinal - case *bc.Spend: ord = e.Ordinal spentOutputIDs[*e.SpentOutputId] = true @@ -63,36 +60,13 @@ func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash } var ( - spends []*bc.Spend - issuances []*bc.Issuance - coinbase *bc.Coinbase + spends []*bc.Spend + coinbase *bc.Coinbase ) muxSources := make([]*bc.ValueSource, len(tx.Inputs)) for i, input := range tx.Inputs { switch inp := input.TypedInput.(type) { - case *IssuanceInput: - nonceHash := inp.NonceHash() - assetDefHash := inp.AssetDefinitionHash() - value := input.AssetAmount() - - issuance := bc.NewIssuance(&nonceHash, &value, uint64(i)) - issuance.WitnessAssetDefinition = &bc.AssetDefinition{ - Data: &assetDefHash, - IssuanceProgram: &bc.Program{ - VmVersion: inp.VMVersion, - Code: inp.IssuanceProgram, - }, - } - issuance.WitnessArguments = inp.Arguments - issuanceID := addEntry(issuance) - - muxSources[i] = &bc.ValueSource{ - Ref: &issuanceID, - Value: &value, - } - issuances = append(issuances, issuance) - case *SpendInput: // create entry for prevout prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram} @@ -135,9 +109,6 @@ func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash spentOutput := entryMap[*spend.SpentOutputId].(*bc.IntraChainOutput) spend.SetDestination(&muxID, spentOutput.Source.Value, spend.Ordinal) } - for _, issuance := range issuances { - issuance.SetDestination(&muxID, issuance.Value, issuance.Ordinal) - } if coinbase != nil { coinbase.SetDestination(&muxID, mux.Sources[0].Value, 0) diff --git a/protocol/bc/types/map_test.go b/protocol/bc/types/map_test.go index 724ae496..e0dfe074 100644 --- a/protocol/bc/types/map_test.go +++ b/protocol/bc/types/map_test.go @@ -21,24 +21,6 @@ func TestMapSpendTx(t *testing.T) { NewIntraChainOutput(*consensus.BTMAssetID, 80, []byte{1}), }, }, - &TxData{ - Inputs: []*TxInput{ - NewIssuanceInput([]byte("nonce"), 254354, []byte("issuanceProgram"), [][]byte{[]byte("arguments1"), []byte("arguments2")}, []byte("assetDefinition")), - }, - Outputs: []*TxOutput{ - NewIntraChainOutput(*consensus.BTMAssetID, 80, []byte{1}), - }, - }, - &TxData{ - Inputs: []*TxInput{ - NewIssuanceInput([]byte("nonce"), 254354, []byte("issuanceProgram"), [][]byte{[]byte("arguments1"), []byte("arguments2")}, []byte("assetDefinition")), - NewSpendInput(nil, testutil.MustDecodeHash("db7b16ac737440d6e38559996ddabb207d7ce84fbd6f3bfd2525d234761dc863"), *consensus.BTMAssetID, 88, 3, []byte{1}), - }, - Outputs: []*TxOutput{ - NewIntraChainOutput(*consensus.BTMAssetID, 80, []byte{1}), - NewIntraChainOutput(*consensus.BTMAssetID, 80, []byte{1}), - }, - }, } for _, txData := range cases { @@ -53,10 +35,6 @@ func TestMapSpendTx(t *testing.T) { t.Errorf("entryMap contains nothing for tx.InputIDs[%d] (%x)", i, tx.InputIDs[i].Bytes()) } switch newInput := resultEntry.(type) { - case *bc.Issuance: - if *newInput.Value.AssetId != oldIn.AssetID() || newInput.Value.Amount != oldIn.Amount() { - t.Errorf("tx.InputIDs[%d]'s asset amount is not equal after map'", i) - } case *bc.Spend: spendOut, err := tx.IntraChainOutput(*newInput.SpentOutputId) if err != nil { diff --git a/protocol/bc/types/merkle_test.go b/protocol/bc/types/merkle_test.go index 68dcb7d2..2cc7bbee 100644 --- a/protocol/bc/types/merkle_test.go +++ b/protocol/bc/types/merkle_test.go @@ -2,10 +2,8 @@ package types import ( "encoding/hex" - "math/rand" "testing" - "time" "github.com/vapor/protocol/bc" "github.com/vapor/protocol/vm" @@ -81,45 +79,13 @@ func TestMerkleRoot(t *testing.T) { } } -func TestMerkleRootRealTx(t *testing.T) { - rawTxs := []string{ - "070100010160015e5ac79a73db78e5c9215b37cb752f0147d1157c542bb4884908ceb97abc33fe0affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0f280d42b0001160014085a02ecdf934a56343aa59a3dec9d9feb86ee43630240035e1ef422b4901997ad3c20c50d82e726d03cb6e8ccb5dddc20e0c09e0a6f2e0055331e2b54d9ec52cffb1c47d8fdf2f8887d55c336753637cbf8f832c7af0b20a29601468f08c57ca9c383d28736a9d5c7737cd483126d8db3d85490fe497b3502013f003dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0aad1b30601160014991b78d1bf731390e2dd838c05ff37ec5146886b00013f003dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8086d8f024011600145ade29df622cc68d0473aa1a20fb89690451c66e00", - "070100020160015e4b5cb973f5bef4eadde4c89b92ee73312b940e84164da0594149554cc8a2adeaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80c480c1240201160014cb9f2391bafe2bc1159b2c4c8a0f17ba1b4dd94e630240d96b8f31519c5e34ef983bb7dfb92e807df7fc1ae5a4c08846d00d4f84ebd2f8634b9e0b0374eb2508d0f989520f622aef051862c26daba0e466944e3d55d00b201381d35e235813ad1e62f9a602c82abee90565639cc4573568206b55bcd2aed901300008ede605460cacbf107b38dc897329a288ea31031724f5c55bcafec80468a546955023380af2faad1480d0dbc3f402b001467b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d0125ae2054a71277cc162eb3eb21b5bd9fe54402829a53b294deaed91692a2cd8a081f9c5151ad01403a54a3ca0210d005cc9bce490478b518c405ba72e0bc1d134b739f29a73e008345229f0e061c420aa3c56a48bc1c9bf592914252ab9100e69252deeac532430f03013f003dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80e0e8f011011600144ab5249140ca4630729030941f59f75e507bd4d5000140003e7b38dc897329a288ea31031724f5c55bcafec80468a546955023380af2faad1480d0dbc3f402011600145ade29df622cc68d0473aa1a20fb89690451c66e00013f003dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80a2c0a012011600145ade29df622cc68d0473aa1a20fb89690451c66e00", - "07010001016c016acf24f1471d67c25a01ac84482ecdd8550229180171cae22321f87fe43d4f6a13ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80b4c4c32101012200200824e931fb806bd77fdcd291aad3bd0a4493443a4120062bd659e64a3e0bac66ef02044059c7a12d006fd34bf8b9b2cb2f99756e5c3c3fdca4c928b830c014819e933b01c92a99bfeb6add73a5087870a3de3465cfed2c99f736b5f77d5fbdc69d91ff0040b95d110d118b873a8232104a6613f0e8c6a791efa3a695c02108cebd5239c8a8471551a48f18ab8ea05d10900b485af5e95b74cd3c01044c1742e71854099c0b40a1b63dae273e3b5b757b7c61286088a934e7282e837d08d62e60d7f75eb739529cd8c6cfef2254d47a546bf8b789657ce0944fec2f7e130c8498e28cae2a9108a901ae20d441b6f375659325a04eede4fc3b74579bb08ccd05b41b99776501e22d6dca7320af6d98ca2c3cd10bf0affbfa6e86609b750523cfadb662ec963c164f05798a49209820b9f1553b03aaebe7e3f9e9222ed7db73b5079b18564042fd3b2cef74156a20271b52de5f554aa4a6f1358f1c2193617bfb3fed4546d13c4af773096a429f9420eeb4a78d8b5cb8283c221ca2d3fd96b8946b3cddee02b7ceffb8f605932588595355ad02014b0049ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80a0d9e61d012200206e8060ef3daca62841802dd9660b24b7dca81c1662b2d68ba8884ecbcd3e1e2200013f003dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80d293ad0301160014ed7d3c466dbc6cc1f3a9af21267ac162f11b30a200", - "070100020161015f4b5cb973f5bef4eadde4c89b92ee73312b940e84164da0594149554cc8a2adea0dafd0f0e42f06f3bf9a8cf5787519d3860650f27a2b3393d34e1fe06e89b469ddc3f8c2f40200011600141da7f908979e521bf2ba12d280b2c84fc1d024416302409524d0d817176eeb718ce45671d95831cdb138d27289aa8a920104e38a8cab8a7dc8cc3fb60d65aa337b719aed0f696fb12610bfe68add89169a47ac1241e0002033444e1b57524161af3899e50fdfe270a90a1ea97fe38e86019a1e252667fb2d0161015fed3181c99ca80db720231aee6948e1183bfe29c64208c1769afa7f938d3b2cf0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff809cd2b0f4020101160014cfbccfac5018ad4b4bfbcb1fab834e3c8503746063024065beb1da2f0840188af0e3c0127b158f7a2a36f1612499694a731df1e3a9d1abe6694c42986b8700aa9856f59cb3692ee88d68b20d1278f05592fb253c58bd0520e5966eee4092eeefdd805b06f2ad368bb9392edec20998993ebe2a929052c1ce030140003e0dafd0f0e42f06f3bf9a8cf5787519d3860650f27a2b3393d34e1fe06e89b469ddfbc8a2cf0201160014583c0323603dd397ba5414255adc80b076cf232b00013f003d0dafd0f0e42f06f3bf9a8cf5787519d3860650f27a2b3393d34e1fe06e89b46980c8afa02501160014fdb3e6abf7f430fdabb53484ca2469103b2af1b5000140003effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80dafa80f4020116001408e75789f47d2a39622e5a940fa918260bf44c5400", - "07010001016d016b1f134a47da4f6df00822935e02a07514718ea99ce5ac4e07bd6c204e098eb525ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808a858fa70200012200206205ec178dc1ac6ea05ea01bb0fcda6aa978173026fa75204a101bdad7bd6b4889010240d8d5bbf4969fba52df8fba06f75c5de0f51b2bd5f902bf234591f90e78bae20bfb5b7904cb83a1d6577c431f644d37722b432df9d64718b8300e3ab74a871a0046ae2068003e53d467b6d81beaf1e7bd9b60a5ffedc79b36ce14ecd1f30a2dcbcd0551200449030407a3a1fa0731f7f784a72c325b5ce4d534fc3cf8fb7140536ba928605152ad02014c004affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80f699b2a302012200209a0b4b27fde7d29d3b465d20eb2e19f4bda3a873d19d11f4cba53958bde92ed000013f003dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80b3ffc40301160014ed7d3c466dbc6cc1f3a9af21267ac162f11b30a200", - } - wantMerkleRoot := "9100f5258bdc059d911b745eada2afb3a64008e91d64e245d7b3729b8909f0c1" - - var txs []*bc.Tx - for i, rawTx := range rawTxs { - tx := Tx{} - if err := tx.UnmarshalText([]byte(rawTx)); err != nil { - t.Fatalf("case#%d, %v", i, err) - } - - txs = append(txs, tx.Tx) - } - - gotMerkleRoot, err := TxMerkleRoot(txs) - if err != nil { - t.Fatal(err) - } - - if wantMerkleRoot != gotMerkleRoot.String() { - t.Errorf("got merkle root:%s, want merkle root:%s", gotMerkleRoot.String(), wantMerkleRoot) - } -} - func TestDuplicateLeaves(t *testing.T) { trueProg := []byte{byte(vm.OP_TRUE)} - assetID := bc.ComputeAssetID(trueProg, 1, &bc.EmptyStringHash) + assetID := bc.AssetID{V0: 9999} txs := make([]*bc.Tx, 6) for i := uint64(0); i < 6; i++ { - now := []byte(time.Now().String()) txs[i] = NewTx(TxData{ Version: 1, - Inputs: []*TxInput{NewIssuanceInput(now, i, trueProg, nil, nil)}, Outputs: []*TxOutput{NewIntraChainOutput(assetID, i, trueProg)}, }).Tx } @@ -145,13 +111,10 @@ func TestDuplicateLeaves(t *testing.T) { func TestAllDuplicateLeaves(t *testing.T) { trueProg := []byte{byte(vm.OP_TRUE)} - assetID := bc.ComputeAssetID(trueProg, 1, &bc.EmptyStringHash) - now := []byte(time.Now().String()) - issuanceInp := NewIssuanceInput(now, 1, trueProg, nil, nil) + assetID := bc.AssetID{V0: 9999} tx := NewTx(TxData{ Version: 1, - Inputs: []*TxInput{issuanceInp}, Outputs: []*TxOutput{NewIntraChainOutput(assetID, 1, trueProg)}, }).Tx tx1, tx2, tx3, tx4, tx5, tx6 := tx, tx, tx, tx, tx, tx @@ -458,13 +421,11 @@ func mockTransactions(txCount int) ([]*Tx, []*bc.Tx) { var txs []*Tx var bcTxs []*bc.Tx trueProg := []byte{byte(vm.OP_TRUE)} - assetID := bc.ComputeAssetID(trueProg, 1, &bc.EmptyStringHash) - for i := 0; i < txCount; i++ { - now := []byte(time.Now().String()) - issuanceInp := NewIssuanceInput(now, 1, trueProg, nil, nil) + assetID := bc.AssetID{V0: 9999} + for i := uint64(0); i < uint64(txCount); i++ { tx := NewTx(TxData{ Version: 1, - Inputs: []*TxInput{issuanceInp}, + Inputs: []*TxInput{NewSpendInput(nil, bc.Hash{V0: i + 1}, assetID, i, i, trueProg)}, Outputs: []*TxOutput{NewIntraChainOutput(assetID, 1, trueProg)}, }) txs = append(txs, tx) diff --git a/protocol/bc/types/transaction.go b/protocol/bc/types/transaction.go index a862762a..383ea30d 100644 --- a/protocol/bc/types/transaction.go +++ b/protocol/bc/types/transaction.go @@ -49,8 +49,6 @@ func (tx *Tx) SetInputArguments(n uint32, args [][]byte) { id := tx.Tx.InputIDs[n] e := tx.Entries[id] switch e := e.(type) { - case *bc.Issuance: - e.WitnessArguments = args case *bc.Spend: e.WitnessArguments = args } diff --git a/protocol/bc/types/transaction_test.go b/protocol/bc/types/transaction_test.go index 993fe5e9..0213ebb9 100644 --- a/protocol/bc/types/transaction_test.go +++ b/protocol/bc/types/transaction_test.go @@ -41,73 +41,6 @@ func TestTransaction(t *testing.T) { { tx: NewTx(TxData{ Version: 1, - SerializedSize: uint64(263), - TimeRange: 654, - Inputs: []*TxInput{ - NewIssuanceInput([]byte("nonce"), 254354, []byte("issuanceProgram"), [][]byte{[]byte("arguments1"), []byte("arguments2")}, []byte("assetDefinition")), - NewSpendInput([][]byte{[]byte("arguments3"), []byte("arguments4")}, testutil.MustDecodeHash("fad5195a0c8e3b590b86a3c0a95e7529565888508aecca96e9aeda633002f409"), *consensus.BTMAssetID, 254354, 3, []byte("spendProgram")), - }, - Outputs: []*TxOutput{ - NewIntraChainOutput(testutil.MustDecodeAsset("a69849e11add96ac7053aad22ba2349a4abf5feb0475a0afcadff4e128be76cf"), 254354, []byte("true")), - }, - }), - hex: strings.Join([]string{ - "07", // serflags - "01", // transaction version - "8e05", // tx time range - "02", // inputs count - "01", // input 0: asset version - "2a", // input 0: serialization length - "00", // input 0: issuance type flag - "05", // input 0: nonce length - "6e6f6e6365", // input 0: nonce - "a69849e11add96ac7053aad22ba2349a4abf5feb0475a0afcadff4e128be76cf", // input 0: assetID - "92c30f", // input 0: amount - "38", // input 0: input witness length - "0f", // input 0: asset definition length - "6173736574446566696e6974696f6e", // input 0: asset definition - "01", // input 0: vm version - "0f", // input 0: issuanceProgram length - "69737375616e636550726f6772616d", // input 0: issuance program - "02", // input 0: argument array length - "0a", // input 0: first argument length - "617267756d656e747331", // input 0: first argument data - "0a", // input 0: second argument length - "617267756d656e747332", // input 0: second argument data - "01", // input 1: asset version - "54", // input 1: input commitment length - "01", // input 1: spend type flag - "52", // input 1: spend commitment length - "fad5195a0c8e3b590b86a3c0a95e7529565888508aecca96e9aeda633002f409", // input 1: source id - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // input 1: assetID - "92c30f", // input 1: amount - "03", // input 1: source position - "01", // input 1: vm version - "0c", // input 1: spend program length - "7370656e6450726f6772616d", // input 1: spend program - "17", // input 1: witness length - "02", // input 1: argument array length - "0a", // input 1: first argument length - "617267756d656e747333", // input 1: first argument data - "0a", // input 1: second argument length - "617267756d656e747334", // input 1: second argument data - "01", // outputs count - "01", // output 0: asset version - "2b", // output 0: serialization length - "00", // output 0: outType - "29", // output 0: output commitment length - "a69849e11add96ac7053aad22ba2349a4abf5feb0475a0afcadff4e128be76cf", // output 0: assetID - "92c30f", // output 0: amount - "01", // output 0: version - "04", // output 0: control program length - "74727565", // output 0: control program - "00", // output 0: witness length - }, ""), - hash: testutil.MustDecodeHash("d6a1f6ea3cc3c53c3cdcd10bbd446c643f23b37ca5e87665d03f204de8c7dc2a"), - }, - { - tx: NewTx(TxData{ - Version: 1, SerializedSize: uint64(112), Inputs: []*TxInput{ NewCoinbaseInput([]byte("arbitrary")), @@ -189,84 +122,6 @@ func TestTransaction(t *testing.T) { } } -func TestTransactionTrailingGarbage(t *testing.T) { - // validTxHex is a valid tx, we don't care what's inside as long as it's valid - validTxHex := `07010001012b00030a0908916133a0d64d1d973b631e226ef95338ad4a536b95635f32f0d04708a6f2a26380a094a58d1d0900010101010301020301012b0029000000000000000000000000000000000000000000000000000000000000000080a094a58d1d01010100` - validTx := Tx{} - if err := validTx.UnmarshalText([]byte(validTxHex)); err != nil { - t.Fatal(err) - } - - invalidTxHex := validTxHex + strings.Repeat("00", 10) - invalidTx := Tx{} - if err := invalidTx.UnmarshalText([]byte(invalidTxHex)); err == nil { - t.Fatal("expected error with trailing garbage but got nil") - } -} - -func TestInvalidIssuance(t *testing.T) { - hex := strings.Join([]string{ - "07", // serflags - "01", // transaction version - "00", // tx maxtime - "01", // inputs count - "01", // input 0, asset version - "2b", // input 0, input commitment length prefix - "00", // input 0, input commitment, "issuance" type - "03", // input 0, input commitment, nonce length prefix - "0a0908", // input 0, input commitment, nonce - "0000000000000000000000000000000000000000000000000000000000000000", // input 0, input commitment, WRONG asset id - "80a094a58d1d", // input 0, input commitment, amount - "29", // input 0, issuance input witness length prefix - "03deff1d4319d67baa10a6d26c1fea9c3e8d30e33474efee1a610a9bb49d758d", // input 0, issuance input witness, initial block - "00", // input 0, issuance input witness, asset definition - "01", // input 0, issuance input witness, vm version - "01", // input 0, issuance input witness, issuance program length prefix - "01", // input 0, issuance input witness, issuance program - "01", // input 0, issuance input witness, arguments count - "03", // input 0, issuance input witness, argument 0 length prefix - "010203", // input 0, issuance input witness, argument 0 - "01", // outputs count - "01", // output 0, asset version - "2b", // output 0, serialization length - "00", // output 0, outType - "29", // output 0, output commitment length - "0000000000000000000000000000000000000000000000000000000000000000", // output 0, output commitment, asset id - "80a094a58d1d", // output 0, output commitment, amount - "01", // output 0, output commitment, vm version - "0101", // output 0, output commitment, control program - "066f7574707574", // output 0, reference data - "00", // output 0, output witness - "0869737375616e6365", - }, "") - - tx := new(TxData) - if err := tx.UnmarshalText([]byte(hex)); errors.Root(err) != errBadAssetID { - t.Errorf("want errBadAssetID, got %v", err) - } -} - -func TestFuzzUnknownAssetVersion(t *testing.T) { - rawTx := `07010001012b00030a0908916133a0d64d1d973b631e226ef95338ad4a536b95635f32f0d04708a6f2a26380a094a58d1d0900010101010301020301012b0029000000000000000000000000000000000000000000000000000000000000000080a094a58d1d01010100` - want := Tx{} - if err := want.UnmarshalText([]byte(rawTx)); err != nil { - t.Fatal(err) - } - - b, err := want.MarshalText() - if err != nil { - t.Fatal(err) - } - - got := Tx{} - if err = got.UnmarshalText(b); err != nil { - t.Fatal(err) - } - if got.ID.String() != want.ID.String() { - t.Errorf("tx id changed to %s", got.ID.String()) - } -} - func BenchmarkTxWriteToTrue(b *testing.B) { tx := &Tx{} for i := 0; i < b.N; i++ { diff --git a/protocol/bc/types/txinput.go b/protocol/bc/types/txinput.go index 22e44857..c9b4e8e6 100644 --- a/protocol/bc/types/txinput.go +++ b/protocol/bc/types/txinput.go @@ -36,12 +36,6 @@ var errBadAssetID = errors.New("asset ID does not match other issuance parameter // AssetAmount return the asset id and amount of the txinput. func (t *TxInput) AssetAmount() bc.AssetAmount { switch inp := t.TypedInput.(type) { - case *IssuanceInput: - assetID := inp.AssetID() - return bc.AssetAmount{ - AssetId: &assetID, - Amount: inp.Amount, - } case *SpendInput: return inp.AssetAmount } @@ -51,8 +45,6 @@ func (t *TxInput) AssetAmount() bc.AssetAmount { // AssetID return the assetID of the txinput func (t *TxInput) AssetID() bc.AssetID { switch inp := t.TypedInput.(type) { - case *IssuanceInput: - return inp.AssetID() case *SpendInput: return *inp.AssetId @@ -63,8 +55,6 @@ func (t *TxInput) AssetID() bc.AssetID { // Amount return the asset amount of the txinput func (t *TxInput) Amount() uint64 { switch inp := t.TypedInput.(type) { - case *IssuanceInput: - return inp.Amount case *SpendInput: return inp.Amount } @@ -79,27 +69,9 @@ func (t *TxInput) ControlProgram() []byte { return nil } -// IssuanceProgram return the control program of the issuance input -func (t *TxInput) IssuanceProgram() []byte { - if ii, ok := t.TypedInput.(*IssuanceInput); ok { - return ii.IssuanceProgram - } - return nil -} - -// AssetDefinition return the asset definition of the issuance input -func (t *TxInput) AssetDefinition() []byte { - if ii, ok := t.TypedInput.(*IssuanceInput); ok { - return ii.AssetDefinition - } - return nil -} - // Arguments get the args for the input func (t *TxInput) Arguments() [][]byte { switch inp := t.TypedInput.(type) { - case *IssuanceInput: - return inp.Arguments case *SpendInput: return inp.Arguments } @@ -109,8 +81,6 @@ func (t *TxInput) Arguments() [][]byte { // SetArguments set the args for the input func (t *TxInput) SetArguments(args [][]byte) { switch inp := t.TypedInput.(type) { - case *IssuanceInput: - inp.Arguments = args case *SpendInput: inp.Arguments = args } @@ -129,7 +99,6 @@ func (t *TxInput) readFrom(r *blockchain.Reader) (err error) { return err } - var assetID bc.AssetID t.CommitmentSuffix, err = blockchain.ReadExtensibleString(r, func(r *blockchain.Reader) error { if t.AssetVersion != 1 { return nil @@ -139,20 +108,6 @@ func (t *TxInput) readFrom(r *blockchain.Reader) (err error) { return errors.Wrap(err, "reading input commitment type") } switch icType[0] { - case IssuanceInputType: - ii := new(IssuanceInput) - t.TypedInput = ii - - if ii.Nonce, err = blockchain.ReadVarstr31(r); err != nil { - return err - } - if _, err = assetID.ReadFrom(r); err != nil { - return err - } - if ii.Amount, err = blockchain.ReadVarint63(r); err != nil { - return err - } - case SpendInputType: si := new(SpendInput) t.TypedInput = si @@ -182,23 +137,6 @@ func (t *TxInput) readFrom(r *blockchain.Reader) (err error) { } switch inp := t.TypedInput.(type) { - case *IssuanceInput: - if inp.AssetDefinition, err = blockchain.ReadVarstr31(r); err != nil { - return err - } - if inp.VMVersion, err = blockchain.ReadVarint63(r); err != nil { - return err - } - if inp.IssuanceProgram, err = blockchain.ReadVarstr31(r); err != nil { - return err - } - if inp.AssetID() != assetID { - return errBadAssetID - } - if inp.Arguments, err = blockchain.ReadVarstrList(r); err != nil { - return err - } - case *SpendInput: if inp.Arguments, err = blockchain.ReadVarstrList(r); err != nil { return err @@ -229,20 +167,6 @@ func (t *TxInput) writeInputCommitment(w io.Writer) (err error) { } switch inp := t.TypedInput.(type) { - case *IssuanceInput: - if _, err = w.Write([]byte{IssuanceInputType}); err != nil { - return err - } - if _, err = blockchain.WriteVarstr31(w, inp.Nonce); err != nil { - return err - } - assetID := t.AssetID() - if _, err = assetID.WriteTo(w); err != nil { - return err - } - _, err = blockchain.WriteVarint63(w, inp.Amount) - return err - case *SpendInput: if _, err = w.Write([]byte{SpendInputType}); err != nil { return err @@ -266,19 +190,6 @@ func (t *TxInput) writeInputWitness(w io.Writer) error { } switch inp := t.TypedInput.(type) { - case *IssuanceInput: - if _, err := blockchain.WriteVarstr31(w, inp.AssetDefinition); err != nil { - return err - } - if _, err := blockchain.WriteVarint63(w, inp.VMVersion); err != nil { - return err - } - if _, err := blockchain.WriteVarstr31(w, inp.IssuanceProgram); err != nil { - return err - } - _, err := blockchain.WriteVarstrList(w, inp.Arguments) - return err - case *SpendInput: _, err := blockchain.WriteVarstrList(w, inp.Arguments) return err diff --git a/protocol/bc/types/txinput_test.go b/protocol/bc/types/txinput_test.go index a133f092..110b8b38 100644 --- a/protocol/bc/types/txinput_test.go +++ b/protocol/bc/types/txinput_test.go @@ -12,61 +12,6 @@ import ( "github.com/vapor/testutil" ) -func TestSerializationIssuance(t *testing.T) { - arguments := [][]byte{ - []byte("arguments1"), - []byte("arguments2"), - } - issuance := NewIssuanceInput([]byte("nonce"), 254354, []byte("issuanceProgram"), arguments, []byte("assetDefinition")) - - wantHex := strings.Join([]string{ - "01", // asset version - "2a", // serialization length - "00", // issuance type flag - "05", // nonce length - "6e6f6e6365", // nonce - "a69849e11add96ac7053aad22ba2349a4abf5feb0475a0afcadff4e128be76cf", // assetID - "92c30f", // amount - "38", // input witness length - "0f", // asset definition length - "6173736574446566696e6974696f6e", // asset definition - "01", // vm version - "0f", // issuanceProgram length - "69737375616e636550726f6772616d", // issuance program - "02", // argument array length - "0a", // first argument length - "617267756d656e747331", // first argument data - "0a", // second argument length - "617267756d656e747332", // second argument data - }, "") - - // Test convert struct to hex - var buffer bytes.Buffer - if err := issuance.writeTo(&buffer); err != nil { - t.Fatal(err) - } - - gotHex := hex.EncodeToString(buffer.Bytes()) - if gotHex != wantHex { - t.Errorf("serialization bytes = %s want %s", gotHex, wantHex) - } - - // Test convert hex to struct - var gotIssuance TxInput - decodeHex, err := hex.DecodeString(wantHex) - if err != nil { - t.Fatal(err) - } - - if err := gotIssuance.readFrom(blockchain.NewReader(decodeHex)); err != nil { - t.Fatal(err) - } - - if !testutil.DeepEqual(*issuance, gotIssuance) { - t.Errorf("expected marshaled/unmarshaled txinput to be:\n%sgot:\n%s", spew.Sdump(*issuance), spew.Sdump(gotIssuance)) - } -} - func TestSerializationSpend(t *testing.T) { arguments := [][]byte{ []byte("arguments1"), diff --git a/protocol/validation/test/tx_ugly_test.go b/protocol/validation/test/tx_ugly_test.go index 30dcc571..72434500 100644 --- a/protocol/validation/test/tx_ugly_test.go +++ b/protocol/validation/test/tx_ugly_test.go @@ -137,161 +137,6 @@ func TestValidateUglyTx(t *testing.T) { }, { category: "input output unbalance", - desc: "issuance asset, no corresponding output", - insts: []*signingInst{singleSignInst, singleSignInst}, - txData: types.TxData{ - Version: 1, - Inputs: []*types.TxInput{ - types.NewSpendInput(nil, - bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994}, - *consensus.BTMAssetID, 10000000000, 0, nil), - types.NewIssuanceInput( // assetID: 97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f - testutil.MustDecodeHexString("fd0aec4229deb281"), - 10000000000, - nil, - nil, - testutil.MustDecodeHexString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"), - ), - }, - Outputs: []*types.TxOutput{ - types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")), - }, - }, - err: true, - gasValid: false, - }, - { - category: "input output unbalance", - desc: "issuance asset A, output asset B", - insts: []*signingInst{singleSignInst, singleSignInst}, - txData: types.TxData{ - Version: 1, - Inputs: []*types.TxInput{ - types.NewSpendInput(nil, - bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994}, - *consensus.BTMAssetID, 10000000000, 0, nil), - types.NewIssuanceInput( // assetID: 97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f - testutil.MustDecodeHexString("fd0aec4229deb281"), - 10000000000, - nil, - nil, - testutil.MustDecodeHexString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"), - ), - }, - Outputs: []*types.TxOutput{ - types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")), - types.NewIntraChainOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707e"), 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")), - }, - }, - err: true, - gasValid: false, - }, - { - category: "input output unbalance", - desc: "sum of output asset A greater than issuance asset A", - insts: []*signingInst{singleSignInst, singleSignInst}, - txData: types.TxData{ - Version: 1, - Inputs: []*types.TxInput{ - types.NewSpendInput(nil, - bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994}, - *consensus.BTMAssetID, 10000000000, 0, nil), - types.NewIssuanceInput( // assetID: 97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f - testutil.MustDecodeHexString("fd0aec4229deb281"), - 10000000000, - nil, - nil, - testutil.MustDecodeHexString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"), - ), - }, - Outputs: []*types.TxOutput{ - types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")), - types.NewIntraChainOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 20000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")), - }, - }, - err: true, - gasValid: false, - }, - { - category: "input output unbalance", - desc: "sum of output asset A less than issuance asset A", - insts: []*signingInst{singleSignInst, singleSignInst}, - txData: types.TxData{ - Version: 1, - Inputs: []*types.TxInput{ - types.NewSpendInput(nil, - bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994}, - *consensus.BTMAssetID, 10000000000, 0, nil), - types.NewIssuanceInput( // assetID: 97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f - testutil.MustDecodeHexString("fd0aec4229deb281"), - 10000000000, - nil, - nil, - testutil.MustDecodeHexString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"), - ), - }, - Outputs: []*types.TxOutput{ - types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")), - types.NewIntraChainOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 5000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")), - }, - }, - err: true, - gasValid: false, - }, - { - category: "input output unbalance", - desc: "sum of retire asset A greater than issuance asset A", - insts: []*signingInst{singleSignInst, singleSignInst}, - txData: types.TxData{ - Version: 1, - Inputs: []*types.TxInput{ - types.NewSpendInput(nil, - bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994}, - *consensus.BTMAssetID, 10000000000, 0, nil), - types.NewIssuanceInput( // assetID: 97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f - testutil.MustDecodeHexString("fd0aec4229deb281"), - 10000000000, - nil, - nil, - testutil.MustDecodeHexString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"), - ), - }, - Outputs: []*types.TxOutput{ - types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")), - types.NewIntraChainOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 20000000000, testutil.MustDecodeHexString("6a")), - }, - }, - err: true, - gasValid: false, - }, - { - category: "input output unbalance", - desc: "sum of retire asset A less than issuance asset A", - insts: []*signingInst{singleSignInst, singleSignInst}, - txData: types.TxData{ - Version: 1, - Inputs: []*types.TxInput{ - types.NewSpendInput(nil, - bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994}, - *consensus.BTMAssetID, 10000000000, 0, nil), - types.NewIssuanceInput( // assetID: 97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f - testutil.MustDecodeHexString("fd0aec4229deb281"), - 10000000000, - nil, - nil, - testutil.MustDecodeHexString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"), - ), - }, - Outputs: []*types.TxOutput{ - types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")), - types.NewIntraChainOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 5000000000, testutil.MustDecodeHexString("6a")), - }, - }, - err: true, - gasValid: false, - }, - { - category: "input output unbalance", desc: "spend asset A, no corresponding output", insts: []*signingInst{singleSignInst, singleSignInst}, txData: types.TxData{ @@ -518,70 +363,6 @@ func TestValidateUglyTx(t *testing.T) { }, { category: "overflow", - desc: "issuance non btm input overflow", - insts: []*signingInst{singleSignInst, singleSignInst, singleSignInst}, - txData: types.TxData{ - Version: 1, - Inputs: []*types.TxInput{ - types.NewSpendInput(nil, - bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302}, - *consensus.BTMAssetID, 10000000000, 1, nil), - types.NewIssuanceInput( // assetID: 97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f - testutil.MustDecodeHexString("fd0aec4229deb281"), - math.MaxInt64, - nil, - [][]byte{ - testutil.MustDecodeHexString("e8f301f7bd3b1e4ca853b15559b3a253a4f5f9c7efba233ab0f6896bec23adc6a816c350e08f6b8ac5bc23eb5720173f9190805328af581f34a7fe561358d100"), - }, - testutil.MustDecodeHexString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"), - ), - types.NewIssuanceInput( // assetID: 97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f - testutil.MustDecodeHexString("fd0aec4229deb281"), - 10000000000, - nil, - nil, - testutil.MustDecodeHexString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"), - ), - }, - Outputs: []*types.TxOutput{ - types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")), - types.NewIntraChainOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")), - }, - }, - err: true, - gasValid: false, - }, - { - category: "overflow", - desc: "sum of spend and issuance non btm input overflow", - insts: []*signingInst{singleSignInst, singleSignInst, singleSignInst}, - txData: types.TxData{ - Version: 1, - Inputs: []*types.TxInput{ - types.NewSpendInput(nil, - bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302}, - *consensus.BTMAssetID, 10000000000, 1, nil), - types.NewIssuanceInput( // assetID: 97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f - testutil.MustDecodeHexString("fd0aec4229deb281"), - math.MaxInt64, - nil, - nil, - testutil.MustDecodeHexString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"), - ), - types.NewSpendInput(nil, - bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302}, - testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 100, 0, nil), - }, - Outputs: []*types.TxOutput{ - types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")), - types.NewIntraChainOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 100, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")), - }, - }, - err: true, - gasValid: false, - }, - { - category: "overflow", desc: "spend btm output overflow", insts: []*signingInst{singleSignInst, singleSignInst}, txData: types.TxData{ @@ -761,60 +542,6 @@ func TestValidateUglyTx(t *testing.T) { gasValid: true, }, { - category: "verify signature fail", - desc: "issuance non btm single sign", - insts: []*signingInst{singleSignInst, multiSignInst}, - txData: types.TxData{ - Version: 1, - Inputs: []*types.TxInput{ - types.NewSpendInput(nil, - bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994}, - *consensus.BTMAssetID, 10000000000, 0, nil), - types.NewIssuanceInput( - testutil.MustDecodeHexString("fd0aec4229deb281"), - 10000000000, - // wrong issuance program - testutil.MustDecodeHexString("ae20c38173d800e62f63bd08cfaa9bc905e4a34a61ad841d7ad6c70ead0fb48196995151ad"), - nil, - nil, - ), - }, - Outputs: []*types.TxOutput{ - types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")), - types.NewIntraChainOutput(testutil.MustDecodeAsset("bf5f8da2334590ee095148ccdcf4d806b26a47a6d9e9e857ef6c2de79aee4f14"), 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")), - }, - }, - err: true, - gasValid: true, - }, - { - category: "verify signature fail", - desc: "issuance non btm multi sign", - insts: []*signingInst{singleSignInst, multiSignInst}, - txData: types.TxData{ - Version: 1, - Inputs: []*types.TxInput{ - types.NewSpendInput(nil, - bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994}, - *consensus.BTMAssetID, 10000000000, 0, nil), - types.NewIssuanceInput( - testutil.MustDecodeHexString("fd0aec4229deb281"), - 10000000000, - // wrong issuance program - testutil.MustDecodeHexString("ae20ce8639c5dc70cb2b12f89a057670602eb013fc54a10ce22bd4691c62cf546b7b2081bdd879bcbce7f58e1731841c6b3deac242efa00e75124fe559fa531c0c5bb820b40b6eec74288ee4bae67191f135512454b52640cfd7be95dc84be0f02281dce20247b6e6f9230a987ef61c66820268e7b766d28c1ce7aa2c550b34e294167f340205096211460415888768a48b121013711aa711634bb9ff7341a7bd072c31525875355ad"), - nil, - testutil.MustDecodeHexString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"), - ), - }, - Outputs: []*types.TxOutput{ - types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")), - types.NewIntraChainOutput(testutil.MustDecodeAsset("776f0a421e9176a03061d388aff4ab3b1bcd32e53a090d593a466706c69e3d3f"), 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")), - }, - }, - err: true, - gasValid: true, - }, - { category: "double spend", desc: "btm asset double spend", insts: []*signingInst{singleSignInst, singleSignInst}, @@ -914,25 +641,6 @@ func mockCtrlProgram(txData types.TxData, insts []*signingInst) { panic(err) } inp.ControlProgram = program.ControlProgram - case *types.IssuanceInput: - if inp.IssuanceProgram != nil { - continue - } - assetSigner, err := signers.Create("asset", xPubs, insts[i].quorum, insts[i].keyIndex, signers.BIP0032) - if err != nil { - panic(err) - } - - path := signers.GetBip0032Path(assetSigner, signers.AssetKeySpace) - derivedXPubs := chainkd.DeriveXPubs(assetSigner.XPubs, path) - derivedPKs := chainkd.XPubKeys(derivedXPubs) - - issuanceProg, err := vmutil.P2SPMultiSigProgramWithHeight(derivedPKs, insts[i].quorum, 0) - if err != nil { - panic(err) - } - - inp.IssuanceProgram = issuanceProg } } } @@ -973,15 +681,6 @@ func mockSignTx(tx *types.Tx, insts []*signingInst) { arguments = append(arguments, script) } inp.Arguments = arguments - case *types.IssuanceInput: - path := signers.GetBip0032Path(&signers.Signer{KeyIndex: inst.keyIndex, DeriveRule: signers.BIP0032}, signers.AssetKeySpace) - xPrvs, _ := mustGetRootKeys(inst.rootPrvKeys) - for _, xPrv := range xPrvs { - childPrv := xPrv.Derive(path) - sigHashBytes := tx.SigHash(uint32(i)).Byte32() - arguments = append(arguments, childPrv.Sign(sigHashBytes[:])) - } - inp.Arguments = arguments } } } diff --git a/protocol/validation/tx.go b/protocol/validation/tx.go index 1e2467b5..058b736d 100644 --- a/protocol/validation/tx.go +++ b/protocol/validation/tx.go @@ -238,26 +238,6 @@ func checkValid(vs *validationState, e bc.Entry) (err error) { return errors.Wrap(err, "checking retirement source") } - case *bc.Issuance: - computedAssetID := e.WitnessAssetDefinition.ComputeAssetID() - if computedAssetID != *e.Value.AssetId { - return errors.WithDetailf(ErrMismatchedAssetID, "asset ID is %x, issuance wants %x", computedAssetID.Bytes(), e.Value.AssetId.Bytes()) - } - - gasLeft, err := vm.Verify(NewTxVMContext(vs, e, e.WitnessAssetDefinition.IssuanceProgram, e.WitnessArguments), vs.gasStatus.GasLeft) - if err != nil { - return errors.Wrap(err, "checking issuance program") - } - if err = vs.gasStatus.updateUsage(gasLeft); err != nil { - return err - } - - destVS := *vs - destVS.destPos = 0 - if err = checkValidDest(&destVS, e.WitnessDestination); err != nil { - return errors.Wrap(err, "checking issuance destination") - } - case *bc.Spend: if e.SpentOutputId == nil { return errors.Wrap(ErrMissingField, "spend without spent output ID") @@ -353,12 +333,6 @@ func checkValidSrc(vstate *validationState, vs *bc.ValueSource) error { } dest = ref.WitnessDestination - case *bc.Issuance: - if vs.Position != 0 { - return errors.Wrapf(ErrPosition, "invalid position %d for issuance source", vs.Position) - } - dest = ref.WitnessDestination - case *bc.Spend: if vs.Position != 0 { return errors.Wrapf(ErrPosition, "invalid position %d for spend source", vs.Position) diff --git a/protocol/validation/tx_scene_test.go b/protocol/validation/tx_scene_test.go index 8b0df290..47068663 100644 --- a/protocol/validation/tx_scene_test.go +++ b/protocol/validation/tx_scene_test.go @@ -145,70 +145,6 @@ func TestValidateTx(t *testing.T) { err: nil, }, { - desc: "single utxo, single sign, issuance, spend, retire, btm stanard transaction, gas sufficient", - txData: &types.TxData{ - Version: 1, - SerializedSize: 601, - Inputs: []*types.TxInput{ - types.NewSpendInput( - [][]byte{ - mustDecodeString("8aab6052cb935384ac8fcbd4c0857cbce2e19825a002635d0b242757f17e5fdd148d83eb3837baf91754bf539cd08e29f66975f4bc9843ac00e280f228026105"), - mustDecodeString("ca85ea98011ddd592d1f081ebd2a91ac0f4238784222ed85b9d95aeb654f1cf1"), - }, - bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994}, - *consensus.BTMAssetID, 11818900000, 0, mustDecodeString("0014e6e1f8b11f1cfb7609037003b90f64837afd272c")), - types.NewIssuanceInput( - mustDecodeString("fd0aec4229deb281"), - 10000000000, - mustDecodeString("ae2054a71277cc162eb3eb21b5bd9fe54402829a53b294deaed91692a2cd8a081f9c5151ad"), - [][]byte{ - mustDecodeString("e8f301f7bd3b1e4ca853b15559b3a253a4f5f9c7efba233ab0f6896bec23adc6a816c350e08f6b8ac5bc23eb5720173f9190805328af581f34a7fe561358d100"), - }, - mustDecodeString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"), - ), - }, - Outputs: []*types.TxOutput{ - types.NewIntraChainOutput(*consensus.BTMAssetID, 1818900000, mustDecodeString("00147d6b00edfbbc758a5da6130a5fa1a4cfec8422c3")), - types.NewIntraChainOutput(*consensus.BTMAssetID, 9900000000, []byte{byte(vm.OP_FAIL)}), - types.NewIntraChainOutput(bc.AssetID{V0: 8879089148261671560, V1: 16875272676673176923, V2: 14627348561007036053, V3: 5774520766896450836}, 10000000000, mustDecodeString("0014447e597c1c326ad1a639f8023d3f87ae22a4e049")), - }, - }, - gasValid: true, - err: nil, - }, - { - desc: "single utxo, single sign, issuance, spend, retire, btm stanard transaction, gas insufficient", - txData: &types.TxData{ - Version: 1, - SerializedSize: 601, - Inputs: []*types.TxInput{ - types.NewSpendInput( - [][]byte{ - mustDecodeString("23ca3a6f8474b1b9ab8b77fcf3cf3fd9dfa761dff4e5d8551a72307dc065cd19100f3ca9fcca4df2f8842b71dba2fd29b73c1b06b3d8bddc2a71e8cc18842a04"), - mustDecodeString("ca85ea98011ddd592d1f081ebd2a91ac0f4238784222ed85b9d95aeb654f1cf1"), - }, - bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994}, - *consensus.BTMAssetID, 11818900000, 0, mustDecodeString("0014e6e1f8b11f1cfb7609037003b90f64837afd272c")), - types.NewIssuanceInput( - mustDecodeString("4b6afc9344c3ce63"), - 10000000000, - mustDecodeString("ae2054a71277cc162eb3eb21b5bd9fe54402829a53b294deaed91692a2cd8a081f9c5151ad"), - [][]byte{ - mustDecodeString("e8f301f7bd3b1e4ca85f1f8acda3a91fb73e717c096b8b82b2c7ed9d25170c0f9fcd9b5e8039094bd1174886f1b5428272eb6c2af03946bf3c2037a4b499c77107b94b96a92088a0d0d3b15559b3a253a4f5f9c7efba233ab0f6896bec23adc6a816c350e08f6b8ac5bc23eb5720173f9190805328af581f34a7fe561358d100"), - }, - mustDecodeString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"), - ), - }, - Outputs: []*types.TxOutput{ - types.NewIntraChainOutput(*consensus.BTMAssetID, 1818900000, mustDecodeString("001482b7991d64d001009b673ffe3ca2b35eab14f142")), - types.NewIntraChainOutput(*consensus.BTMAssetID, 10000000000, []byte{byte(vm.OP_FAIL)}), - types.NewIntraChainOutput(bc.AssetID{V0: 8879089148261671560, V1: 16875272676673176923, V2: 14627348561007036053, V3: 5774520766896450836}, 10000000000, mustDecodeString("0014447e597c1c326ad1a639f8023d3f87ae22a4e049")), - }, - }, - gasValid: false, - err: vm.ErrRunLimitExceeded, - }, - { desc: "btm stanard transaction check signature is not passed", txData: &types.TxData{ Version: 1, diff --git a/protocol/validation/tx_test.go b/protocol/validation/tx_test.go index 465cb60f..ed0f06e8 100644 --- a/protocol/validation/tx_test.go +++ b/protocol/validation/tx_test.go @@ -366,15 +366,6 @@ func TestTxValidation(t *testing.T) { { desc: "unbalanced mux amounts", f: func() { - mux.Sources[0].Value.Amount++ - iss := tx.Entries[*mux.Sources[0].Ref].(*bc.Issuance) - iss.WitnessDestination.Value.Amount++ - }, - err: ErrUnbalanced, - }, - { - desc: "unbalanced mux amounts", - f: func() { mux.WitnessDestinations[0].Value.Amount++ }, err: ErrUnbalanced, @@ -388,15 +379,6 @@ func TestTxValidation(t *testing.T) { err: nil, }, { - desc: "overflowing mux source amounts", - f: func() { - mux.Sources[0].Value.Amount = math.MaxInt64 - iss := tx.Entries[*mux.Sources[0].Ref].(*bc.Issuance) - iss.WitnessDestination.Value.Amount = math.MaxInt64 - }, - err: ErrOverflow, - }, - { desc: "underflowing mux destination amounts", f: func() { mux.WitnessDestinations[0].Value.Amount = math.MaxInt64 @@ -448,21 +430,6 @@ func TestTxValidation(t *testing.T) { err: ErrMismatchedReference, }, { - desc: "mismatched input dest and mux source", - f: func() { - fixture2 := sample(t, fixture) - tx2 := types.NewTx(*fixture2.tx).Tx - input2ID := tx2.InputIDs[2] - input2 := tx2.Entries[input2ID].(*bc.Spend) - dest2Ref := input2.WitnessDestination.Ref - dest2 := tx2.Entries[*dest2Ref].(*bc.Mux) - tx.Entries[*dest2Ref] = dest2 - tx.Entries[input2ID] = input2 - mux.Sources[0].Ref = &input2ID - }, - err: ErrMismatchedReference, - }, - { desc: "invalid mux destination position", f: func() { mux.WitnessDestinations[0].Position = 1 @@ -497,14 +464,6 @@ func TestTxValidation(t *testing.T) { }, }, { - desc: "issuance program failure", - f: func() { - iss := txIssuance(t, tx, 0) - iss.WitnessArguments[0] = []byte{} - }, - err: vm.ErrFalseVMResult, - }, - { desc: "spend control program failure", f: func() { spend := txSpend(t, tx, 1) @@ -574,24 +533,6 @@ func TestTxValidation(t *testing.T) { err: ErrMismatchedValue, }, { - desc: "mismatched witness asset destination", - f: func() { - issuanceID := mux.Sources[0].Ref - issuance := tx.Entries[*issuanceID].(*bc.Issuance) - issuance.WitnessAssetDefinition.Data = &bc.Hash{V0: 9999} - }, - err: ErrMismatchedAssetID, - }, - { - desc: "issuance witness position greater than length of mux sources", - f: func() { - issuanceID := mux.Sources[0].Ref - issuance := tx.Entries[*issuanceID].(*bc.Issuance) - issuance.WitnessDestination.Position = uint64(len(mux.Sources) + 1) - }, - err: ErrPosition, - }, - { desc: "normal coinbase tx", f: func() { addCoinbase(consensus.BTMAssetID, 100000, nil) @@ -1041,8 +982,7 @@ func sample(tb testing.TB, in *txFixture) *txFixture { result.assetDef = []byte{2} } if result.assetID.IsZero() { - refdatahash := hashData(result.assetDef) - result.assetID = bc.ComputeAssetID(result.issuanceProg.Code, result.issuanceProg.VmVersion, &refdatahash) + result.assetID = bc.AssetID{V0: 9999} } if result.txVersion == 0 { @@ -1062,7 +1002,7 @@ func sample(tb testing.TB, in *txFixture) *txFixture { args2 := [][]byte{{6}, {7}} result.txInputs = []*types.TxInput{ - types.NewIssuanceInput([]byte{3}, 10, result.issuanceProg.Code, result.issuanceArgs, result.assetDef), + types.NewSpendInput(nil, *newHash(9), result.assetID, 10, 0, []byte{byte(vm.OP_TRUE)}), types.NewSpendInput(args1, *newHash(5), result.assetID, 20, 0, cp1), types.NewSpendInput(args2, *newHash(8), result.assetID, 40, 0, cp2), } @@ -1129,15 +1069,6 @@ func newAssetID(n byte) *bc.AssetID { return &a } -func txIssuance(t *testing.T, tx *bc.Tx, index int) *bc.Issuance { - id := tx.InputIDs[index] - res, err := tx.Issuance(id) - if err != nil { - t.Fatal(err) - } - return res -} - func txSpend(t *testing.T, tx *bc.Tx, index int) *bc.Spend { id := tx.InputIDs[index] res, err := tx.Spend(id) diff --git a/protocol/validation/vmcontext.go b/protocol/validation/vmcontext.go index 356dc7ca..f7b62bcf 100644 --- a/protocol/validation/vmcontext.go +++ b/protocol/validation/vmcontext.go @@ -25,11 +25,6 @@ func NewTxVMContext(vs *validationState, entry bc.Entry, prog *bc.Program, args ) switch e := entry.(type) { - case *bc.Issuance: - a1 := e.Value.AssetId.Bytes() - assetID = &a1 - amount = &e.Value.Amount - destPos = &e.WitnessDestination.Position case *bc.Spend: spentOutput := tx.Entries[*e.SpentOutputId].(*bc.IntraChainOutput) @@ -148,19 +143,6 @@ func (ec *entryContext) checkOutput(index uint64, amount uint64, assetID []byte, case *bc.Mux: return checkMux(e) - case *bc.Issuance: - d, ok := ec.entries[*e.WitnessDestination.Ref] - if !ok { - return false, errors.Wrapf(bc.ErrMissingEntry, "entry for issuance destination %x not found", e.WitnessDestination.Ref.Bytes()) - } - if m, ok := d.(*bc.Mux); ok { - return checkMux(m) - } - if index != 0 { - return false, errors.Wrapf(vm.ErrBadValue, "index %d >= 1", index) - } - return checkEntry(d) - case *bc.Spend: d, ok := ec.entries[*e.WitnessDestination.Ref] if !ok { diff --git a/protocol/validation/vmcontext_test.go b/protocol/validation/vmcontext_test.go index f0f85060..9f6e7306 100644 --- a/protocol/validation/vmcontext_test.go +++ b/protocol/validation/vmcontext_test.go @@ -14,7 +14,6 @@ func TestCheckOutput(t *testing.T) { tx := types.NewTx(types.TxData{ Inputs: []*types.TxInput{ types.NewSpendInput(nil, bc.Hash{}, bc.NewAssetID([32]byte{1}), 5, 1, []byte("spendprog")), - types.NewIssuanceInput(nil, 6, []byte("issueprog"), nil, nil), }, Outputs: []*types.TxOutput{ types.NewIntraChainOutput(bc.NewAssetID([32]byte{3}), 8, []byte("wrongprog")), diff --git a/protocol/vm/vmutil/script.go b/protocol/vm/vmutil/script.go index 67f80f70..adc0d77b 100644 --- a/protocol/vm/vmutil/script.go +++ b/protocol/vm/vmutil/script.go @@ -133,22 +133,3 @@ func checkMultiSigParams(nrequired, npubkeys int64) error { } return nil } - -// GetIssuanceProgramRestrictHeight return issuance program restrict height -// if height invalid return 0 -func GetIssuanceProgramRestrictHeight(program []byte) int64 { - insts, err := vm.ParseProgram(program) - if err != nil { - return 0 - } - - if len(insts) >= 4 && insts[0].IsPushdata() && insts[1].Op == vm.OP_BLOCKHEIGHT && insts[2].Op == vm.OP_GREATERTHAN && insts[3].Op == vm.OP_VERIFY { - height, err := vm.AsInt64(insts[0].Data) - if err != nil { - return 0 - } - - return height - } - return 0 -} diff --git a/protocol/vm/vmutil/script_test.go b/protocol/vm/vmutil/script_test.go index 7160c1fb..623bccf7 100644 --- a/protocol/vm/vmutil/script_test.go +++ b/protocol/vm/vmutil/script_test.go @@ -188,35 +188,3 @@ func TestP2SPMultiSigProgramWithHeight(t *testing.T) { } } } - -func TestGetIssuanceProgramRestrictHeight(t *testing.T) { - tests := []struct { - issuanceProgram string - wantHeight int64 - }{ - { - issuanceProgram: "", - wantHeight: 0, - }, - { - issuanceProgram: "ae20ac20f5cdb9ada2ae9836bcfff32126d6b885aa3f73ee111a95d1bf37f3904aca5151ad", - wantHeight: 0, - }, - { - issuanceProgram: "01c8cda069ae20f44dd85be89de08b0f894476ccc7b3eebcf0a288c79504fa7e4c8033f5b7338020c86dc682ce3ecac64e165d9b5f8cca9ee05bd0d4df07adbfd11251ad7e88f1685152ad", - wantHeight: 200, - }, - } - - for i, test := range tests { - program, err := hex.DecodeString(test.issuanceProgram) - if err != nil { - t.Fatal(err) - } - - gotHeight := GetIssuanceProgramRestrictHeight(program) - if gotHeight != test.wantHeight { - t.Errorf("TestGetIssuanceProgramRestrictHeight #%d failed: got %d want %d", i, gotHeight, test.wantHeight) - } - } -} diff --git a/test/chain_test.go b/test/chain_test.go deleted file mode 100644 index 052c3575..00000000 --- a/test/chain_test.go +++ /dev/null @@ -1,15 +0,0 @@ -// +build functional - -package test - -import ( - "testing" -) - -func TestChain(t *testing.T) { - walk(t, chainTestDir, func(t *testing.T, name string, test *chainTestConfig) { - if err := test.Run(); err != nil { - t.Fatal(err) - } - }) -} diff --git a/test/testdata/chain_tests/ct_dependency_tx.json b/test/testdata/chain_tests/ct_dependency_tx.json deleted file mode 100644 index c25e24a4..00000000 --- a/test/testdata/chain_tests/ct_dependency_tx.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "blocks": [ - { - "append": 100 - }, - { - "transactions": [ - { - "inputs": [ - {"height": 1, "tx_index": 0, "output_index": 0} - ], - "outputs": [3000000000, 10000000, 3000000000] - } - ], - "append": 2 - }, - { - "transactions": [ - { - "inputs": [ - {"height": 2, "tx_index": 0, "output_index": 0} - ], - "outputs": [3000000000, 10000000, 3000000000] - } - ] - }, - { - "transactions": [ - { - "inputs": [ - {"height": 102, "tx_index": 1, "output_index": 0}, - {"height": 3, "tx_index": 0, "output_index": 0} - ], - "outputs": [3000000000, 10000000, 3000000000] - }, - { - "inputs": [ - {"height": 105, "tx_index": 1, "output_index": 0}, - {"height": 4, "tx_index": 0, "output_index": 0} - ], - "outputs": [3000000000, 10000000, 3000000000] - } - ] - }, - { - "transactions": [ - { - "inputs": [ - {"height": 106, "tx_index": 1, "output_index": 0}, - {"height": 106, "tx_index": 2, "output_index": 0}, - {"height": 106, "tx_index": 2, "output_index": 2} - ], - "outputs": [3000000000, 10000000, 3000000000] - }, - { - "inputs": [ - {"height": 107, "tx_index": 1, "output_index": 0}, - {"height": 107, "tx_index": 1, "output_index": 2}, - {"height": 5, "tx_index": 0, "output_index": 0} - ], - "outputs": [3000000000, 10000000, 3000000000] - }, - { - "inputs": [ - {"height": 107, "tx_index": 2, "output_index": 0}, - {"height": 107, "tx_index": 1, "output_index": 1}, - {"height": 6, "tx_index": 0, "output_index": 0} - ], - "outputs": [3000000000, 10000000, 3000000000] - } - ] - } - ] -} \ No newline at end of file diff --git a/test/testdata/chain_tests/ct_double_spend.json b/test/testdata/chain_tests/ct_double_spend.json deleted file mode 100644 index b835a1ed..00000000 --- a/test/testdata/chain_tests/ct_double_spend.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "blocks": [ - { - "append": 100 - }, - { - "transactions": [ - { - "inputs": [ - {"height": 1, "tx_index": 0, "output_index": 0} - ], - "outputs": [3000000000, 10000000, 3000000000] - } - ], - "append": 2 - }, - { - "transactions": [ - { - "inputs": [ - {"height": 2, "tx_index": 0, "output_index": 0} - ], - "outputs": [3000000000, 10000000, 3000000000] - }, - { - "inputs": [ - {"height": 105, "tx_index": 1, "output_index": 0}, - {"height": 3, "tx_index": 0, "output_index": 0} - ], - "outputs": [3000000000, 10000000, 3000000000] - } - ] - }, - { - "transactions": [ - { - "inputs": [ - {"height": 105, "tx_index": 1, "output_index": 0}, - {"height": 4, "tx_index": 0, "output_index": 0} - ], - "outputs": [3000000000, 10000000, 3000000000] - } - ], - "invalid": true - } - ] -} diff --git a/test/testdata/chain_tests/ct_normal.json b/test/testdata/chain_tests/ct_normal.json deleted file mode 100644 index 272db05e..00000000 --- a/test/testdata/chain_tests/ct_normal.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "blocks": [ - { - "append": 100 - }, - { - "transactions": [ - { - "inputs": [ - {"height": 1, "tx_index": 0, "output_index": 0} - ], - "outputs": [3000000000, 10000000, 3000000000] - } - ], - "append": 2 - }, - { - "transactions": [ - { - "inputs": [ - {"height": 2, "tx_index": 0, "output_index": 0} - ], - "outputs": [3000000000, 10000000, 3000000000] - } - ] - }, - { - "transactions": [ - { - "inputs": [ - {"height": 105, "tx_index": 1, "output_index": 0}, - {"height": 3, "tx_index": 0, "output_index": 0} - ], - "outputs": [3000000000, 10000000, 3000000000] - }, - { - "inputs": [ - {"height": 105, "tx_index": 1, "output_index": 2}, - {"height": 4, "tx_index": 0, "output_index": 0} - ], - "outputs": [3000000000, 10000000, 3000000000] - } - ] - } - ] -} \ No newline at end of file diff --git a/test/testdata/chain_tests/ct_rollback.json b/test/testdata/chain_tests/ct_rollback.json deleted file mode 100644 index f3178d04..00000000 --- a/test/testdata/chain_tests/ct_rollback.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "rollback": 104, - "blocks": [ - { - "append": 100 - }, - { - "transactions": [ - { - "inputs": [ - {"height": 1, "tx_index": 0, "output_index": 0} - ], - "outputs": [3000000000, 10000000, 3000000000] - } - ], - "append": 2 - }, - { - "transactions": [ - { - "inputs": [ - {"height": 2, "tx_index": 0, "output_index": 0} - ], - "outputs": [3000000000, 10000000, 3000000000] - } - ] - }, - { - "transactions": [ - { - "inputs": [ - {"height": 102, "tx_index": 1, "output_index": 0}, - {"height": 3, "tx_index": 0, "output_index": 0} - ], - "outputs": [3000000000, 10000000, 3000000000] - }, - { - "inputs": [ - {"height": 105, "tx_index": 1, "output_index": 0}, - {"height": 4, "tx_index": 0, "output_index": 0} - ], - "outputs": [3000000000, 10000000, 3000000000] - } - ] - }, - { - "transactions": [ - { - "inputs": [ - {"height": 106, "tx_index": 1, "output_index": 0}, - {"height": 106, "tx_index": 2, "output_index": 0}, - {"height": 106, "tx_index": 2, "output_index": 2} - ], - "outputs": [3000000000, 10000000, 3000000000] - }, - { - "inputs": [ - {"height": 107, "tx_index": 1, "output_index": 0}, - {"height": 107, "tx_index": 1, "output_index": 2}, - {"height": 5, "tx_index": 0, "output_index": 0} - ], - "outputs": [3000000000, 10000000, 3000000000] - }, - { - "inputs": [ - {"height": 107, "tx_index": 2, "output_index": 0}, - {"height": 107, "tx_index": 1, "output_index": 1}, - {"height": 6, "tx_index": 0, "output_index": 0} - ], - "outputs": [3000000000, 10000000, 3000000000] - } - ] - } - ] -} \ No newline at end of file diff --git a/test/testdata/tx_tests/tx_tests.json b/test/testdata/tx_tests/tx_tests.json deleted file mode 100644 index 5417ce2b..00000000 --- a/test/testdata/tx_tests/tx_tests.json +++ /dev/null @@ -1,229 +0,0 @@ -{ - "keys": [ - {"name": "alice", "password": "alice"}, - {"name": "bob", "password": "bob"} - ], - "accounts": [ - {"name": "alice", "keys": ["alice"], "quorum": 1}, - {"name": "bob", "keys": ["bob"], "quorum": 1}, - {"name": "multi-sig", "keys": ["alice", "bob"], "quorum": 2} - ], - "transactions": [ - { - "describe": "normal single sign btm tx", - "passwords": ["alice"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 100000000000, "asset": "BTM"} - ], - "outputs": [ - {"type": "output", "name": "bob", "amount": 40000000000, "asset": "BTM"} - ], - "valid": true, - "gas_only": false, - "tx_fee": 60000000000 - }, - { - "describe": "single sign btm tx, out of gas", - "passwords": ["alice"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 100000000000, "asset": "BTM"} - ], - "outputs": [ - {"type": "output", "name": "bob", "amount": 100000000000, "asset": "BTM"} - ], - "gas_only": false, - "valid": false - }, - { - "describe": "normal multi utxo btm tx", - "passwords": ["alice", "bob"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 100000000000, "asset": "BTM"}, - {"type": "spend_account", "name": "bob", "amount": 100000000000, "asset": "BTM"} - ], - "outputs": [ - {"type": "output", "name": "bob", "amount": 30000000000, "asset": "BTM"}, - {"type": "output", "name": "alice", "amount": 30000000000, "asset": "BTM"} - ], - "valid": true, - "gas_only": false, - "tx_fee": 140000000000 - }, - { - "describe": "single sign asset tx", - "passwords": ["alice"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 100000000000, "asset": "BTM"}, - {"type": "issue", "name": "alice", "amount": 100, "asset": "GOLD"} - ], - "outputs": [ - {"type": "output", "name": "alice", "amount": 30000000000, "asset": "BTM"}, - {"type": "output", "name": "alice", "amount": 100, "asset": "GOLD"} - ], - "valid": true, - "gas_only": false, - "tx_fee": 70000000000 - }, - { - "describe": "single sign asset, out of gas", - "passwords": ["alice"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 100000000000, "asset": "BTM"}, - {"type": "issue", "name": "alice", "amount": 100, "asset": "RMB"} - ], - "outputs": [ - {"type": "output", "name": "alice", "amount": 100000000000, "asset": "BTM"}, - {"type": "output", "name": "alice", "amount": 100, "asset": "RMB"} - ], - "valid": false, - "gas_only": false - }, - { - "describe": "single sign asset, input not equal with output", - "passwords": ["alice"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 100000000000, "asset": "BTM"}, - {"type": "issue", "name": "alice", "amount": 100, "asset": "SILVER"} - ], - "outputs": [ - {"type": "output", "name": "alice", "amount": 30000000000, "asset": "BTM"}, - {"type": "output", "name": "alice", "amount": 50, "asset": "SILVER"} - ], - "valid": false, - "gas_only": false - }, - { - "describe": "normal single sign with retire", - "passwords": ["alice"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 100000000000, "asset": "BTM"}, - {"type": "spend_account", "name": "alice", "amount": 100, "asset": "GOLD"} - ], - "outputs": [ - {"type": "output", "name": "alice", "amount": 30000000000, "asset": "BTM"}, - {"type": "retire", "name": "alice", "amount": 100, "asset": "GOLD"} - ], - "valid": true, - "gas_only": false, - "tx_fee": 70000000000 - }, - { - "describe": "gas only tx", - "passwords": ["alice"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 100000000000, "asset": "BTM"}, - {"type": "spend_account", "name": "bob", "amount": 100, "asset": "GOLD"} - ], - "outputs": [ - {"type": "output", "name": "alice", "amount": 30000000000, "asset": "BTM"}, - {"type": "retire", "name": "alice", "amount": 100, "asset": "GOLD"} - ], - "valid": false, - "gas_only": true, - "tx_fee": 70000000000 - }, - { - "describe": "normal multi-sig asset with issue and retire", - "passwords": ["alice", "bob"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 100000000000, "asset": "BTM"}, - {"type": "spend_account", "name": "bob", "amount": 100000000000, "asset": "BTM"}, - {"type": "issue", "name": "multi-sig", "amount": 100, "asset": "MULTI-SIGN-ASSET"}, - {"type": "spend_account", "name": "alice", "amount": 10, "asset": "GOLD"} - ], - "outputs": [ - {"type": "output", "name": "multi-sig", "amount": 199500000000, "asset": "BTM"}, - {"type": "output", "name": "multi-sig", "amount": 100, "asset": "MULTI-SIGN-ASSET"}, - {"type": "retire", "name": "alice", "amount": 10, "asset": "GOLD"} - ], - "valid": true, - "gas_only": false, - "tx_fee": 500000000 - }, - { - "describe": "multi-sig asset with issue and retire, out of gas", - "passwords": ["alice", "bob"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 100000000000, "asset": "BTM"}, - {"type": "spend_account", "name": "bob", "amount": 100000000000, "asset": "BTM"}, - {"type": "issue", "name": "multi-sig", "amount": 100, "asset": "DOLLAR"}, - {"type": "spend_account", "name": "alice", "amount": 10, "asset": "GOLD"} - ], - "outputs": [ - {"type": "output", "name": "multi-sig", "amount": 200000000000, "asset": "BTM"}, - {"type": "output", "name": "multi-sig", "amount": 100, "asset": "DOLLAR"}, - {"type": "retire", "name": "alice", "amount": 10, "asset": "GOLD"} - ], - "gas_only": false, - "valid": false - }, - { - "describe": "multi utxo btm tx, wrong sig", - "passwords": ["alice"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 100000000000, "asset": "BTM"}, - {"type": "spend_account", "name": "bob", "amount": 100000000000, "asset": "BTM"} - ], - "outputs": [ - {"type": "output", "name": "bob", "amount": 30000000000, "asset": "BTM"}, - {"type": "output", "name": "alice", "amount": 30000000000, "asset": "BTM"} - ], - "gas_only": false, - "valid": false - }, - { - "describe": "multi utxo btm tx, output large than input", - "passwords": ["alice", "bob"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 100000000000, "asset": "BTM"}, - {"type": "spend_account", "name": "bob", "amount": 100000000000, "asset": "BTM"} - ], - "outputs": [ - {"type": "output", "name": "bob", "amount": 90000000000, "asset": "BTM"}, - {"type": "output", "name": "alice", "amount": 200000000000, "asset": "BTM"} - ], - "gas_only": false, - "valid": false - }, - { - "describe": "version is 0", - "passwords": ["alice"], - "version": 0, - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 100000000000, "asset": "BTM"} - ], - "outputs": [ - {"type": "output", "name": "bob", "amount": 90000000000, "asset": "BTM"} - ], - "gas_only": false, - "valid": false - }, - { - "describe": "version is 1", - "passwords": ["alice"], - "version": 1, - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 100000000000, "asset": "BTM"} - ], - "outputs": [ - {"type": "output", "name": "bob", "amount": 90000000000, "asset": "BTM"} - ], - "tx_fee": 10000000000, - "gas_only": false, - "valid": true - }, - { - "describe": "version greater than block version(1)", - "passwords": ["alice"], - "version": 12, - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 100000000000, "asset": "BTM"} - ], - "outputs": [ - {"type": "output", "name": "bob", "amount": 90000000000, "asset": "BTM"} - ], - "gas_only": false, - "valid": false - } - ] -} \ No newline at end of file diff --git a/test/testdata/wallet_tests/wt_asset.json b/test/testdata/wallet_tests/wt_asset.json deleted file mode 100644 index ea766144..00000000 --- a/test/testdata/wallet_tests/wt_asset.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "keys": [ - {"name": "alice", "password": "alice"}, - {"name": "bob", "password": "bob"}, - {"name": "none", "password": "none"} - ], - "accounts": [ - {"name": "alice", "keys": ["alice"], "quorum": 1}, - {"name": "bob", "keys": ["bob"], "quorum": 1}, - {"name": "none", "keys": ["none"], "quorum": 1} - ], - "blocks": [ - { - "coinbase_account": "alice", - "post_states": [ - {"name": "alice", "asset": "BTM", "amount": 41250000000} - ], - "append": 100 - }, - { - "coinbase_account": "none", - "transactions": [ - { - "passwords": ["alice"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 6000000000, "asset": "BTM"} - ], - "outputs": [ - {"type": "output", "name": "bob", "amount": 500000000, "asset": "BTM"}, - {"type": "output", "name": "bob", "amount": 500000000, "asset": "BTM"}, - {"type": "output", "name": "alice", "amount": 2000000000, "asset": "BTM"}, - {"type": "output", "name": "alice", "amount": 2000000000, "asset": "BTM"} - ] - } - ], - "post_states": [ - {"name": "alice", "asset": "BTM", "amount": 39250000000}, - {"name": "bob", "asset": "BTM", "amount": 1000000000} - ] - }, - { - "coinbase_account": "none", - "transactions": [ - { - "passwords": ["alice"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 1000000000, "asset": "BTM"}, - {"type": "issue", "name": "alice", "amount": 100, "asset": "GOLD"} - ], - "outputs": [ - {"type": "output", "name": "alice", "amount": 100, "asset": "GOLD"} - ] - } - ], - "post_states": [ - {"name": "alice", "asset": "BTM", "amount": 38250000000}, - {"name": "alice", "asset": "GOLD", "amount": 100}, - {"name": "bob", "asset": "BTM", "amount": 1000000000} - ] - }, - { - "coinbase_account": "none", - "transactions": [ - { - "passwords": ["bob"], - "inputs": [ - {"type": "spend_account", "name": "bob", "amount": 400000000, "asset": "BTM"} - ], - "outputs": [ - {"type": "output", "name": "alice", "amount": 100000000, "asset": "BTM"}, - {"type": "output", "name": "bob", "amount": 200000000, "asset": "BTM"} - ] - }, - { - "passwords": ["alice", "bob"], - "inputs": [ - {"type": "spend_account", "name": "bob", "amount": 200000000, "asset": "BTM"}, - {"type": "spend_account", "name": "alice", "amount": 50, "asset": "GOLD"} - ], - "outputs": [ - {"type": "output", "name": "bob", "amount": 50, "asset": "GOLD"}, - {"type": "output", "name": "alice", "amount": 100000000, "asset": "BTM"} - ] - } - ], - "post_states": [ - {"name": "alice", "asset": "BTM", "amount": 38450000000}, - {"name": "alice", "asset": "GOLD", "amount": 50}, - {"name": "bob", "asset": "BTM", "amount": 600000000}, - {"name": "bob", "asset": "GOLD", "amount": 50} - ] - } - ] -} diff --git a/test/testdata/wallet_tests/wt_btm.json b/test/testdata/wallet_tests/wt_btm.json deleted file mode 100644 index 9acaea30..00000000 --- a/test/testdata/wallet_tests/wt_btm.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "keys": [ - {"name": "alice", "password": "alice"}, - {"name": "bob", "password": "bob"} - ], - "accounts": [ - {"name": "alice", "keys": ["alice"], "quorum": 1}, - {"name": "bob", "keys": ["bob"], "quorum": 1} - ], - "blocks": [ - { - "coinbase_account": "alice", - "post_states": [ - {"name": "alice", "asset": "BTM", "amount": 41250000000} - ], - "append": 100 - }, - { - "coinbase_account": "bob", - "transactions": [ - { - "passwords": ["alice"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 6000000000, "asset": "BTM"} - ], - "outputs": [ - {"type": "output", "name": "bob", "amount": 1000000000, "asset": "BTM"}, - {"type": "output", "name": "alice", "amount": 4000000000, "asset": "BTM"} - ] - } - ], - "post_states": [ - {"name": "alice", "asset": "BTM", "amount": 39250000000}, - {"name": "bob", "asset": "BTM", "amount": 43250000000} - ], - "append": 0 - } - ] -} diff --git a/test/testdata/wallet_tests/wt_invalid_txs.json b/test/testdata/wallet_tests/wt_invalid_txs.json deleted file mode 100644 index 5a687151..00000000 --- a/test/testdata/wallet_tests/wt_invalid_txs.json +++ /dev/null @@ -1,113 +0,0 @@ -{ - "keys": [ - {"name": "alice", "password": "alice"}, - {"name": "bob", "password": "bob"}, - {"name": "default", "password": "default"} - ], - "accounts": [ - {"name": "alice", "keys": ["alice"], "quorum": 1}, - {"name": "bob", "keys": ["bob"], "quorum": 1}, - {"name": "default", "keys": ["default"], "quorum": 1} - ], - "blocks": [ - { - "coinbase_account": "alice", - "post_states": [ - {"name": "alice", "asset": "BTM", "amount": 41250000000} - ], - "append": 100 - }, - { - "coinbase_account": "bob", - "transactions": [ - { - "passwords": ["alice"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 1000000000, "asset": "BTM"}, - {"type": "issue", "name": "alice", "amount": 100, "asset": "GOLD"} - ], - "outputs": [ - {"type": "output", "name": "alice", "amount": 100, "asset": "GOLD"} - ] - } - ], - "post_states": [ - {"name": "alice", "asset": "BTM", "amount": 40250000000}, - {"name": "alice", "asset": "GOLD", "amount": 100}, - {"name": "bob", "asset": "BTM", "amount": 42250000000} - ], - "append": 0 - }, - { - "coinbase_account": "default", - "transactions": [ - { - "passwords": ["alice"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 700000000000, "asset": "BTM"} - ], - "outputs": [ - {"type": "output", "name": "alice", "amount": 400000000000, "asset": "BTM"}, - {"type": "output", "name": "bob", "amount": 299000000000, "asset": "BTM"} - ] - }, - { - "passwords": ["alice"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 1000000000, "asset": "BTM"}, - {"type": "spend_account", "name": "alice", "amount": 100, "asset": "GOLD"} - ], - "outputs": [ - {"type": "retire", "name": "alice", "amount": 100, "asset": "GOLD"} - ] - } - ], - "post_states": [ - {"name": "alice", "asset": "BTM", "amount": 39250000000}, - {"name": "alice", "asset": "GOLD", "amount": 0}, - {"name": "bob", "asset": "BTM", "amount": 42250000000} - ], - "append": 0 - }, - { - "coinbase_account": "default", - "transactions": [ - { - "passwords": ["alice"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 1000000000, "asset": "BTM"}, - {"type": "spend_account", "name": "alice", "amount": 20, "asset": "GOLD"} - ], - "outputs": [ - {"type": "output", "name": "bob", "amount": 20, "asset": "GOLD"} - ] - } - ], - "post_states": [ - {"name": "alice", "asset": "BTM", "amount": 39250000000}, - {"name": "alice", "asset": "GOLD", "amount": 0}, - {"name": "bob", "asset": "BTM", "amount": 42250000000}, - {"name": "bob", "asset": "GOLD", "amount": 0} - ], - "append": 0 - }, - { - "coinbase_account": "default", - "transactions": [ - { - "passwords": ["alice"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 1000000000, "asset": "BTM"} - ] - } - ], - "post_states": [ - {"name": "alice", "asset": "BTM", "amount": 39250000000}, - {"name": "alice", "asset": "GOLD", "amount": 0}, - {"name": "bob", "asset": "BTM", "amount": 42250000000}, - {"name": "bob", "asset": "GOLD", "amount": 0} - ], - "append": 0 - } - ] -} diff --git a/test/testdata/wallet_tests/wt_multi_sig_asset.json b/test/testdata/wallet_tests/wt_multi_sig_asset.json deleted file mode 100644 index fbbaed9e..00000000 --- a/test/testdata/wallet_tests/wt_multi_sig_asset.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "keys": [ - {"name": "alice", "password": "alice"}, - {"name": "bob", "password": "bob"}, - {"name": "none", "password": "none"} - ], - "accounts": [ - {"name": "alice", "keys": ["alice"], "quorum": 1}, - {"name": "bob", "keys": ["bob"], "quorum": 1}, - {"name": "multi-sig", "keys": ["alice", "bob"], "quorum": 2}, - {"name": "none", "keys": ["none"], "quorum": 1} - ], - "blocks": [ - { - "coinbase_account": "alice", - "post_states": [ - {"name": "alice", "asset": "BTM", "amount": 41250000000} - ], - "append": 100 - }, - { - "coinbase_account": "none", - "transactions": [ - { - "passwords": ["alice"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 40000000000, "asset": "BTM"} - ], - "outputs": [ - {"type": "output", "name": "bob", "amount": 5000000000, "asset": "BTM"}, - {"type": "output", "name": "bob", "amount": 5000000000, "asset": "BTM"}, - {"type": "output", "name": "bob", "amount": 5000000000, "asset": "BTM"}, - {"type": "output", "name": "alice", "amount": 5000000000, "asset": "BTM"}, - {"type": "output", "name": "alice", "amount": 2000000000, "asset": "BTM"}, - {"type": "output", "name": "alice", "amount": 2000000000, "asset": "BTM"}, - {"type": "output", "name": "multi-sig", "amount": 5000000000, "asset": "BTM"}, - {"type": "output", "name": "multi-sig", "amount": 5000000000, "asset": "BTM"}, - {"type": "output", "name": "multi-sig", "amount": 5000000000, "asset": "BTM"} - ] - } - ], - "post_states": [ - {"name": "alice", "asset": "BTM", "amount": 10250000000}, - {"name": "bob", "asset": "BTM", "amount": 15000000000}, - {"name": "multi-sig", "asset": "BTM", "amount": 15000000000} - ] - }, - { - "coinbase_account": "none", - "transactions": [ - { - "passwords": ["bob", "alice"], - "inputs": [ - {"type": "spend_account", "name": "multi-sig", "amount": 1000000000, "asset": "BTM"}, - {"type": "issue", "name": "multi-sig", "amount": 100, "asset": "GOLD"} - ], - "outputs": [ - {"type": "output", "name": "multi-sig", "amount": 100, "asset": "GOLD"} - ] - } - ], - "post_states": [ - {"name": "alice", "asset": "BTM", "amount": 10250000000}, - {"name": "multi-sig", "asset": "GOLD", "amount": 100}, - {"name": "multi-sig", "asset": "BTM", "amount": 14000000000}, - {"name": "bob", "asset": "BTM", "amount": 15000000000} - ] - }, - { - "coinbase_account": "none", - "transactions": [ - { - "passwords": ["alice", "bob"], - "inputs": [ - {"type": "spend_account", "name": "multi-sig", "amount": 1000000000, "asset": "BTM"}, - {"type": "spend_account", "name": "multi-sig", "amount": 40, "asset": "GOLD"}, - {"type": "spend_account", "name": "bob", "amount": 10000000000, "asset": "BTM"}, - {"type": "spend_account", "name": "alice", "amount": 10000000000, "asset": "BTM"} - ], - "outputs": [ - {"type": "output", "name": "alice", "amount": 20, "asset": "GOLD"}, - {"type": "output", "name": "bob", "amount": 20, "asset": "GOLD"}, - {"type": "output", "name": "multi-sig", "amount": 20000000000, "asset": "BTM"} - ] - } - ], - "post_states": [ - {"name": "multi-sig", "asset": "BTM", "amount": 33000000000}, - {"name": "multi-sig", "asset": "GOLD", "amount": 60}, - {"name": "alice", "asset": "BTM", "amount": 250000000}, - {"name": "alice", "asset": "GOLD", "amount": 20}, - {"name": "bob", "asset": "BTM", "amount": 5000000000}, - {"name": "bob", "asset": "GOLD", "amount": 20} - ] - } - ] -} diff --git a/test/testdata/wallet_tests/wt_retire_asset.json b/test/testdata/wallet_tests/wt_retire_asset.json deleted file mode 100644 index 49fab7db..00000000 --- a/test/testdata/wallet_tests/wt_retire_asset.json +++ /dev/null @@ -1,118 +0,0 @@ -{ - "keys": [ - {"name": "alice", "password": "alice"}, - {"name": "bob", "password": "bob"}, - {"name": "none", "password": "none"} - ], - "accounts": [ - {"name": "alice", "keys": ["alice"], "quorum": 1}, - {"name": "bob", "keys": ["bob"], "quorum": 1}, - {"name": "none", "keys": ["none"], "quorum": 1} - ], - "blocks": [ - { - "coinbase_account": "alice", - "post_states": [ - {"name": "alice", "asset": "BTM", "amount": 41250000000} - ], - "append": 100 - }, - { - "coinbase_account": "none", - "transactions": [ - { - "passwords": ["alice"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 30000000000, "asset": "BTM"} - ], - "outputs": [ - {"type": "output", "name": "bob", "amount": 5000000000, "asset": "BTM"}, - {"type": "output", "name": "bob", "amount": 5000000000, "asset": "BTM"}, - {"type": "output", "name": "bob", "amount": 5000000000, "asset": "BTM"}, - {"type": "output", "name": "alice", "amount": 5000000000, "asset": "BTM"}, - {"type": "output", "name": "alice", "amount": 5000000000, "asset": "BTM"}, - {"type": "output", "name": "alice", "amount": 2000000000, "asset": "BTM"}, - {"type": "output", "name": "alice", "amount": 2000000000, "asset": "BTM"} - ] - } - ], - "post_states": [ - {"name": "alice", "asset": "BTM", "amount": 25250000000}, - {"name": "bob", "asset": "BTM", "amount": 15000000000} - ] - }, - { - "coinbase_account": "none", - "transactions": [ - { - "passwords": ["alice"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 1000000000, "asset": "BTM"}, - {"type": "issue", "name": "alice", "amount": 100, "asset": "GOLD"} - ], - "outputs": [ - {"type": "output", "name": "alice", "amount": 100, "asset": "GOLD"} - ] - } - ], - "post_states": [ - {"name": "alice", "asset": "BTM", "amount": 24250000000}, - {"name": "alice", "asset": "GOLD", "amount": 100}, - {"name": "bob", "asset": "BTM", "amount": 15000000000} - ] - }, - { - "coinbase_account": "none", - "transactions": [ - { - "passwords": ["bob"], - "inputs": [ - {"type": "spend_account", "name": "bob", "amount": 5000000000, "asset": "BTM"} - ], - "outputs": [ - {"type": "output", "name": "alice", "amount": 1000000000, "asset": "BTM"}, - {"type": "output", "name": "bob", "amount": 3000000000, "asset": "BTM"} - ] - }, - { - "passwords": ["alice", "bob"], - "inputs": [ - {"type": "spend_account", "name": "bob", "amount": 2000000000, "asset": "BTM"}, - {"type": "spend_account", "name": "alice", "amount": 50, "asset": "GOLD"} - ], - "outputs": [ - {"type": "output", "name": "bob", "amount": 50, "asset": "GOLD"}, - {"type": "output", "name": "alice", "amount": 1000000000, "asset": "BTM"} - ] - } - ], - "post_states": [ - {"name": "alice", "asset": "BTM", "amount": 26250000000}, - {"name": "alice", "asset": "GOLD", "amount": 50}, - {"name": "bob", "asset": "BTM", "amount": 11000000000}, - {"name": "bob", "asset": "GOLD", "amount": 50} - ] - }, - { - "coinbase_account": "none", - "transactions": [ - { - "passwords": ["alice"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 1000000000, "asset": "BTM"}, - {"type": "spend_account", "name": "alice", "amount": 20, "asset": "GOLD"} - ], - "outputs": [ - {"type": "retire", "name": "alice", "amount": 20, "asset": "GOLD"} - ] - } - ], - "post_states": [ - {"name": "alice", "asset": "BTM", "amount": 25250000000}, - {"name": "alice", "asset": "GOLD", "amount": 30}, - {"name": "bob", "asset": "BTM", "amount": 11000000000}, - {"name": "bob", "asset": "GOLD", "amount": 50} - ] - } - ] -} diff --git a/test/testdata/wallet_tests/wt_rollback.json b/test/testdata/wallet_tests/wt_rollback.json deleted file mode 100644 index dbbcfaf8..00000000 --- a/test/testdata/wallet_tests/wt_rollback.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "rollback": 102, - "keys": [ - {"name": "alice", "password": "alice"}, - {"name": "bob", "password": "bob"}, - {"name": "none", "password": "none"} - ], - "accounts": [ - {"name": "alice", "keys": ["alice"], "quorum": 1}, - {"name": "bob", "keys": ["bob"], "quorum": 1}, - {"name": "multi-sig", "keys": ["alice", "bob"], "quorum": 2}, - {"name": "none", "keys": ["none"], "quorum": 1} - ], - "blocks": [ - { - "coinbase_account": "alice", - "post_states": [ - {"name": "alice", "asset": "BTM", "amount": 41250000000} - ], - "append": 100 - }, - { - "coinbase_account": "none", - "transactions": [ - { - "passwords": ["alice"], - "inputs": [ - {"type": "spend_account", "name": "alice", "amount": 40000000000, "asset": "BTM"} - ], - "outputs": [ - {"type": "output", "name": "bob", "amount": 5000000000, "asset": "BTM"}, - {"type": "output", "name": "bob", "amount": 5000000000, "asset": "BTM"}, - {"type": "output", "name": "bob", "amount": 5000000000, "asset": "BTM"}, - {"type": "output", "name": "alice", "amount": 5000000000, "asset": "BTM"}, - {"type": "output", "name": "alice", "amount": 2000000000, "asset": "BTM"}, - {"type": "output", "name": "alice", "amount": 2000000000, "asset": "BTM"}, - {"type": "output", "name": "multi-sig", "amount": 5000000000, "asset": "BTM"}, - {"type": "output", "name": "multi-sig", "amount": 5000000000, "asset": "BTM"}, - {"type": "output", "name": "multi-sig", "amount": 5000000000, "asset": "BTM"} - ] - } - ], - "post_states": [ - {"name": "alice", "asset": "BTM", "amount": 10250000000}, - {"name": "bob", "asset": "BTM", "amount": 15000000000}, - {"name": "multi-sig", "asset": "BTM", "amount": 15000000000} - ] - }, - { - "coinbase_account": "none", - "transactions": [ - { - "passwords": ["bob", "alice"], - "inputs": [ - {"type": "spend_account", "name": "multi-sig", "amount": 1000000000, "asset": "BTM"}, - {"type": "issue", "name": "multi-sig", "amount": 100, "asset": "GOLD"} - ], - "outputs": [ - {"type": "output", "name": "multi-sig", "amount": 100, "asset": "GOLD"} - ] - } - ], - "post_states": [ - {"name": "alice", "asset": "BTM", "amount": 10250000000}, - {"name": "multi-sig", "asset": "GOLD", "amount": 100}, - {"name": "multi-sig", "asset": "BTM", "amount": 14000000000}, - {"name": "bob", "asset": "BTM", "amount": 15000000000} - ] - }, - { - "coinbase_account": "none", - "transactions": [ - { - "passwords": ["alice", "bob"], - "inputs": [ - {"type": "spend_account", "name": "multi-sig", "amount": 1000000000, "asset": "BTM"}, - {"type": "spend_account", "name": "multi-sig", "amount": 40, "asset": "GOLD"}, - {"type": "spend_account", "name": "bob", "amount": 10000000000, "asset": "BTM"}, - {"type": "spend_account", "name": "alice", "amount": 10000000000, "asset": "BTM"} - ], - "outputs": [ - {"type": "output", "name": "alice", "amount": 20, "asset": "GOLD"}, - {"type": "output", "name": "bob", "amount": 20, "asset": "GOLD"}, - {"type": "output", "name": "multi-sig", "amount": 20000000000, "asset": "BTM"} - ] - } - ], - "post_states": [ - {"name": "multi-sig", "asset": "BTM", "amount": 33000000000}, - {"name": "multi-sig", "asset": "GOLD", "amount": 60}, - {"name": "alice", "asset": "BTM", "amount": 250000000}, - {"name": "alice", "asset": "GOLD", "amount": 20}, - {"name": "bob", "asset": "BTM", "amount": 5000000000}, - {"name": "bob", "asset": "GOLD", "amount": 20} - ] - } - ] -} diff --git a/test/tx_test.go b/test/tx_test.go deleted file mode 100644 index c24768ca..00000000 --- a/test/tx_test.go +++ /dev/null @@ -1,264 +0,0 @@ -// +build functional - -package test - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "os" - "testing" - - log "github.com/sirupsen/logrus" - - "github.com/vapor/account" - "github.com/vapor/asset" - "github.com/vapor/blockchain/pseudohsm" - "github.com/vapor/consensus" - dbm "github.com/vapor/database/leveldb" - "github.com/vapor/protocol/bc" - "github.com/vapor/protocol/bc/types" - "github.com/vapor/protocol/validation" - "github.com/vapor/protocol/vm" -) - -func init() { - log.SetLevel(log.ErrorLevel) -} - -type TxTestConfig struct { - Keys []*keyInfo `json:"keys"` - Accounts []*accountInfo `json:"accounts"` - Transactions []*ttTransaction `json:"transactions"` -} - -func (cfg *TxTestConfig) Run() error { - dirPath, err := ioutil.TempDir(".", "pseudo_hsm") - if err != nil { - return err - } - defer os.RemoveAll(dirPath) - hsm, err := pseudohsm.New(dirPath) - if err != nil { - return err - } - - chainDB := dbm.NewDB("chain_db", "leveldb", "chain_db") - defer os.RemoveAll("chain_db") - chain, _, _, _ := MockChain(chainDB) - txTestDB := dbm.NewDB("tx_test_db", "leveldb", "tx_test_db") - defer os.RemoveAll("tx_test_db") - accountManager := account.NewManager(txTestDB, chain) - assets := asset.NewRegistry(txTestDB, chain) - - generator := NewTxGenerator(accountManager, assets, hsm) - for _, key := range cfg.Keys { - if err := generator.createKey(key.Name, key.Password); err != nil { - return err - } - } - - for _, acc := range cfg.Accounts { - if err := generator.createAccount(acc.Name, acc.Keys, acc.Quorum); err != nil { - return err - } - } - - block := &bc.Block{ - BlockHeader: &bc.BlockHeader{ - Height: 1, - Version: 1, - }, - } - for _, t := range cfg.Transactions { - tx, err := t.create(generator) - if err != nil { - return err - } - - tx.TxData.Version = t.Version - tx.Tx = types.MapTx(&tx.TxData) - status, err := validation.ValidateTx(tx.Tx, block) - result := err == nil - if result != t.Valid { - return fmt.Errorf("tx %s validate failed, expected: %t, have: %t", t.Describe, t.Valid, result) - } - if status == nil { - continue - } - - gasOnlyTx := false - if err != nil && status.GasValid { - gasOnlyTx = true - } - if gasOnlyTx != t.GasOnly { - return fmt.Errorf("gas only tx %s validate failed", t.Describe) - } - if result && t.TxFee != status.BTMValue { - return fmt.Errorf("gas used dismatch, expected: %d, have: %d", t.TxFee, status.BTMValue) - } - } - return nil -} - -type ttTransaction struct { - wtTransaction - Describe string `json:"describe"` - Version uint64 `json:"version"` - Valid bool `json:"valid"` - GasOnly bool `json:"gas_only"` - TxFee uint64 `json:"tx_fee"` -} - -// UnmarshalJSON unmarshal transaction with default version 1 -func (t *ttTransaction) UnmarshalJSON(data []byte) error { - type typeAlias ttTransaction - tx := &typeAlias{ - Version: 1, - } - - err := json.Unmarshal(data, tx) - if err != nil { - return err - } - *t = ttTransaction(*tx) - return nil -} - -func (t *ttTransaction) create(g *TxGenerator) (*types.Tx, error) { - g.Reset() - for _, input := range t.Inputs { - switch input.Type { - case "spend_account": - utxo, err := g.mockUtxo(input.AccountAlias, input.AssetAlias, input.Amount) - if err != nil { - return nil, err - } - if err := g.AddTxInputFromUtxo(utxo, input.AccountAlias); err != nil { - return nil, err - } - case "issue": - _, err := g.createAsset(input.AccountAlias, input.AssetAlias) - if err != nil { - return nil, err - } - if err := g.AddIssuanceInput(input.AssetAlias, input.Amount); err != nil { - return nil, err - } - } - } - - for _, output := range t.Outputs { - switch output.Type { - case "output": - if err := g.AddTxOutput(output.AccountAlias, output.AssetAlias, output.Amount); err != nil { - return nil, err - } - case "retire": - if err := g.AddRetirement(output.AssetAlias, output.Amount); err != nil { - return nil, err - } - } - } - return g.Sign(t.Passwords) -} - -func TestTx(t *testing.T) { - walk(t, txTestDir, func(t *testing.T, name string, test *TxTestConfig) { - if err := test.Run(); err != nil { - t.Fatal(err) - } - }) -} - -func TestCoinbaseMature(t *testing.T) { - db := dbm.NewDB("test_coinbase_mature_db", "leveldb", "test_coinbase_mature_db") - defer os.RemoveAll("test_coinbase_mature_db") - chain, _, _, _ := MockChain(db) - - defaultCtrlProg := []byte{byte(vm.OP_TRUE)} - if err := AppendBlocks(chain, 1); err != nil { - t.Fatal(err) - } - - height := chain.BestBlockHeight() - block, err := chain.GetBlockByHeight(height) - if err != nil { - t.Fatal(err) - } - - tx, err := CreateTxFromTx(block.Transactions[0], 0, 1000000000, defaultCtrlProg) - if err != nil { - t.Fatal(err) - } - - txs := []*types.Tx{tx} - matureHeight := chain.BestBlockHeight() + consensus.CoinbasePendingBlockNumber - currentHeight := chain.BestBlockHeight() - for h := currentHeight + 1; h < matureHeight; h++ { - block, err := NewBlock(chain, txs, defaultCtrlProg) - if err != nil { - t.Fatal(err) - } - if _, err := chain.ProcessBlock(block); err == nil { - t.Fatal("spent immature coinbase output success") - } - block, err = NewBlock(chain, nil, defaultCtrlProg) - if err != nil { - t.Fatal(err) - } - if _, err := chain.ProcessBlock(block); err != nil { - t.Fatal(err) - } - } - - block, err = NewBlock(chain, txs, defaultCtrlProg) - if err != nil { - t.Fatal(err) - } - if _, err := chain.ProcessBlock(block); err != nil { - t.Fatalf("spent mature coinbase output failed: %s", err) - } -} - -func TestCoinbaseTx(t *testing.T) { - db := dbm.NewDB("test_coinbase_tx_db", "leveldb", "test_coinbase_tx_db") - defer os.RemoveAll("test_coinbase_tx_db") - chain, _, _, _ := MockChain(db) - - defaultCtrlProg := []byte{byte(vm.OP_TRUE)} - if err := AppendBlocks(chain, 1); err != nil { - t.Fatal(err) - } - - block, err := chain.GetBlockByHeight(chain.BestBlockHeight()) - if err != nil { - t.Fatal(err) - } - - tx, err := CreateTxFromTx(block.Transactions[0], 0, 1000000000, defaultCtrlProg) - if err != nil { - t.Fatal(err) - } - - block, err = NewBlock(chain, []*types.Tx{tx}, defaultCtrlProg) - if err != nil { - t.Fatal(err) - } - - txFees := []uint64{100000, 5000000000000} - for _, txFee := range txFees { - coinbaseTx, err := CreateCoinbaseTx(defaultCtrlProg, block.Height, txFee) - if err != nil { - t.Fatal(err) - } - - if err := ReplaceCoinbase(block, coinbaseTx); err != nil { - t.Fatal(err) - } - - if _, err := chain.ProcessBlock(block); err == nil { - t.Fatalf("invalid coinbase tx validate success") - } - } -} diff --git a/test/tx_test_util.go b/test/tx_test_util.go index 3279fe7b..11c63136 100644 --- a/test/tx_test_util.go +++ b/test/tx_test_util.go @@ -1,7 +1,6 @@ package test import ( - "crypto/rand" "encoding/json" "fmt" "time" @@ -74,14 +73,6 @@ func (g *TxGenerator) createAccount(name string, keys []string, quorum int) erro return err } -func (g *TxGenerator) createAsset(accountAlias string, assetAlias string) (*asset.Asset, error) { - acc, err := g.AccountManager.FindByAlias(accountAlias) - if err != nil { - return nil, err - } - return g.Assets.Define(acc.XPubs, len(acc.XPubs), nil, 0, assetAlias, nil) -} - func (g *TxGenerator) mockUtxo(accountAlias, assetAlias string, amount uint64) (*account.UTXO, error) { ctrlProg, err := g.createControlProgram(accountAlias, false) if err != nil { @@ -182,26 +173,6 @@ func (g *TxGenerator) AddTxInputFromUtxo(utxo *account.UTXO, accountAlias string return g.AddTxInput(txInput, signInst) } -// AddIssuanceInput add a issue input -func (g *TxGenerator) AddIssuanceInput(assetAlias string, amount uint64) error { - asset, err := g.Assets.FindByAlias(assetAlias) - if err != nil { - return err - } - - var nonce [8]byte - _, err = rand.Read(nonce[:]) - if err != nil { - return err - } - issuanceInput := types.NewIssuanceInput(nonce[:], amount, asset.IssuanceProgram, nil, asset.RawDefinitionByte) - signInstruction := &txbuilder.SigningInstruction{} - path := signers.GetBip0032Path(asset.Signer, signers.AssetKeySpace) - signInstruction.AddRawWitnessKeys(asset.Signer.XPubs, path, asset.Signer.Quorum) - g.Builder.RestrictMinTime(time.Now()) - return g.Builder.AddInput(issuanceInput, signInstruction) -} - // AddTxOutput add a tx output func (g *TxGenerator) AddTxOutput(accountAlias, assetAlias string, amount uint64) error { assetAmount, err := g.assetAmount(assetAlias, uint64(amount)) diff --git a/test/wallet_test.go b/test/wallet_test.go deleted file mode 100644 index 9d2fca22..00000000 --- a/test/wallet_test.go +++ /dev/null @@ -1,18 +0,0 @@ -// +build functional - -package test - -import ( - "testing" - - log "github.com/sirupsen/logrus" -) - -func TestWallet(t *testing.T) { - log.SetLevel(log.ErrorLevel) - walk(t, walletTestDir, func(t *testing.T, name string, test *walletTestConfig) { - if err := test.Run(); err != nil { - t.Fatal(err) - } - }) -} diff --git a/test/wallet_test_util.go b/test/wallet_test_util.go index 9a2a0cc3..b03b430b 100644 --- a/test/wallet_test_util.go +++ b/test/wallet_test_util.go @@ -85,14 +85,6 @@ func (t *wtTransaction) create(ctx *walletTestContext) (*types.Tx, error) { if err := generator.AddSpendInput(input.AccountAlias, input.AssetAlias, input.Amount); err != nil { return nil, err } - case "issue": - _, err := ctx.createAsset(input.AccountAlias, input.AssetAlias) - if err != nil { - return nil, err - } - if err := generator.AddIssuanceInput(input.AssetAlias, input.Amount); err != nil { - return nil, err - } } } @@ -148,14 +140,6 @@ func (ctx *walletTestContext) getPubkey(keyAlias string) *chainkd.XPub { return nil } -func (ctx *walletTestContext) createAsset(accountAlias string, assetAlias string) (*asset.Asset, error) { - acc, err := ctx.Wallet.AccountMgr.FindByAlias(accountAlias) - if err != nil { - return nil, err - } - return ctx.Wallet.AssetReg.Define(acc.XPubs, len(acc.XPubs), nil, 0, assetAlias, nil) -} - func (ctx *walletTestContext) newBlock(txs []*types.Tx, coinbaseAccount string) (*types.Block, error) { controlProgram, err := ctx.createControlProgram(coinbaseAccount, true) if err != nil { diff --git a/wallet/annotated.go b/wallet/annotated.go index 849304d1..4d25ce80 100644 --- a/wallet/annotated.go +++ b/wallet/annotated.go @@ -9,7 +9,6 @@ import ( "github.com/vapor/account" "github.com/vapor/asset" "github.com/vapor/blockchain/query" - "github.com/vapor/blockchain/signers" "github.com/vapor/common" "github.com/vapor/consensus" "github.com/vapor/consensus/segwit" @@ -51,7 +50,6 @@ func (w *Wallet) getExternalDefinition(assetID *bc.AssetID) json.RawMessage { Alias: &alias, DefinitionMap: definitionMap, RawDefinitionByte: definitionByte, - Signer: &signers.Signer{Type: "external"}, } if err := w.AssetReg.SaveAsset(externalAsset, alias); err != nil { @@ -192,17 +190,6 @@ func (w *Wallet) BuildAnnotatedInput(tx *types.Tx, i uint32) *query.AnnotatedInp for _, arg := range arguments { in.WitnessArguments = append(in.WitnessArguments, arg) } - case *bc.Issuance: - in.Type = "issue" - in.IssuanceProgram = orig.IssuanceProgram() - arguments := orig.Arguments() - for _, arg := range arguments { - in.WitnessArguments = append(in.WitnessArguments, arg) - } - if assetDefinition := orig.AssetDefinition(); isValidJSON(assetDefinition) { - assetDefinition := json.RawMessage(assetDefinition) - in.AssetDefinition = &assetDefinition - } case *bc.Coinbase: in.Type = "coinbase" in.Arbitrary = e.Arbitrary diff --git a/wallet/indexer.go b/wallet/indexer.go index 2fde9ae4..ddf7248d 100644 --- a/wallet/indexer.go +++ b/wallet/indexer.go @@ -9,7 +9,6 @@ import ( log "github.com/sirupsen/logrus" "github.com/vapor/account" - "github.com/vapor/asset" "github.com/vapor/blockchain/query" "github.com/vapor/crypto/sha3pool" dbm "github.com/vapor/database/leveldb" @@ -87,15 +86,8 @@ func saveExternalAssetDefinition(b *types.Block, walletDB dbm.DB) { defer storeBatch.Write() for _, tx := range b.Transactions { - for _, orig := range tx.Inputs { - if ii, ok := orig.TypedInput.(*types.IssuanceInput); ok { - if isValidJSON(ii.AssetDefinition) { - assetID := ii.AssetID() - if assetExist := walletDB.Get(asset.ExtAssetKey(&assetID)); assetExist == nil { - storeBatch.Set(asset.ExtAssetKey(&assetID), ii.AssetDefinition) - } - } - } + for _, _ = range tx.Inputs { + // handle cross chain input here } } } diff --git a/wallet/unconfirmed_test.go b/wallet/unconfirmed_test.go index 0cc68bc6..60ece604 100644 --- a/wallet/unconfirmed_test.go +++ b/wallet/unconfirmed_test.go @@ -14,6 +14,7 @@ import ( "github.com/vapor/crypto/ed25519/chainkd" dbm "github.com/vapor/database/leveldb" "github.com/vapor/event" + "github.com/vapor/protocol/bc" "github.com/vapor/protocol/bc/types" "github.com/vapor/testutil" ) @@ -52,10 +53,7 @@ func TestWalletUnconfirmedTxs(t *testing.T) { controlProg.KeyIndex = 1 reg := asset.NewRegistry(testDB, nil) - asset, err := reg.Define([]chainkd.XPub{xpub1.XPub}, 1, nil, 0, "TESTASSET", nil) - if err != nil { - t.Fatal(err) - } + asset := bc.AssetID{V0: 5} dispatcher := event.NewDispatcher() w := mockWallet(testDB, accountManager, reg, nil, dispatcher, false) @@ -63,7 +61,7 @@ func TestWalletUnconfirmedTxs(t *testing.T) { btmUtxo := mockUTXO(controlProg, consensus.BTMAssetID) utxos = append(utxos, btmUtxo) - OtherUtxo := mockUTXO(controlProg, &asset.AssetID) + OtherUtxo := mockUTXO(controlProg, &asset) utxos = append(utxos, OtherUtxo) _, txData, err := mockTxData(utxos, testAccount) if err != nil { diff --git a/wallet/utxo_test.go b/wallet/utxo_test.go index fb8a224b..cabff152 100644 --- a/wallet/utxo_test.go +++ b/wallet/utxo_test.go @@ -396,18 +396,6 @@ func TestTxInToUtxos(t *testing.T) { { tx: types.NewTx(types.TxData{ Inputs: []*types.TxInput{ - types.NewIssuanceInput([]byte{}, 4125, []byte{0x51}, [][]byte{}, []byte{}), - }, - Outputs: []*types.TxOutput{ - types.NewIntraChainOutput(*consensus.BTMAssetID, 4125, []byte{0x51}), - }, - }), - statusFail: false, - wantUtxos: []*account.UTXO{}, - }, - { - tx: types.NewTx(types.TxData{ - Inputs: []*types.TxInput{ types.NewSpendInput([][]byte{}, bc.Hash{V0: 1}, bc.AssetID{V0: 1}, 1, 1, []byte{0x51}), types.NewSpendInput([][]byte{}, bc.Hash{V0: 2}, bc.AssetID{V0: 1}, 3, 2, []byte{0x52}), types.NewSpendInput([][]byte{}, bc.Hash{V0: 3}, *consensus.BTMAssetID, 5, 3, []byte{0x53}), diff --git a/wallet/wallet_test.go b/wallet/wallet_test.go index 9f818ead..a0a3708f 100644 --- a/wallet/wallet_test.go +++ b/wallet/wallet_test.go @@ -149,15 +149,12 @@ func TestWalletUpdate(t *testing.T) { controlProg.KeyIndex = 1 reg := asset.NewRegistry(testDB, chain) - asset, err := reg.Define([]chainkd.XPub{xpub1.XPub}, 1, nil, 0, "TESTASSET", nil) - if err != nil { - t.Fatal(err) - } + asset := bc.AssetID{V0: 5} utxos := []*account.UTXO{} btmUtxo := mockUTXO(controlProg, consensus.BTMAssetID) utxos = append(utxos, btmUtxo) - OtherUtxo := mockUTXO(controlProg, &asset.AssetID) + OtherUtxo := mockUTXO(controlProg, &asset) utxos = append(utxos, OtherUtxo) _, txData, err := mockTxData(utxos, testAccount) @@ -293,15 +290,12 @@ func TestMemPoolTxQueryLoop(t *testing.T) { controlProg.KeyIndex = 1 reg := asset.NewRegistry(testDB, chain) - asset, err := reg.Define([]chainkd.XPub{xpub1.XPub}, 1, nil, 0, "TESTASSET", nil) - if err != nil { - t.Fatal(err) - } + asset := bc.AssetID{V0: 5} utxos := []*account.UTXO{} btmUtxo := mockUTXO(controlProg, consensus.BTMAssetID) utxos = append(utxos, btmUtxo) - OtherUtxo := mockUTXO(controlProg, &asset.AssetID) + OtherUtxo := mockUTXO(controlProg, &asset) utxos = append(utxos, OtherUtxo) _, txData, err := mockTxData(utxos, testAccount) -- 2.11.0 From 86f47fea7c334231e3bf9b975d94c5b806b8d033 Mon Sep 17 00:00:00 2001 From: yahtoo Date: Thu, 16 May 2019 22:15:48 +0800 Subject: [PATCH 03/16] Optimize status message process (#66) * StatusResponseMessage del GenesisHash * Del useless broadcastMinedBlock msg * Add StatusMsg process * Add new status broadcast --- netsync/block_fetcher.go | 5 ++ netsync/block_keeper.go | 11 +-- netsync/handle.go | 49 ++++++------- netsync/message.go | 39 +++------- netsync/message_test.go | 173 ++++++++++++++++++++++++++++++++++++++++++++ netsync/peer.go | 53 +++++++++++--- netsync/protocol_reactor.go | 24 ++---- netsync/tool_test.go | 4 +- 8 files changed, 259 insertions(+), 99 deletions(-) create mode 100644 netsync/message_test.go diff --git a/netsync/block_fetcher.go b/netsync/block_fetcher.go index e7fe5858..c48cd0b6 100644 --- a/netsync/block_fetcher.go +++ b/netsync/block_fetcher.go @@ -92,6 +92,11 @@ func (f *blockFetcher) insert(msg *blockMsg) { log.WithFields(log.Fields{"module": logModule, "err": err}).Error("blockFetcher fail on broadcast new block") return } + + if err := f.peers.broadcastNewStatus(msg.block); err != nil { + log.WithFields(log.Fields{"module": logModule, "err": err}).Error("blockFetcher fail on broadcast new status") + return + } } func (f *blockFetcher) processNewBlock(msg *blockMsg) { diff --git a/netsync/block_keeper.go b/netsync/block_keeper.go index 62a4025c..9b61081e 100644 --- a/netsync/block_keeper.go +++ b/netsync/block_keeper.go @@ -379,11 +379,6 @@ func (bk *blockKeeper) startSync() bool { } func (bk *blockKeeper) syncWorker() { - genesisBlock, err := bk.chain.GetBlockByHeight(0) - if err != nil { - log.WithFields(log.Fields{"module": logModule, "err": err}).Error("fail on handleStatusRequestMsg get genesis") - return - } syncTicker := time.NewTicker(syncCycle) defer syncTicker.Stop() @@ -398,11 +393,7 @@ func (bk *blockKeeper) syncWorker() { log.WithFields(log.Fields{"module": logModule, "err": err}).Error("fail on syncWorker get best block") } - if err := bk.peers.broadcastMinedBlock(block); err != nil { - log.WithFields(log.Fields{"module": logModule, "err": err}).Error("fail on syncWorker broadcast new block") - } - - if err = bk.peers.broadcastNewStatus(block, genesisBlock); err != nil { + if err = bk.peers.broadcastNewStatus(block); err != nil { log.WithFields(log.Fields{"module": logModule, "err": err}).Error("fail on syncWorker broadcast new status") } } diff --git a/netsync/handle.go b/netsync/handle.go index db50d8a3..70702c99 100644 --- a/netsync/handle.go +++ b/netsync/handle.go @@ -109,6 +109,10 @@ func newSyncManager(config *cfg.Config, sw Switch, chain Chain, txPool *core.TxP return manager, nil } +func (sm *SyncManager) AddPeer(peer BasePeer) { + sm.peers.addPeer(peer) +} + //BestPeer return the highest p2p peerInfo func (sm *SyncManager) BestPeer() *PeerInfo { bestPeer := sm.peers.bestPeer(consensus.SFFullNode) @@ -303,32 +307,11 @@ func (sm *SyncManager) handleMineBlockMsg(peer *peer, msg *MineBlockMessage) { peer.setStatus(block.Height, &hash) } -func (sm *SyncManager) handleStatusRequestMsg(peer BasePeer) { - bestHeader := sm.chain.BestBlockHeader() - genesisBlock, err := sm.chain.GetBlockByHeight(0) - if err != nil { - log.WithFields(log.Fields{"module": logModule, "err": err}).Error("fail on handleStatusRequestMsg get genesis") - } - - genesisHash := genesisBlock.Hash() - msg := NewStatusResponseMessage(bestHeader, &genesisHash) - if ok := peer.TrySend(BlockchainChannel, struct{ BlockchainMessage }{msg}); !ok { - sm.peers.removePeer(peer.ID()) - } -} - -func (sm *SyncManager) handleStatusResponseMsg(basePeer BasePeer, msg *StatusResponseMessage) { +func (sm *SyncManager) handleStatusMsg(basePeer BasePeer, msg *StatusMessage) { if peer := sm.peers.getPeer(basePeer.ID()); peer != nil { peer.setStatus(msg.Height, msg.GetHash()) return } - - if genesisHash := msg.GetGenesisHash(); sm.genesisHash != *genesisHash { - log.WithFields(log.Fields{"module": logModule, "remote genesis": genesisHash.String(), "local genesis": sm.genesisHash.String()}).Warn("fail hand shake due to differnt genesis") - return - } - - sm.peers.addPeer(basePeer, msg.Height, msg.GetHash()) } func (sm *SyncManager) handleTransactionMsg(peer *peer, msg *TransactionMessage) { @@ -363,7 +346,7 @@ func (sm *SyncManager) PeerCount() int { func (sm *SyncManager) processMsg(basePeer BasePeer, msgType byte, msg BlockchainMessage) { peer := sm.peers.getPeer(basePeer.ID()) - if peer == nil && msgType != StatusResponseByte && msgType != StatusRequestByte { + if peer == nil { return } @@ -381,11 +364,8 @@ func (sm *SyncManager) processMsg(basePeer BasePeer, msgType byte, msg Blockchai case *BlockMessage: sm.handleBlockMsg(peer, msg) - case *StatusRequestMessage: - sm.handleStatusRequestMsg(basePeer) - - case *StatusResponseMessage: - sm.handleStatusResponseMsg(basePeer, msg) + case *StatusMessage: + sm.handleStatusMsg(basePeer, msg) case *TransactionMessage: sm.handleTransactionMsg(peer, msg) @@ -426,6 +406,19 @@ func (sm *SyncManager) processMsg(basePeer BasePeer, msgType byte, msg Blockchai } } +func (sm *SyncManager) SendStatus(peer BasePeer) error { + p := sm.peers.getPeer(peer.ID()) + if p == nil { + return errors.New("invalid peer") + } + + if err := p.sendStatus(sm.chain.BestBlockHeader()); err != nil { + sm.peers.removePeer(p.ID()) + return err + } + return nil +} + func (sm *SyncManager) Start() error { var err error if _, err = sm.sw.Start(); err != nil { diff --git a/netsync/message.go b/netsync/message.go index ed7b4a48..1c86d142 100644 --- a/netsync/message.go +++ b/netsync/message.go @@ -23,8 +23,7 @@ const ( HeadersResponseByte = byte(0x13) BlocksRequestByte = byte(0x14) BlocksResponseByte = byte(0x15) - StatusRequestByte = byte(0x20) - StatusResponseByte = byte(0x21) + StatusByte = byte(0x21) NewTransactionByte = byte(0x30) NewMineBlockByte = byte(0x40) FilterLoadByte = byte(0x50) @@ -49,8 +48,7 @@ var _ = wire.RegisterInterface( wire.ConcreteType{&HeadersMessage{}, HeadersResponseByte}, wire.ConcreteType{&GetBlocksMessage{}, BlocksRequestByte}, wire.ConcreteType{&BlocksMessage{}, BlocksResponseByte}, - wire.ConcreteType{&StatusRequestMessage{}, StatusRequestByte}, - wire.ConcreteType{&StatusResponseMessage{}, StatusResponseByte}, + wire.ConcreteType{&StatusMessage{}, StatusByte}, wire.ConcreteType{&TransactionMessage{}, NewTransactionByte}, wire.ConcreteType{&MineBlockMessage{}, NewMineBlockByte}, wire.ConcreteType{&FilterLoadMessage{}, FilterLoadByte}, @@ -274,42 +272,27 @@ func (m *BlocksMessage) String() string { return fmt.Sprintf("{blocks_length: %d}", len(m.RawBlocks)) } -//StatusRequestMessage status request msg -type StatusRequestMessage struct{} - -func (m *StatusRequestMessage) String() string { - return "{}" -} - //StatusResponseMessage get status response msg -type StatusResponseMessage struct { - Height uint64 - RawHash [32]byte - GenesisHash [32]byte +type StatusMessage struct { + Height uint64 + RawHash [32]byte } //NewStatusResponseMessage construct get status response msg -func NewStatusResponseMessage(blockHeader *types.BlockHeader, hash *bc.Hash) *StatusResponseMessage { - return &StatusResponseMessage{ - Height: blockHeader.Height, - RawHash: blockHeader.Hash().Byte32(), - GenesisHash: hash.Byte32(), +func NewStatusMessage(blockHeader *types.BlockHeader) *StatusMessage { + return &StatusMessage{ + Height: blockHeader.Height, + RawHash: blockHeader.Hash().Byte32(), } } //GetHash get hash from msg -func (m *StatusResponseMessage) GetHash() *bc.Hash { +func (m *StatusMessage) GetHash() *bc.Hash { hash := bc.NewHash(m.RawHash) return &hash } -//GetGenesisHash get hash from msg -func (m *StatusResponseMessage) GetGenesisHash() *bc.Hash { - hash := bc.NewHash(m.GenesisHash) - return &hash -} - -func (m *StatusResponseMessage) String() string { +func (m *StatusMessage) String() string { return fmt.Sprintf("{height: %d, hash: %s}", m.Height, hex.EncodeToString(m.RawHash[:])) } diff --git a/netsync/message_test.go b/netsync/message_test.go new file mode 100644 index 00000000..8743df70 --- /dev/null +++ b/netsync/message_test.go @@ -0,0 +1,173 @@ +package netsync + +import ( + "reflect" + "testing" + + "github.com/davecgh/go-spew/spew" + + "github.com/vapor/protocol/bc" + "github.com/vapor/protocol/bc/types" +) + +var testBlock = &types.Block{ + BlockHeader: types.BlockHeader{ + Version: 1, + Height: 0, + Timestamp: 1528945000, + BlockCommitment: types.BlockCommitment{ + TransactionsMerkleRoot: bc.Hash{V0: uint64(0x11)}, + TransactionStatusHash: bc.Hash{V0: uint64(0x55)}, + }, + }, +} + +func TestBlockMessage(t *testing.T) { + blockMsg, err := NewBlockMessage(testBlock) + if err != nil { + t.Fatalf("create new block msg err:%s", err) + } + + gotBlock, err := blockMsg.GetBlock() + if err != nil { + t.Fatalf("got block err:%s", err) + } + + if !reflect.DeepEqual(gotBlock.BlockHeader, testBlock.BlockHeader) { + t.Errorf("block msg test err: got %s\nwant %s", spew.Sdump(gotBlock.BlockHeader), spew.Sdump(testBlock.BlockHeader)) + } + + blockMsg.RawBlock[1] = blockMsg.RawBlock[1] + 0x1 + _, err = blockMsg.GetBlock() + if err == nil { + t.Fatalf("get mine block err") + } +} + +var testHeaders = []*types.BlockHeader{ + { + Version: 1, + Height: 0, + Timestamp: 1528945000, + BlockCommitment: types.BlockCommitment{ + TransactionsMerkleRoot: bc.Hash{V0: uint64(0x11)}, + TransactionStatusHash: bc.Hash{V0: uint64(0x55)}, + }, + }, + { + Version: 1, + Height: 1, + Timestamp: 1528945000, + BlockCommitment: types.BlockCommitment{ + TransactionsMerkleRoot: bc.Hash{V0: uint64(0x11)}, + TransactionStatusHash: bc.Hash{V0: uint64(0x55)}, + }, + }, + { + Version: 1, + Height: 3, + Timestamp: 1528945000, + BlockCommitment: types.BlockCommitment{ + TransactionsMerkleRoot: bc.Hash{V0: uint64(0x11)}, + TransactionStatusHash: bc.Hash{V0: uint64(0x55)}, + }, + }, +} + +func TestHeadersMessage(t *testing.T) { + headersMsg, err := NewHeadersMessage(testHeaders) + if err != nil { + t.Fatalf("create headers msg err:%s", err) + } + + gotHeaders, err := headersMsg.GetHeaders() + if err != nil { + t.Fatalf("got headers err:%s", err) + } + + if !reflect.DeepEqual(gotHeaders, testHeaders) { + t.Errorf("headers msg test err: got %s\nwant %s", spew.Sdump(gotHeaders), spew.Sdump(testHeaders)) + } +} + +func TestGetBlockMessage(t *testing.T) { + getBlockMsg := GetBlockMessage{RawHash: [32]byte{0x01}} + gotHash := getBlockMsg.GetHash() + + if !reflect.DeepEqual(gotHash.Byte32(), getBlockMsg.RawHash) { + t.Errorf("get block msg test err: got %s\nwant %s", spew.Sdump(gotHash.Byte32()), spew.Sdump(getBlockMsg.RawHash)) + } +} + +type testGetHeadersMessage struct { + blockLocator []*bc.Hash + stopHash *bc.Hash +} + +func TestGetHeadersMessage(t *testing.T) { + testMsg := testGetHeadersMessage{ + blockLocator: []*bc.Hash{{V0: 0x01}, {V0: 0x02}, {V0: 0x03}}, + stopHash: &bc.Hash{V0: 0xaa, V2: 0x55}, + } + getHeadersMsg := NewGetHeadersMessage(testMsg.blockLocator, testMsg.stopHash) + gotBlockLocator := getHeadersMsg.GetBlockLocator() + gotStopHash := getHeadersMsg.GetStopHash() + + if !reflect.DeepEqual(testMsg.blockLocator, gotBlockLocator) { + t.Errorf("get headers msg test err: got %s\nwant %s", spew.Sdump(gotBlockLocator), spew.Sdump(testMsg.blockLocator)) + } + + if !reflect.DeepEqual(testMsg.stopHash, gotStopHash) { + t.Errorf("get headers msg test err: got %s\nwant %s", spew.Sdump(gotStopHash), spew.Sdump(testMsg.stopHash)) + } +} + +var testBlocks = []*types.Block{ + { + BlockHeader: types.BlockHeader{ + Version: 1, + Height: 0, + Timestamp: 1528945000, + BlockCommitment: types.BlockCommitment{ + TransactionsMerkleRoot: bc.Hash{V0: uint64(0x11)}, + TransactionStatusHash: bc.Hash{V0: uint64(0x55)}, + }, + }, + }, + { + BlockHeader: types.BlockHeader{ + Version: 1, + Height: 0, + Timestamp: 1528945000, + BlockCommitment: types.BlockCommitment{ + TransactionsMerkleRoot: bc.Hash{V0: uint64(0x11)}, + TransactionStatusHash: bc.Hash{V0: uint64(0x55)}, + }, + }, + }, +} + +func TestBlocksMessage(t *testing.T) { + blocksMsg, err := NewBlocksMessage(testBlocks) + if err != nil { + t.Fatalf("create blocks msg err:%s", err) + } + gotBlocks, err := blocksMsg.GetBlocks() + if err != nil { + t.Fatalf("get blocks err:%s", err) + } + + for _, gotBlock := range gotBlocks { + if !reflect.DeepEqual(gotBlock.BlockHeader, testBlock.BlockHeader) { + t.Errorf("block msg test err: got %s\nwant %s", spew.Sdump(gotBlock.BlockHeader), spew.Sdump(testBlock.BlockHeader)) + } + } +} + +func TestStatusMessage(t *testing.T) { + statusResponseMsg := NewStatusMessage(&testBlock.BlockHeader) + gotHash := statusResponseMsg.GetHash() + if !reflect.DeepEqual(*gotHash, testBlock.Hash()) { + t.Errorf("status response msg test err: got %s\nwant %s", spew.Sdump(*gotHash), spew.Sdump(testBlock.Hash())) + } +} diff --git a/netsync/peer.go b/netsync/peer.go index b024989c..246f1bc1 100644 --- a/netsync/peer.go +++ b/netsync/peer.go @@ -23,6 +23,8 @@ const ( defaultBanThreshold = uint32(100) ) +var errSendStatusMsg = errors.New("send status msg fail") + //BasePeer is the interface for connection level peer type BasePeer interface { Addr() net.Addr @@ -63,15 +65,14 @@ type peer struct { banScore trust.DynamicBanScore knownTxs *set.Set // Set of transaction hashes known to be known by this peer knownBlocks *set.Set // Set of block hashes known to be known by this peer + knownStatus uint64 // Set of chain status known to be known by this peer filterAdds *set.Set // Set of addresses that the spv node cares about. } -func newPeer(height uint64, hash *bc.Hash, basePeer BasePeer) *peer { +func newPeer(basePeer BasePeer) *peer { return &peer{ BasePeer: basePeer, services: basePeer.ServiceFlag(), - height: height, - hash: hash, knownTxs: set.New(), knownBlocks: set.New(), filterAdds: set.New(), @@ -216,6 +217,13 @@ func (p *peer) markBlock(hash *bc.Hash) { p.knownBlocks.Add(hash.String()) } +func (p *peer) markNewStatus(height uint64) { + p.mtx.Lock() + defer p.mtx.Unlock() + + p.knownStatus = height +} + func (p *peer) markTransaction(hash *bc.Hash) { p.mtx.Lock() defer p.mtx.Unlock() @@ -310,6 +318,15 @@ func (p *peer) sendTransactions(txs []*types.Tx) (bool, error) { return true, nil } +func (p *peer) sendStatus(header *types.BlockHeader) error { + msg := NewStatusMessage(header) + if ok := p.TrySend(BlockchainChannel, struct{ BlockchainMessage }{msg}); !ok { + return errSendStatusMsg + } + p.markNewStatus(header.Height) + return nil +} + func (p *peer) setStatus(height uint64, hash *bc.Hash) { p.mtx.Lock() defer p.mtx.Unlock() @@ -348,12 +365,12 @@ func (ps *peerSet) addBanScore(peerID string, persistent, transient uint32, reas ps.removePeer(peerID) } -func (ps *peerSet) addPeer(peer BasePeer, height uint64, hash *bc.Hash) { +func (ps *peerSet) addPeer(peer BasePeer) { ps.mtx.Lock() defer ps.mtx.Unlock() if _, ok := ps.peers[peer.ID()]; !ok { - ps.peers[peer.ID()] = newPeer(height, hash, peer) + ps.peers[peer.ID()] = newPeer(peer) return } log.WithField("module", logModule).Warning("add existing peer to blockKeeper") @@ -393,22 +410,21 @@ func (ps *peerSet) broadcastMinedBlock(block *types.Block) error { continue } peer.markBlock(&hash) + peer.markNewStatus(block.Height) } return nil } -func (ps *peerSet) broadcastNewStatus(bestBlock, genesisBlock *types.Block) error { - bestBlockHash := bestBlock.Hash() - peers := ps.peersWithoutBlock(&bestBlockHash) - - genesisHash := genesisBlock.Hash() - msg := NewStatusResponseMessage(&bestBlock.BlockHeader, &genesisHash) +func (ps *peerSet) broadcastNewStatus(bestBlock *types.Block) error { + msg := NewStatusMessage(&bestBlock.BlockHeader) + peers := ps.peersWithoutNewStatus(bestBlock.Height) for _, peer := range peers { if ok := peer.TrySend(BlockchainChannel, struct{ BlockchainMessage }{msg}); !ok { - log.WithFields(log.Fields{"module": logModule, "peer": peer.Addr(), "type": reflect.TypeOf(msg), "message": msg.String()}).Warning("send message to peer error") ps.removePeer(peer.ID()) continue } + + peer.markNewStatus(bestBlock.Height) } return nil } @@ -478,6 +494,19 @@ func (ps *peerSet) peersWithoutBlock(hash *bc.Hash) []*peer { return peers } +func (ps *peerSet) peersWithoutNewStatus(height uint64) []*peer { + ps.mtx.RLock() + defer ps.mtx.RUnlock() + + var peers []*peer + for _, peer := range ps.peers { + if peer.knownStatus < height { + peers = append(peers, peer) + } + } + return peers +} + func (ps *peerSet) peersWithoutTx(hash *bc.Hash) []*peer { ps.mtx.RLock() defer ps.mtx.RUnlock() diff --git a/netsync/protocol_reactor.go b/netsync/protocol_reactor.go index cb9be4bd..8a6c610d 100644 --- a/netsync/protocol_reactor.go +++ b/netsync/protocol_reactor.go @@ -62,26 +62,12 @@ func (pr *ProtocolReactor) OnStop() { // AddPeer implements Reactor by sending our state to peer. func (pr *ProtocolReactor) AddPeer(peer *p2p.Peer) error { - if ok := peer.TrySend(BlockchainChannel, struct{ BlockchainMessage }{&StatusRequestMessage{}}); !ok { - return errStatusRequest - } - - checkTicker := time.NewTicker(handshakeCheckPerid) - defer checkTicker.Stop() - timeout := time.NewTimer(handshakeTimeout) - defer timeout.Stop() - for { - select { - case <-checkTicker.C: - if exist := pr.peers.getPeer(peer.Key); exist != nil { - pr.sm.syncTransactions(peer.Key) - return nil - } - - case <-timeout.C: - return errProtocolHandshakeTimeout - } + pr.sm.AddPeer(peer) + if err := pr.sm.SendStatus(peer); err != nil { + return err } + pr.sm.syncTransactions(peer.Key) + return nil } // RemovePeer implements Reactor by removing peer from the pool. diff --git a/netsync/tool_test.go b/netsync/tool_test.go index 69de67ef..e8179307 100644 --- a/netsync/tool_test.go +++ b/netsync/tool_test.go @@ -117,8 +117,8 @@ func (nw *NetWork) HandsShake(nodeA, nodeB *SyncManager) (*P2PPeer, *P2PPeer, er A2B.SetConnection(&B2A, nodeB) B2A.SetConnection(&A2B, nodeA) - nodeA.handleStatusRequestMsg(&A2B) - nodeB.handleStatusRequestMsg(&B2A) + nodeA.AddPeer(&A2B) + nodeB.AddPeer(&B2A) A2B.setAsync(true) B2A.setAsync(true) -- 2.11.0 From 161fb4f6668cb705e3e2203b6162ccd21f7df095 Mon Sep 17 00:00:00 2001 From: wz Date: Fri, 17 May 2019 10:57:28 +0800 Subject: [PATCH 04/16] V0.1 votetx input (#67) * add unvote struct * modify ComputeOutputID * add uint test * fix --- protocol/bc/types/map.go | 22 ++++++++++++++ protocol/bc/types/txinput.go | 62 +++++++++++++++++++++++++++++++++++--- protocol/bc/types/txinput_test.go | 57 +++++++++++++++++++++++++++++++++++ protocol/bc/types/txoutput.go | 12 ++++++-- protocol/bc/types/txoutput_test.go | 32 +++++++++++++++++++- protocol/bc/types/unvote.go | 38 +++++++++++++++++++++++ 6 files changed, 216 insertions(+), 7 deletions(-) create mode 100644 protocol/bc/types/unvote.go diff --git a/protocol/bc/types/map.go b/protocol/bc/types/map.go index b4a4ff07..348c203d 100644 --- a/protocol/bc/types/map.go +++ b/protocol/bc/types/map.go @@ -98,6 +98,28 @@ func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash Ref: &coinbaseID, Value: &value, } + + case *UnvoteInput: + // create entry for prevout + prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram} + src := &bc.ValueSource{ + Ref: &inp.SourceID, + Value: &inp.AssetAmount, + Position: inp.SourcePosition, + } + prevout := bc.NewVoteOutput(src, prog, 0, inp.Vote) // ordinal doesn't matter for prevouts, only for result outputs + prevoutID := addEntry(prevout) + // create entry for spend + spend := bc.NewSpend(&prevoutID, uint64(i)) + spend.WitnessArguments = inp.Arguments + spendID := addEntry(spend) + // setup mux + muxSources[i] = &bc.ValueSource{ + Ref: &spendID, + Value: &inp.AssetAmount, + } + spends = append(spends, spend) + } } diff --git a/protocol/bc/types/txinput.go b/protocol/bc/types/txinput.go index c9b4e8e6..2da01345 100644 --- a/protocol/bc/types/txinput.go +++ b/protocol/bc/types/txinput.go @@ -14,6 +14,7 @@ const ( IssuanceInputType uint8 = iota SpendInputType CoinbaseInputType + UnvoteInputType ) type ( @@ -38,6 +39,9 @@ func (t *TxInput) AssetAmount() bc.AssetAmount { switch inp := t.TypedInput.(type) { case *SpendInput: return inp.AssetAmount + + case *UnvoteInput: + return inp.AssetAmount } return bc.AssetAmount{} } @@ -48,6 +52,8 @@ func (t *TxInput) AssetID() bc.AssetID { case *SpendInput: return *inp.AssetId + case *UnvoteInput: + return *inp.AssetId } return bc.AssetID{} } @@ -57,15 +63,23 @@ func (t *TxInput) Amount() uint64 { switch inp := t.TypedInput.(type) { case *SpendInput: return inp.Amount + + case *UnvoteInput: + return inp.Amount } return 0 } // ControlProgram return the control program of the spend input func (t *TxInput) ControlProgram() []byte { - if si, ok := t.TypedInput.(*SpendInput); ok { - return si.ControlProgram + switch inp := t.TypedInput.(type) { + case *SpendInput: + return inp.ControlProgram + + case *UnvoteInput: + return inp.ControlProgram } + return nil } @@ -74,6 +88,9 @@ func (t *TxInput) Arguments() [][]byte { switch inp := t.TypedInput.(type) { case *SpendInput: return inp.Arguments + + case *UnvoteInput: + return inp.Arguments } return nil } @@ -83,14 +100,22 @@ func (t *TxInput) SetArguments(args [][]byte) { switch inp := t.TypedInput.(type) { case *SpendInput: inp.Arguments = args + + case *UnvoteInput: + inp.Arguments = args } } // SpentOutputID calculate the hash of spended output func (t *TxInput) SpentOutputID() (o bc.Hash, err error) { - if si, ok := t.TypedInput.(*SpendInput); ok { - o, err = ComputeOutputID(&si.SpendCommitment) + switch inp := t.TypedInput.(type) { + case *SpendInput: + o, err = ComputeOutputID(&inp.SpendCommitment, SpendInputType, nil) + + case *UnvoteInput: + o, err = ComputeOutputID(&inp.SpendCommitment, UnvoteInputType, inp.Vote) } + return o, err } @@ -122,6 +147,13 @@ func (t *TxInput) readFrom(r *blockchain.Reader) (err error) { return err } + case UnvoteInputType: + ui := new(UnvoteInput) + t.TypedInput = ui + if ui.UnvoteCommitmentSuffix, err = ui.SpendCommitment.readFrom(r, 1); err != nil { + return err + } + default: return fmt.Errorf("unsupported input type %d", icType[0]) } @@ -141,6 +173,15 @@ func (t *TxInput) readFrom(r *blockchain.Reader) (err error) { if inp.Arguments, err = blockchain.ReadVarstrList(r); err != nil { return err } + + case *UnvoteInput: + if inp.Arguments, err = blockchain.ReadVarstrList(r); err != nil { + return err + } + if inp.Vote, err = blockchain.ReadVarstr31(r); err != nil { + return err + } + } return nil }) @@ -180,6 +221,12 @@ func (t *TxInput) writeInputCommitment(w io.Writer) (err error) { if _, err = blockchain.WriteVarstr31(w, inp.Arbitrary); err != nil { return errors.Wrap(err, "writing coinbase arbitrary") } + + case *UnvoteInput: + if _, err = w.Write([]byte{UnvoteInputType}); err != nil { + return err + } + return inp.SpendCommitment.writeExtensibleString(w, inp.UnvoteCommitmentSuffix, t.AssetVersion) } return nil } @@ -193,6 +240,13 @@ func (t *TxInput) writeInputWitness(w io.Writer) error { case *SpendInput: _, err := blockchain.WriteVarstrList(w, inp.Arguments) return err + + case *UnvoteInput: + if _, err := blockchain.WriteVarstrList(w, inp.Arguments); err != nil { + return err + } + _, err := blockchain.WriteVarstr31(w, inp.Vote) + return err } return nil } diff --git a/protocol/bc/types/txinput_test.go b/protocol/bc/types/txinput_test.go index 110b8b38..ec78bbef 100644 --- a/protocol/bc/types/txinput_test.go +++ b/protocol/bc/types/txinput_test.go @@ -66,6 +66,63 @@ func TestSerializationSpend(t *testing.T) { } } +func TestSerializationUnvote(t *testing.T) { + arguments := [][]byte{ + []byte("arguments1"), + []byte("arguments2"), + } + + unvote := NewUnvoteInput(arguments, testutil.MustDecodeHash("fad5195a0c8e3b590b86a3c0a95e7529565888508aecca96e9aeda633002f409"), testutil.MustDecodeAsset("fe9791d71b67ee62515e08723c061b5ccb952a80d804417c8aeedf7f633c524a"), 254354, 3, []byte("spendProgram"), []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269")) + + wantHex := strings.Join([]string{ + "01", // asset version + "54", // input commitment length + "03", // unvote type flag + "52", // unvote commitment length + "fad5195a0c8e3b590b86a3c0a95e7529565888508aecca96e9aeda633002f409", // source id + "fe9791d71b67ee62515e08723c061b5ccb952a80d804417c8aeedf7f633c524a", // assetID + "92c30f", // amount + "03", // source position + "01", // vm version + "0c", // unvote program length + "7370656e6450726f6772616d", // unvote program + "9901", // witness length + "02", // argument array length + "0a", // first argument length + "617267756d656e747331", // first argument data + "0a", // second argument length + "617267756d656e747332", // second argument data + "8001", //xpub length + "6166353934303036613430383337643966303238646161626236643538396466306239313338646165666164353638336535323333633236343632373932313732393461386435333265363038363362636631393636323561333566623863656566666133633039363130656239326463666236353561393437663133323639", //voter xpub + }, "") + + // Test convert struct to hex + var buffer bytes.Buffer + if err := unvote.writeTo(&buffer); err != nil { + t.Fatal(err) + } + + gotHex := hex.EncodeToString(buffer.Bytes()) + if gotHex != wantHex { + t.Errorf("serialization bytes = %s want %s", gotHex, wantHex) + } + + // Test convert hex to struct + var gotUnvote TxInput + decodeHex, err := hex.DecodeString(wantHex) + if err != nil { + t.Fatal(err) + } + + if err := gotUnvote.readFrom(blockchain.NewReader(decodeHex)); err != nil { + t.Fatal(err) + } + + if !testutil.DeepEqual(*unvote, gotUnvote) { + t.Errorf("expected marshaled/unmarshaled txinput to be:\n%sgot:\n%s", spew.Sdump(*unvote), spew.Sdump(gotUnvote)) + } +} + func TestSerializationCoinbase(t *testing.T) { coinbase := NewCoinbaseInput([]byte("arbitrary")) wantHex := strings.Join([]string{ diff --git a/protocol/bc/types/txoutput.go b/protocol/bc/types/txoutput.go index 7cc2b618..aca99209 100644 --- a/protocol/bc/types/txoutput.go +++ b/protocol/bc/types/txoutput.go @@ -206,7 +206,7 @@ func (to *TxOutput) writeOutputCommitment(w io.Writer) error { // ComputeOutputID assembles an intra-chain(!) output entry given a spend // commitment and computes and returns its corresponding entry ID. -func ComputeOutputID(sc *SpendCommitment) (h bc.Hash, err error) { +func ComputeOutputID(sc *SpendCommitment, inputType uint8, vote []byte) (h bc.Hash, err error) { defer func() { if r, ok := recover().(error); ok { err = r @@ -217,7 +217,15 @@ func ComputeOutputID(sc *SpendCommitment) (h bc.Hash, err error) { Value: &sc.AssetAmount, Position: sc.SourcePosition, } - o := bc.NewIntraChainOutput(src, &bc.Program{VmVersion: sc.VMVersion, Code: sc.ControlProgram}, 0) + var o bc.Entry + switch inputType { + case SpendInputType: + o = bc.NewIntraChainOutput(src, &bc.Program{VmVersion: sc.VMVersion, Code: sc.ControlProgram}, 0) + case UnvoteInputType: + o = bc.NewVoteOutput(src, &bc.Program{VmVersion: sc.VMVersion, Code: sc.ControlProgram}, 0, vote) + default: + return h, fmt.Errorf("Input type error:[%v]", inputType) + } h = bc.EntryID(o) return h, nil diff --git a/protocol/bc/types/txoutput_test.go b/protocol/bc/types/txoutput_test.go index b978073a..a6c4eba0 100644 --- a/protocol/bc/types/txoutput_test.go +++ b/protocol/bc/types/txoutput_test.go @@ -106,6 +106,8 @@ func TestComputeOutputID(t *testing.T) { btmAssetID := testutil.MustDecodeAsset("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") cases := []struct { sc *SpendCommitment + inputType uint8 + vote []byte wantOutputID string }{ { @@ -116,6 +118,8 @@ func TestComputeOutputID(t *testing.T) { VMVersion: 1, ControlProgram: testutil.MustDecodeHexString("0014cb9f2391bafe2bc1159b2c4c8a0f17ba1b4dd94e"), }, + inputType: SpendInputType, + vote: nil, wantOutputID: "73eea4d38b22ffd60fc30d0941f3875f45e29d424227bfde100193a08568605b", }, { @@ -126,12 +130,38 @@ func TestComputeOutputID(t *testing.T) { VMVersion: 1, ControlProgram: testutil.MustDecodeHexString("001418549d84daf53344d32563830c7cf979dc19d5c0"), }, + inputType: SpendInputType, + vote: nil, wantOutputID: "8371e76fd1c873503a326268bfd286ffe13009a0f1140d2c858e8187825696ab", }, + { + sc: &SpendCommitment{ + AssetAmount: bc.AssetAmount{AssetId: &btmAssetID, Amount: 999}, + SourceID: testutil.MustDecodeHash("993d3797fa3b2d958f300e599987dc10904b13f56ce89d158f60f9131424e0e2"), + SourcePosition: 2, + VMVersion: 1, + ControlProgram: testutil.MustDecodeHexString("00145c47f3a0dd3e1e9956fe5b0f897072ed33f9efb9"), + }, + inputType: UnvoteInputType, + vote: []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"), + wantOutputID: "c95701822db14f5c647158762e4d4b9bff270bfd3040f0ca32cb87c18e377429", + }, + { + sc: &SpendCommitment{ + AssetAmount: bc.AssetAmount{AssetId: &btmAssetID, Amount: 999}, + SourceID: testutil.MustDecodeHash("993d3797fa3b2d958f300e599987dc10904b13f56ce89d158f60f9131424e0e2"), + SourcePosition: 2, + VMVersion: 1, + ControlProgram: testutil.MustDecodeHexString("00145c47f3a0dd3e1e9956fe5b0f897072ed33f9efb9"), + }, + inputType: UnvoteInputType, + vote: []byte(""), + wantOutputID: "8f17b871f3fd07bfe778e92c272e26d4bb19258c90af08310ef32feb526eaf9c", + }, } for _, c := range cases { - outputID, err := ComputeOutputID(c.sc) + outputID, err := ComputeOutputID(c.sc, c.inputType, c.vote) if err != nil { t.Fatal(err) } diff --git a/protocol/bc/types/unvote.go b/protocol/bc/types/unvote.go new file mode 100644 index 00000000..810a8f39 --- /dev/null +++ b/protocol/bc/types/unvote.go @@ -0,0 +1,38 @@ +package types + +import ( + "github.com/vapor/protocol/bc" +) + +// UnvoteInput satisfies the TypedInput interface and represents a unvote transaction. +type UnvoteInput struct { + UnvoteCommitmentSuffix []byte // The unconsumed suffix of the output commitment + Arguments [][]byte // Witness + Vote []byte // voter xpub + SpendCommitment +} + +// NewUnvoteInput create a new UnvoteInput struct. +func NewUnvoteInput(arguments [][]byte, sourceID bc.Hash, assetID bc.AssetID, amount, sourcePos uint64, controlProgram []byte, vote []byte) *TxInput { + sc := SpendCommitment{ + AssetAmount: bc.AssetAmount{ + AssetId: &assetID, + Amount: amount, + }, + SourceID: sourceID, + SourcePosition: sourcePos, + VMVersion: 1, + ControlProgram: controlProgram, + } + return &TxInput{ + AssetVersion: 1, + TypedInput: &UnvoteInput{ + SpendCommitment: sc, + Arguments: arguments, + Vote: vote, + }, + } +} + +// InputType is the interface function for return the input type. +func (ui *UnvoteInput) InputType() uint8 { return SpendInputType } -- 2.11.0 From 627c2746596ce7cf687cc6afd7c93754510eea63 Mon Sep 17 00:00:00 2001 From: yahtoo Date: Fri, 17 May 2019 12:19:22 +0800 Subject: [PATCH 05/16] Nodeinfo handshake information modification (#68) * Nodeinfo handshake information modification * Add moniker to config file * Add node info test file * Del useless code * opz code format * opz log print --- cmd/bytomd/commands/run_node.go | 3 -- config/config.go | 5 --- config/toml.go | 2 +- netsync/handle.go | 5 --- node/node.go | 5 --- p2p/node_info.go | 68 +++++++++++++++++++---------------------- p2p/node_info_test.go | 63 ++++++++++++++++++++++++++++++++++++++ p2p/peer.go | 17 +++++------ p2p/switch.go | 14 +++------ 9 files changed, 108 insertions(+), 74 deletions(-) create mode 100644 p2p/node_info_test.go diff --git a/cmd/bytomd/commands/run_node.go b/cmd/bytomd/commands/run_node.go index fc8e8647..a129307b 100644 --- a/cmd/bytomd/commands/run_node.go +++ b/cmd/bytomd/commands/run_node.go @@ -85,11 +85,8 @@ func runNode(cmd *cobra.Command, args []string) error { log.WithFields(log.Fields{"module": logModule, "err": err}).Fatal("failed to start node") } - nodeInfo := n.NodeInfo() log.WithFields(log.Fields{ "module": logModule, - "version": nodeInfo.Version, - "network": nodeInfo.Network, "duration": time.Since(startTime), }).Info("start node complete") diff --git a/config/config.go b/config/config.go index 3b4b28b9..03d7d6fb 100644 --- a/config/config.go +++ b/config/config.go @@ -85,9 +85,6 @@ type BaseConfig struct { // This should be set in viper so it can unmarshal into this struct RootDir string `mapstructure:"home"` - //The alias of the node - NodeAlias string `mapstructure:"node_alias"` - //The ID of the network to json ChainID string `mapstructure:"chain_id"` @@ -131,8 +128,6 @@ func DefaultBaseConfig() BaseConfig { DBBackend: "leveldb", DBPath: "data", KeysPath: "keystore", - NodeAlias: "", - // CipherServiceProvider: "ed25519", } } diff --git a/config/toml.go b/config/toml.go index 1d9b0c6d..ceb448c5 100644 --- a/config/toml.go +++ b/config/toml.go @@ -24,7 +24,7 @@ var defaultConfigTmpl = `# This is a TOML config file. fast_sync = true db_backend = "leveldb" api_addr = "0.0.0.0:9888" -node_alias = "" +moniker = "" ` var mainNetConfigTmpl = `chain_id = "mainnet" diff --git a/netsync/handle.go b/netsync/handle.go index 70702c99..ce10e1ac 100644 --- a/netsync/handle.go +++ b/netsync/handle.go @@ -44,7 +44,6 @@ type Switch interface { AddReactor(name string, reactor p2p.Reactor) p2p.Reactor AddBannedPeer(string) error StopPeerGracefully(string) - NodeInfo() *p2p.NodeInfo Start() (bool, error) Stop() bool IsListening() bool @@ -333,10 +332,6 @@ func (sm *SyncManager) IsListening() bool { return sm.sw.IsListening() } -func (sm *SyncManager) NodeInfo() *p2p.NodeInfo { - return sm.sw.NodeInfo() -} - func (sm *SyncManager) PeerCount() int { if sm.config.VaultMode { return 0 diff --git a/node/node.go b/node/node.go index 92a45932..b590a7c2 100644 --- a/node/node.go +++ b/node/node.go @@ -29,7 +29,6 @@ import ( "github.com/vapor/mining/cpuminer" "github.com/vapor/net/websocket" "github.com/vapor/netsync" - "github.com/vapor/p2p" "github.com/vapor/protocol" w "github.com/vapor/wallet" ) @@ -257,7 +256,3 @@ func (n *Node) RunForever() { n.Stop() }) } - -func (n *Node) NodeInfo() *p2p.NodeInfo { - return n.syncManager.NodeInfo() -} diff --git a/p2p/node_info.go b/p2p/node_info.go index 2e52e31d..5caed49d 100644 --- a/p2p/node_info.go +++ b/p2p/node_info.go @@ -3,92 +3,88 @@ package p2p import ( "fmt" "net" - "strconv" "github.com/tendermint/go-crypto" cfg "github.com/vapor/config" "github.com/vapor/consensus" + "github.com/vapor/errors" "github.com/vapor/version" ) const maxNodeInfoSize = 10240 // 10Kb +var ( + errDiffMajorVersion = errors.New("Peer is on a different major version.") + errDiffNetwork = errors.New("Peer is on a different network name.") + errDiffNetworkID = errors.New("Peer has different network ID.") +) + //NodeInfo peer node info type NodeInfo struct { PubKey crypto.PubKeyEd25519 `json:"pub_key"` Moniker string `json:"moniker"` Network string `json:"network"` //NetworkID used to isolate subnets with same network name - NetworkID uint64 `json:"network_id"` - RemoteAddr string `json:"remote_addr"` - ListenAddr string `json:"listen_addr"` - Version string `json:"version"` // major.minor.revision + NetworkID uint64 `json:"network_id"` + RemoteAddr string `json:"remote_addr"` + ListenAddr string `json:"listen_addr"` + Version string `json:"version"` // major.minor.revision + ServiceFlag consensus.ServiceFlag `json:"service_flag"` // other application specific data - //field 0: node service flags. field 1: node alias. Other []string `json:"other"` } func NewNodeInfo(config *cfg.Config, pubkey crypto.PubKeyEd25519, listenAddr string, netID uint64) *NodeInfo { - other := []string{strconv.FormatUint(uint64(consensus.DefaultServices), 10)} - if config.NodeAlias != "" { - other = append(other, config.NodeAlias) - } return &NodeInfo{ - PubKey: pubkey, - Moniker: config.Moniker, - Network: config.ChainID, - NetworkID: netID, - ListenAddr: listenAddr, - Version: version.Version, - Other: other, + PubKey: pubkey, + Moniker: config.Moniker, + Network: config.ChainID, + NetworkID: netID, + ListenAddr: listenAddr, + Version: version.Version, + ServiceFlag: consensus.DefaultServices, } } +type VersionCompatibleWith func(remoteVerStr string) (bool, error) + // CompatibleWith checks if two NodeInfo are compatible with eachother. // CONTRACT: two nodes are compatible if the major version matches and network match -func (info *NodeInfo) CompatibleWith(other *NodeInfo) error { +func (info *NodeInfo) compatibleWith(other *NodeInfo, versionCompatibleWith VersionCompatibleWith) error { if info.Network != other.Network { - return fmt.Errorf("Peer is on a different network. Peer network: %v, node network: %v", other.Network, info.Network) + return errors.Wrapf(errDiffNetwork, "Peer network: %v, node network: %v", other.Network, info.Network) } if info.NetworkID != other.NetworkID { - return fmt.Errorf("Network id dismatch. Peer network id: %v, node network id: %v", other.NetworkID, info.NetworkID) + return errors.Wrapf(errDiffNetworkID, "Peer network id: %v, node network id: %v", other.NetworkID, info.NetworkID) } - compatible, err := version.CompatibleWith(other.Version) + compatible, err := versionCompatibleWith(other.Version) if err != nil { return err } + if !compatible { - return fmt.Errorf("Peer is on a different major version. Peer version: %v, node version: %v", other.Version, info.Version) + return errors.Wrapf(errDiffMajorVersion, "Peer version: %v, node version: %v", other.Version, info.Version) } return nil } -func (info *NodeInfo) getPubkey() crypto.PubKeyEd25519 { - return info.PubKey -} - -//ListenHost peer listener ip address -func (info *NodeInfo) listenHost() string { +//listenHost peer listener ip address +func (info NodeInfo) listenHost() string { host, _, _ := net.SplitHostPort(info.ListenAddr) return host } -//RemoteAddrHost peer external ip address -func (info *NodeInfo) remoteAddrHost() string { +//remoteAddrHost peer external ip address +func (info NodeInfo) remoteAddrHost() string { host, _, _ := net.SplitHostPort(info.RemoteAddr) return host } -//GetNetwork get node info network field -func (info *NodeInfo) GetNetwork() string { - return info.Network -} - //String representation func (info NodeInfo) String() string { - return fmt.Sprintf("NodeInfo{pk: %v, moniker: %v, network: %v [listen %v], version: %v (%v)}", info.PubKey, info.Moniker, info.Network, info.ListenAddr, info.Version, info.Other) + return fmt.Sprintf("NodeInfo{pk: %v, moniker: %v, network: %v [listen %v],networkID: %x, service: %v,version: %v (%v)}", info.PubKey, info.Moniker, info.Network, info.ListenAddr, info.NetworkID, info.ServiceFlag, info.Version, info.Other) } diff --git a/p2p/node_info_test.go b/p2p/node_info_test.go new file mode 100644 index 00000000..f31aa9fb --- /dev/null +++ b/p2p/node_info_test.go @@ -0,0 +1,63 @@ +package p2p + +import ( + "bytes" + "reflect" + "testing" + + "github.com/davecgh/go-spew/spew" + "github.com/tendermint/go-crypto" + "github.com/tendermint/go-wire" + + "github.com/vapor/errors" +) + +func mockCompatibleWithFalse(remoteVerStr string) (bool, error) { + return false, nil +} + +func mockCompatibleWithTrue(remoteVerStr string) (bool, error) { + return true, nil +} + +func TestCompatibleWith(t *testing.T) { + nodeInfo := &NodeInfo{Network: "testnet", NetworkID: 0x888} + + cases := []struct { + other *NodeInfo + versionCompatibleWith VersionCompatibleWith + err error + }{ + {other: &NodeInfo{Network: "mainnet", NetworkID: 0x888}, versionCompatibleWith: mockCompatibleWithTrue, err: errDiffNetwork}, + {other: &NodeInfo{Network: "testnet", NetworkID: 0x888}, versionCompatibleWith: mockCompatibleWithTrue, err: nil}, + {other: &NodeInfo{Network: "testnet", NetworkID: 0x999}, versionCompatibleWith: mockCompatibleWithTrue, err: errDiffNetworkID}, + {other: &NodeInfo{Network: "testnet", NetworkID: 0x888}, versionCompatibleWith: mockCompatibleWithFalse, err: errDiffMajorVersion}, + } + + for i, c := range cases { + if err := nodeInfo.compatibleWith(c.other, c.versionCompatibleWith); errors.Root(err) != c.err { + t.Fatalf("index:%d node info compatible test err want:%s result:%s", i, c.err, err) + } + } +} + +func TestNodeInfoWriteRead(t *testing.T) { + nodeInfo := &NodeInfo{PubKey: crypto.GenPrivKeyEd25519().PubKey().Unwrap().(crypto.PubKeyEd25519), Moniker: "bytomd", Network: "mainnet", NetworkID: 0x888, RemoteAddr: "127.0.0.2:0", ListenAddr: "127.0.0.1:0", Version: "1.1.0-test", ServiceFlag: 10, Other: []string{"abc", "bcd"}} + n, err, err1 := new(int), new(error), new(error) + buf := new(bytes.Buffer) + + wire.WriteBinary(nodeInfo, buf, n, err) + if *err != nil { + t.Fatal(*err) + } + + peerNodeInfo := new(NodeInfo) + wire.ReadBinary(peerNodeInfo, buf, maxNodeInfoSize, new(int), err1) + if *err1 != nil { + t.Fatal(*err1) + } + + if !reflect.DeepEqual(*nodeInfo, *peerNodeInfo) { + t.Fatal("TestNodeInfoWriteRead err", spew.Sdump(nodeInfo), spew.Sdump(peerNodeInfo)) + } +} diff --git a/p2p/peer.go b/p2p/peer.go index cdb609d4..11641b8c 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -4,7 +4,6 @@ import ( "fmt" "net" "reflect" - "strconv" "time" "github.com/btcsuite/go-socks/socks" @@ -110,6 +109,11 @@ func newPeerConn(rawConn net.Conn, outbound bool, ourNodePrivKey crypto.PrivKeyE return nil, errors.Wrap(err, "Error creating peer") } + // Remove deadline + if err := rawConn.SetDeadline(time.Time{}); err != nil { + return nil, err + } + return &peerConn{ config: config, outbound: outbound, @@ -206,15 +210,8 @@ func (p *Peer) Send(chID byte, msg interface{}) bool { // ServiceFlag return the ServiceFlag of this peer func (p *Peer) ServiceFlag() consensus.ServiceFlag { - services := consensus.SFFullNode - if len(p.Other) == 0 { - return services - } - - if serviceFlag, err := strconv.ParseUint(p.Other[0], 10, 64); err == nil { - services = consensus.ServiceFlag(serviceFlag) - } - return services + // ServiceFlag return the ServiceFlag of this peer + return p.NodeInfo.ServiceFlag } // String representation. diff --git a/p2p/switch.go b/p2p/switch.go index c64a69e9..d70fa75a 100644 --- a/p2p/switch.go +++ b/p2p/switch.go @@ -151,6 +151,7 @@ func newSwitch(config *cfg.Config, discv discv, lanDiscv lanDiscv, blacklistDB d sw.AddListener(l) sw.BaseService = *cmn.NewBaseService(nil, "P2P Switch", sw) trust.Init() + log.WithFields(log.Fields{"module": logModule, "nodeInfo": sw.nodeInfo}).Info("init p2p network") return sw, nil } @@ -220,7 +221,8 @@ func (sw *Switch) AddPeer(pc *peerConn, isLAN bool) error { if err := version.Status.CheckUpdate(sw.nodeInfo.Version, peerNodeInfo.Version, peerNodeInfo.RemoteAddr); err != nil { return err } - if err := sw.nodeInfo.CompatibleWith(peerNodeInfo); err != nil { + + if err := sw.nodeInfo.compatibleWith(peerNodeInfo, version.CompatibleWith); err != nil { return err } @@ -336,12 +338,6 @@ func (sw *Switch) NumPeers() (lan, outbound, inbound, dialing int) { return } -// NodeInfo returns the switch's NodeInfo. -// NOTE: Not goroutine safe. -func (sw *Switch) NodeInfo() *NodeInfo { - return sw.nodeInfo -} - //Peers return switch peerset func (sw *Switch) Peers() *PeerSet { return sw.peers @@ -466,7 +462,7 @@ func (sw *Switch) filterConnByPeer(peer *Peer) error { return err } - if sw.nodeInfo.getPubkey().Equals(peer.PubKey().Wrap()) { + if sw.nodeInfo.PubKey.Equals(peer.PubKey().Wrap()) { return ErrConnectSelf } @@ -515,7 +511,7 @@ func (sw *Switch) dialPeers(addresses []*NetAddress) { var wg sync.WaitGroup for _, address := range addresses { - if sw.NodeInfo().ListenAddr == address.String() { + if sw.nodeInfo.ListenAddr == address.String() { continue } if dialling := sw.IsDialing(address); dialling { -- 2.11.0 From 6bf0548429896ef136792b04c6dc21dfe95de016 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com> Date: Fri, 17 May 2019 14:58:18 +0800 Subject: [PATCH 06/16] feature: add cross-chain input (#61) * refactor: rename files * feat: add types.CrossChainInput * feat: add protocol.CrossChainInput * wip: init bc.CrossChainInput * fix: add mainchain output hash * fix: fix letter cases * refactor: fix indent * fix: fix missing value in CrossChainInput * fix: fix NewCrossChainInput() * wip: upgrade MapTx() * refactor: use issue's type indicator for cross-chain input * revert * wip: loop Inputs in mapTx() * wip: add crossIn.SetDestination() in mapTx() * feat: draft mapTx() * refactor: remove ruleAA * feat: add checkValidSrc * wip: init crossIn in checkValid() * wip: add vm.Verify for *bc.CrossChainInput * feat: skip gas for CrossChainInput * refactor: clean up * fix: fix protobuf * fix: fix validate tx * update (t *TxInput) AssetAmount() * add (t *TxInput) Amount() * update * clean * wip: types/txinputs.go * feat: draft types.TxInput * fix: fix test * clean * fix outputID * init assetDefinition * add read/write AssetDefinition * fix the merge issue --- protocol/bc/bc.pb.go | 169 ++++++++++++++------- protocol/bc/bc.proto | 9 ++ protocol/bc/crosschain_input.go | 30 ++++ protocol/bc/types/crosschain_input.go | 40 +++++ ...crosschain_txoutput.go => crosschain_output.go} | 0 ...intrachain_txoutput.go => intrachain_output.go} | 0 protocol/bc/types/map.go | 30 +++- protocol/bc/types/spend.go | 2 +- protocol/bc/types/txinput.go | 73 ++++++++- protocol/validation/tx.go | 23 ++- 10 files changed, 312 insertions(+), 64 deletions(-) create mode 100644 protocol/bc/crosschain_input.go create mode 100644 protocol/bc/types/crosschain_input.go rename protocol/bc/types/{crosschain_txoutput.go => crosschain_output.go} (100%) rename protocol/bc/types/{intrachain_txoutput.go => intrachain_output.go} (100%) diff --git a/protocol/bc/bc.pb.go b/protocol/bc/bc.pb.go index 619de902..6b0a50ac 100644 --- a/protocol/bc/bc.pb.go +++ b/protocol/bc/bc.pb.go @@ -25,6 +25,7 @@ It has these top-level messages: VoteOutput Retirement Spend + CrossChainInput */ package bc @@ -624,6 +625,62 @@ func (m *Spend) GetOrdinal() uint64 { return 0 } +type CrossChainInput struct { + MainchainOutputId *Hash `protobuf:"bytes,1,opt,name=mainchain_output_id,json=mainchainOutputId" json:"mainchain_output_id,omitempty"` + Value *AssetAmount `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` + WitnessDestination *ValueDestination `protobuf:"bytes,3,opt,name=witness_destination,json=witnessDestination" json:"witness_destination,omitempty"` + ControlProgram *Program `protobuf:"bytes,4,opt,name=control_program,json=controlProgram" json:"control_program,omitempty"` + WitnessArguments [][]byte `protobuf:"bytes,5,rep,name=witness_arguments,json=witnessArguments,proto3" json:"witness_arguments,omitempty"` + Ordinal uint64 `protobuf:"varint,6,opt,name=ordinal" json:"ordinal,omitempty"` +} + +func (m *CrossChainInput) Reset() { *m = CrossChainInput{} } +func (m *CrossChainInput) String() string { return proto.CompactTextString(m) } +func (*CrossChainInput) ProtoMessage() {} +func (*CrossChainInput) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{17} } + +func (m *CrossChainInput) GetMainchainOutputId() *Hash { + if m != nil { + return m.MainchainOutputId + } + return nil +} + +func (m *CrossChainInput) GetValue() *AssetAmount { + if m != nil { + return m.Value + } + return nil +} + +func (m *CrossChainInput) GetWitnessDestination() *ValueDestination { + if m != nil { + return m.WitnessDestination + } + return nil +} + +func (m *CrossChainInput) GetControlProgram() *Program { + if m != nil { + return m.ControlProgram + } + return nil +} + +func (m *CrossChainInput) GetWitnessArguments() [][]byte { + if m != nil { + return m.WitnessArguments + } + return nil +} + +func (m *CrossChainInput) GetOrdinal() uint64 { + if m != nil { + return m.Ordinal + } + return 0 +} + func init() { proto.RegisterType((*Hash)(nil), "bc.Hash") proto.RegisterType((*Program)(nil), "bc.Program") @@ -642,63 +699,67 @@ func init() { proto.RegisterType((*VoteOutput)(nil), "bc.VoteOutput") proto.RegisterType((*Retirement)(nil), "bc.Retirement") proto.RegisterType((*Spend)(nil), "bc.Spend") + proto.RegisterType((*CrossChainInput)(nil), "bc.CrossChainInput") } func init() { proto.RegisterFile("bc.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 835 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0xcf, 0x6f, 0xe4, 0x34, - 0x14, 0xd6, 0x4c, 0xd2, 0x49, 0xfa, 0xa6, 0xdb, 0xe9, 0x78, 0x77, 0x21, 0x5a, 0x81, 0xa8, 0x22, - 0x2d, 0x5d, 0x84, 0x54, 0xf5, 0xc7, 0x22, 0x2e, 0x1c, 0x28, 0x2d, 0xcb, 0xce, 0x61, 0xb5, 0xc8, - 0xad, 0x7a, 0x8d, 0x3c, 0x89, 0xdb, 0xb1, 0xc8, 0xc4, 0xc1, 0x76, 0x42, 0xb7, 0xff, 0x02, 0x67, - 0x0e, 0xfc, 0x45, 0x9c, 0xf8, 0x9b, 0x40, 0x7e, 0x71, 0x3a, 0x99, 0x4e, 0x5b, 0x40, 0x08, 0xb1, - 0xb7, 0x79, 0xcf, 0xef, 0x7d, 0xef, 0xf3, 0x67, 0x7f, 0xce, 0x40, 0x38, 0x4d, 0x77, 0x4b, 0x25, - 0x8d, 0x24, 0xfd, 0x69, 0x1a, 0xbf, 0x02, 0xff, 0x35, 0xd3, 0x33, 0xb2, 0x09, 0xfd, 0x7a, 0x2f, - 0xea, 0x6d, 0xf7, 0x5e, 0x0c, 0x68, 0xbf, 0xde, 0xc3, 0x78, 0x3f, 0xea, 0xbb, 0x78, 0x1f, 0xe3, - 0x83, 0xc8, 0x73, 0xf1, 0x01, 0xc6, 0x87, 0x91, 0xef, 0xe2, 0xc3, 0xf8, 0x2b, 0x08, 0xbe, 0x57, - 0xf2, 0x52, 0xb1, 0x39, 0xf9, 0x18, 0xa0, 0x9e, 0x27, 0x35, 0x57, 0x5a, 0xc8, 0x02, 0x21, 0x7d, - 0xba, 0x5e, 0xcf, 0xcf, 0x9b, 0x04, 0x21, 0xe0, 0xa7, 0x32, 0xe3, 0x88, 0xbd, 0x41, 0xf1, 0x77, - 0x3c, 0x81, 0xe0, 0x48, 0x6b, 0x6e, 0x26, 0x27, 0xff, 0x9a, 0xc8, 0x1b, 0x18, 0x22, 0xd4, 0xd1, - 0x5c, 0x56, 0x85, 0x21, 0x9f, 0x42, 0xc8, 0x6c, 0x98, 0x88, 0x0c, 0x41, 0x87, 0x07, 0xc3, 0xdd, - 0x69, 0xba, 0xeb, 0xa6, 0xd1, 0x00, 0x17, 0x27, 0x19, 0xf9, 0x00, 0x06, 0x0c, 0x3b, 0x70, 0x94, - 0x4f, 0x5d, 0x14, 0xe7, 0x30, 0x3c, 0x67, 0x79, 0xc5, 0x4f, 0x65, 0xa5, 0x52, 0x4e, 0x9e, 0x81, - 0xa7, 0xf8, 0x85, 0x43, 0x0a, 0x2d, 0x92, 0x55, 0x8f, 0xda, 0x24, 0x79, 0x0e, 0x6b, 0xb5, 0x2d, - 0x45, 0x84, 0xe1, 0xc1, 0xe8, 0x66, 0x4e, 0x43, 0x85, 0x36, 0xab, 0xe4, 0x19, 0x84, 0xa5, 0xd4, - 0xc2, 0x58, 0x71, 0x3c, 0x9c, 0x75, 0x13, 0xc7, 0x3f, 0xc2, 0x16, 0x4e, 0x3b, 0xe1, 0xda, 0x88, - 0x82, 0xd9, 0xdc, 0x7f, 0x3d, 0xf2, 0x8f, 0x3e, 0x0c, 0xbf, 0xc9, 0x65, 0xfa, 0xc3, 0x6b, 0xce, - 0x32, 0xae, 0x48, 0x04, 0xc1, 0xf2, 0xd1, 0xb5, 0xa1, 0x95, 0x68, 0xc6, 0xc5, 0xe5, 0xec, 0x46, - 0xa2, 0x26, 0x22, 0x2f, 0x61, 0x5c, 0x2a, 0x5e, 0x0b, 0x59, 0xe9, 0x64, 0x6a, 0x91, 0xac, 0xd6, - 0xde, 0x2d, 0xba, 0xa3, 0xb6, 0x04, 0x67, 0x4d, 0x32, 0xf2, 0x11, 0xac, 0x1b, 0x31, 0xe7, 0xda, - 0xb0, 0x79, 0x89, 0xc7, 0xe7, 0xd3, 0x45, 0x82, 0x7c, 0x01, 0x63, 0xa3, 0x58, 0xa1, 0x59, 0x6a, - 0x49, 0xea, 0x44, 0x49, 0x69, 0xa2, 0xb5, 0x5b, 0x98, 0x5b, 0xdd, 0x12, 0x2a, 0xa5, 0x21, 0x5f, - 0xc3, 0x87, 0x9d, 0x5c, 0xa2, 0x0d, 0x33, 0x95, 0x4e, 0x66, 0x4c, 0xcf, 0xa2, 0xc1, 0xad, 0xe6, - 0xa7, 0x9d, 0xc2, 0x53, 0xac, 0x43, 0x1f, 0x9c, 0x00, 0x59, 0x45, 0x88, 0x02, 0x6c, 0x7e, 0x6a, - 0x9b, 0xcf, 0x6e, 0xb7, 0xd1, 0xf1, 0x0a, 0x12, 0xf9, 0x1c, 0xc6, 0x3f, 0x09, 0x53, 0x70, 0xad, - 0x13, 0xa6, 0x2e, 0xab, 0x39, 0x2f, 0x8c, 0x8e, 0xc2, 0x6d, 0xef, 0xc5, 0x06, 0xdd, 0x72, 0x0b, - 0x47, 0x6d, 0x3e, 0xfe, 0xa5, 0x07, 0xe1, 0xd9, 0xd5, 0x5f, 0xca, 0xbf, 0x03, 0x23, 0xcd, 0x95, - 0x60, 0xb9, 0xb8, 0xe6, 0x59, 0xa2, 0xc5, 0x35, 0x77, 0xe7, 0xb0, 0xb9, 0x48, 0x9f, 0x8a, 0x6b, - 0x6e, 0xfd, 0x67, 0x85, 0x4c, 0x14, 0x2b, 0x2e, 0xb9, 0x3b, 0x6f, 0x94, 0x96, 0xda, 0x04, 0xd9, - 0x01, 0x50, 0x5c, 0x57, 0xb9, 0xb5, 0x84, 0x8e, 0xfc, 0x6d, 0x6f, 0x49, 0x96, 0xf5, 0x66, 0x6d, - 0x92, 0xe9, 0x78, 0x1f, 0x36, 0xcf, 0xae, 0xce, 0xb9, 0x12, 0x17, 0xef, 0x28, 0x26, 0xc9, 0x27, - 0x30, 0x74, 0x92, 0x5e, 0x30, 0x91, 0x23, 0xc1, 0x90, 0x42, 0x93, 0x7a, 0xc5, 0x44, 0x1e, 0x5f, - 0xc0, 0x78, 0x45, 0x9f, 0x07, 0xb6, 0xf4, 0x25, 0x3c, 0xaa, 0x11, 0xbf, 0xd5, 0xb9, 0x8f, 0x6c, - 0x08, 0xea, 0xbc, 0x34, 0x9a, 0x6e, 0x34, 0x85, 0x0d, 0x64, 0xfc, 0x7b, 0x0f, 0xbc, 0x37, 0xd5, - 0x15, 0xf9, 0x0c, 0x02, 0x8d, 0xc6, 0xd4, 0x51, 0x0f, 0x5b, 0xd1, 0x01, 0x1d, 0xc3, 0xd2, 0x76, - 0x9d, 0x3c, 0x87, 0xa0, 0x6c, 0x1e, 0x28, 0x67, 0x16, 0x7c, 0x07, 0xdc, 0x9b, 0x45, 0xdb, 0x35, - 0xf2, 0x1d, 0x3c, 0x69, 0x4f, 0x2e, 0x5b, 0x98, 0x50, 0x47, 0x1e, 0xc2, 0x3f, 0xb9, 0x81, 0xef, - 0x38, 0x94, 0x3e, 0x76, 0x1d, 0x9d, 0xdc, 0x3d, 0x57, 0xc0, 0xbf, 0xe7, 0x0a, 0x48, 0x08, 0x8f, - 0xa5, 0x28, 0xa6, 0x4c, 0x73, 0xf2, 0x2d, 0x3c, 0xbe, 0x83, 0x81, 0xf3, 0xff, 0xdd, 0x04, 0xc8, - 0x2a, 0x01, 0xeb, 0x2f, 0xa6, 0xa6, 0xc2, 0x28, 0xa6, 0xde, 0xb9, 0xb7, 0x76, 0x91, 0x88, 0x7f, - 0xee, 0xc1, 0xd6, 0xa4, 0x30, 0x8a, 0x1d, 0xcf, 0x98, 0x28, 0xde, 0x56, 0xa6, 0xac, 0x0c, 0xd9, - 0x81, 0x41, 0xa3, 0x96, 0x1b, 0xb6, 0x22, 0xa6, 0x5b, 0x26, 0x2f, 0x61, 0x94, 0xca, 0xc2, 0x28, - 0x99, 0x27, 0x0f, 0x68, 0xba, 0xe9, 0x6a, 0xda, 0xef, 0x42, 0x04, 0x81, 0x54, 0x99, 0x28, 0x58, - 0xee, 0x2e, 0x65, 0x1b, 0x22, 0x9b, 0x63, 0x25, 0xb5, 0x7e, 0x2f, 0xd8, 0xfc, 0xda, 0x03, 0x38, - 0x97, 0x86, 0xff, 0xcf, 0x3c, 0xec, 0x87, 0xb2, 0x96, 0x86, 0xe3, 0xe3, 0xb8, 0x41, 0xf1, 0x77, - 0xfc, 0x16, 0x80, 0x72, 0x23, 0x14, 0xb7, 0xf7, 0xe6, 0xef, 0x53, 0xeb, 0x0c, 0xe9, 0x2f, 0x6f, - 0xf6, 0xb7, 0x1e, 0xac, 0x9d, 0x96, 0xbc, 0xc8, 0xc8, 0x1e, 0x8c, 0x74, 0xc9, 0x0b, 0x93, 0x48, - 0xdc, 0xf7, 0xe2, 0x83, 0xb9, 0x78, 0x1c, 0x1e, 0x61, 0x41, 0xa3, 0xcb, 0x24, 0xbb, 0xef, 0xa6, - 0xf6, 0xff, 0xe1, 0x4d, 0xbd, 0xd3, 0x29, 0xde, 0xdd, 0x4e, 0xe9, 0xee, 0xc4, 0x5f, 0xda, 0xc9, - 0x74, 0x80, 0x7f, 0x6a, 0x0e, 0xff, 0x0c, 0x00, 0x00, 0xff, 0xff, 0xc7, 0x32, 0xe6, 0x29, 0xe0, - 0x08, 0x00, 0x00, + // 886 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0x4f, 0x6f, 0xe3, 0x44, + 0x14, 0x57, 0x6c, 0x37, 0x49, 0x5f, 0xba, 0x4d, 0x33, 0xdd, 0x05, 0x6b, 0x05, 0xa2, 0xb2, 0xb4, + 0x74, 0x11, 0x52, 0xd5, 0x3f, 0x8b, 0xe0, 0xc0, 0x81, 0xd2, 0xb2, 0x6c, 0x0e, 0xab, 0x45, 0xd3, + 0xaa, 0x57, 0x6b, 0x62, 0x4f, 0x9b, 0x11, 0x8e, 0x27, 0xcc, 0x8c, 0x4d, 0xb7, 0x5f, 0x81, 0x33, + 0x07, 0xbe, 0x08, 0x5f, 0x81, 0x13, 0x9f, 0x09, 0x34, 0xcf, 0xe3, 0xc4, 0x69, 0xd2, 0x76, 0x57, + 0x08, 0xc1, 0xcd, 0xef, 0xdf, 0xef, 0xbd, 0xf7, 0x9b, 0xf7, 0x66, 0x0c, 0xdd, 0x51, 0xb2, 0x37, + 0x55, 0xd2, 0x48, 0xe2, 0x8d, 0x92, 0xe8, 0x25, 0x04, 0xaf, 0x98, 0x1e, 0x93, 0x4d, 0xf0, 0xca, + 0xfd, 0xb0, 0xb5, 0xd3, 0x7a, 0xde, 0xa6, 0x5e, 0xb9, 0x8f, 0xf2, 0x41, 0xe8, 0x39, 0xf9, 0x00, + 0xe5, 0xc3, 0xd0, 0x77, 0xf2, 0x21, 0xca, 0x47, 0x61, 0xe0, 0xe4, 0xa3, 0xe8, 0x6b, 0xe8, 0xfc, + 0xa0, 0xe4, 0x95, 0x62, 0x13, 0xf2, 0x31, 0x40, 0x39, 0x89, 0x4b, 0xae, 0xb4, 0x90, 0x39, 0x42, + 0x06, 0x74, 0xbd, 0x9c, 0x5c, 0x54, 0x0a, 0x42, 0x20, 0x48, 0x64, 0xca, 0x11, 0x7b, 0x83, 0xe2, + 0x77, 0x34, 0x84, 0xce, 0xb1, 0xd6, 0xdc, 0x0c, 0x4f, 0xff, 0x71, 0x21, 0xaf, 0xa1, 0x87, 0x50, + 0xc7, 0x13, 0x59, 0xe4, 0x86, 0x7c, 0x0a, 0x5d, 0x66, 0xc5, 0x58, 0xa4, 0x08, 0xda, 0x3b, 0xec, + 0xed, 0x8d, 0x92, 0x3d, 0x97, 0x8d, 0x76, 0xd0, 0x38, 0x4c, 0xc9, 0x07, 0xd0, 0x66, 0x18, 0x81, + 0xa9, 0x02, 0xea, 0xa4, 0x28, 0x83, 0xde, 0x05, 0xcb, 0x0a, 0x7e, 0x26, 0x0b, 0x95, 0x70, 0xf2, + 0x14, 0x7c, 0xc5, 0x2f, 0x1d, 0x52, 0xd7, 0x22, 0x59, 0xf6, 0xa8, 0x55, 0x92, 0x67, 0xb0, 0x56, + 0x5a, 0x57, 0x44, 0xe8, 0x1d, 0xf6, 0x67, 0x79, 0xaa, 0x52, 0x68, 0x65, 0x25, 0x4f, 0xa1, 0x3b, + 0x95, 0x5a, 0x18, 0x4b, 0x8e, 0x8f, 0xb9, 0x66, 0x72, 0xf4, 0x13, 0x6c, 0x61, 0xb6, 0x53, 0xae, + 0x8d, 0xc8, 0x99, 0xd5, 0xfd, 0xdb, 0x29, 0xff, 0xf2, 0xa0, 0xf7, 0x6d, 0x26, 0x93, 0x1f, 0x5f, + 0x71, 0x96, 0x72, 0x45, 0x42, 0xe8, 0x2c, 0x1e, 0x5d, 0x2d, 0x5a, 0x8a, 0xc6, 0x5c, 0x5c, 0x8d, + 0x67, 0x14, 0x55, 0x12, 0x79, 0x01, 0x83, 0xa9, 0xe2, 0xa5, 0x90, 0x85, 0x8e, 0x47, 0x16, 0xc9, + 0x72, 0xed, 0xdf, 0x2a, 0xb7, 0x5f, 0xbb, 0x60, 0xae, 0x61, 0x4a, 0x3e, 0x82, 0x75, 0x23, 0x26, + 0x5c, 0x1b, 0x36, 0x99, 0xe2, 0xf1, 0x05, 0x74, 0xae, 0x20, 0x5f, 0xc0, 0xc0, 0x28, 0x96, 0x6b, + 0x96, 0xd8, 0x22, 0x75, 0xac, 0xa4, 0x34, 0xe1, 0xda, 0x2d, 0xcc, 0xad, 0xa6, 0x0b, 0x95, 0xd2, + 0x90, 0x6f, 0xe0, 0xc3, 0x86, 0x2e, 0xd6, 0x86, 0x99, 0x42, 0xc7, 0x63, 0xa6, 0xc7, 0x61, 0xfb, + 0x56, 0xf0, 0x93, 0x86, 0xe3, 0x19, 0xfa, 0xe1, 0x1e, 0x9c, 0x02, 0x59, 0x46, 0x08, 0x3b, 0x18, + 0xfc, 0xc4, 0x06, 0x9f, 0xdf, 0x0e, 0xa3, 0x83, 0x25, 0x24, 0xf2, 0x39, 0x0c, 0x7e, 0x16, 0x26, + 0xe7, 0x5a, 0xc7, 0x4c, 0x5d, 0x15, 0x13, 0x9e, 0x1b, 0x1d, 0x76, 0x77, 0xfc, 0xe7, 0x1b, 0x74, + 0xcb, 0x19, 0x8e, 0x6b, 0x7d, 0xf4, 0x6b, 0x0b, 0xba, 0xe7, 0xd7, 0x0f, 0xd2, 0xbf, 0x0b, 0x7d, + 0xcd, 0x95, 0x60, 0x99, 0xb8, 0xe1, 0x69, 0xac, 0xc5, 0x0d, 0x77, 0xe7, 0xb0, 0x39, 0x57, 0x9f, + 0x89, 0x1b, 0x6e, 0xf7, 0xcf, 0x12, 0x19, 0x2b, 0x96, 0x5f, 0x71, 0x77, 0xde, 0x48, 0x2d, 0xb5, + 0x0a, 0xb2, 0x0b, 0xa0, 0xb8, 0x2e, 0x32, 0xbb, 0x12, 0x3a, 0x0c, 0x76, 0xfc, 0x05, 0x5a, 0xd6, + 0x2b, 0xdb, 0x30, 0xd5, 0xd1, 0x01, 0x6c, 0x9e, 0x5f, 0x5f, 0x70, 0x25, 0x2e, 0xdf, 0x52, 0x54, + 0x92, 0x4f, 0xa0, 0xe7, 0x28, 0xbd, 0x64, 0x22, 0xc3, 0x02, 0xbb, 0x14, 0x2a, 0xd5, 0x4b, 0x26, + 0xb2, 0xe8, 0x12, 0x06, 0x4b, 0xfc, 0xdc, 0xd3, 0xd2, 0x97, 0xf0, 0xa8, 0x44, 0xfc, 0x9a, 0x67, + 0x0f, 0xab, 0x21, 0xc8, 0xf3, 0x42, 0x6a, 0xba, 0x51, 0x39, 0x56, 0x90, 0xd1, 0x9f, 0x2d, 0xf0, + 0x5f, 0x17, 0xd7, 0xe4, 0x33, 0xe8, 0x68, 0x5c, 0x4c, 0x1d, 0xb6, 0x30, 0x14, 0x37, 0xa0, 0xb1, + 0xb0, 0xb4, 0xb6, 0x93, 0x67, 0xd0, 0x99, 0x56, 0x17, 0x94, 0x5b, 0x16, 0xbc, 0x07, 0xdc, 0x9d, + 0x45, 0x6b, 0x1b, 0xf9, 0x1e, 0x1e, 0xd7, 0x27, 0x97, 0xce, 0x97, 0x50, 0x87, 0x3e, 0xc2, 0x3f, + 0x9e, 0xc1, 0x37, 0x36, 0x94, 0x6e, 0xbb, 0x88, 0x86, 0xee, 0x8e, 0x11, 0x08, 0xee, 0x18, 0x01, + 0x09, 0xdd, 0x13, 0x29, 0xf2, 0x11, 0xd3, 0x9c, 0x7c, 0x07, 0xdb, 0x2b, 0x2a, 0x70, 0xfb, 0xbf, + 0xba, 0x00, 0xb2, 0x5c, 0x80, 0xdd, 0x2f, 0xa6, 0x46, 0xc2, 0x28, 0xa6, 0xde, 0xba, 0xbb, 0x76, + 0xae, 0x88, 0x7e, 0x69, 0xc1, 0xd6, 0x30, 0x37, 0x8a, 0x9d, 0x8c, 0x99, 0xc8, 0xdf, 0x14, 0x66, + 0x5a, 0x18, 0xb2, 0x0b, 0xed, 0x8a, 0x2d, 0x97, 0x6c, 0x89, 0x4c, 0x67, 0x26, 0x2f, 0xa0, 0x9f, + 0xc8, 0xdc, 0x28, 0x99, 0xc5, 0xf7, 0x70, 0xba, 0xe9, 0x7c, 0xea, 0x77, 0x21, 0x84, 0x8e, 0x54, + 0xa9, 0xc8, 0x59, 0xe6, 0x86, 0xb2, 0x16, 0xb1, 0x9a, 0x13, 0x25, 0xb5, 0xfe, 0x5f, 0x54, 0xf3, + 0x5b, 0x0b, 0xe0, 0x42, 0x1a, 0xfe, 0x1f, 0xd7, 0x61, 0x1f, 0xca, 0x52, 0x1a, 0x8e, 0x97, 0xe3, + 0x06, 0xc5, 0xef, 0xe8, 0x0d, 0x00, 0xe5, 0x46, 0x28, 0x6e, 0xe7, 0xe6, 0xdd, 0x4b, 0x6b, 0x24, + 0xf1, 0x16, 0x9b, 0xfd, 0xa3, 0x05, 0x6b, 0x67, 0x53, 0x9e, 0xa7, 0x64, 0x1f, 0xfa, 0x7a, 0xca, + 0x73, 0x13, 0x4b, 0xec, 0x7b, 0xfe, 0x60, 0xce, 0x2f, 0x87, 0x47, 0xe8, 0x50, 0xf1, 0x32, 0x4c, + 0xef, 0x9a, 0x54, 0xef, 0x3d, 0x27, 0x75, 0xe5, 0xa6, 0xf8, 0xab, 0x37, 0xa5, 0xd9, 0x49, 0xb0, + 0xd8, 0xc9, 0xef, 0x1e, 0xf4, 0xe7, 0x43, 0x34, 0xcc, 0xed, 0xd9, 0x7d, 0x05, 0xdb, 0x13, 0x26, + 0xf2, 0xc4, 0x6a, 0xee, 0xe9, 0x6b, 0x30, 0x73, 0x9a, 0xf5, 0xf6, 0x8e, 0x2f, 0xeb, 0x1d, 0x14, + 0xf8, 0xef, 0x49, 0xc1, 0x8a, 0xd1, 0x09, 0x1e, 0x1e, 0x9d, 0x95, 0xc4, 0xad, 0x3d, 0x4c, 0x5c, + 0x7b, 0x81, 0xb8, 0x51, 0x1b, 0xff, 0x06, 0x8f, 0xfe, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xd8, 0x41, + 0xe2, 0x4f, 0x19, 0x0a, 0x00, 0x00, } diff --git a/protocol/bc/bc.proto b/protocol/bc/bc.proto index 254285ff..fd25c9e9 100644 --- a/protocol/bc/bc.proto +++ b/protocol/bc/bc.proto @@ -111,4 +111,13 @@ message Spend { ValueDestination witness_destination = 2; repeated bytes witness_arguments = 3; uint64 ordinal = 4; +} + +message CrossChainInput { + Hash mainchain_output_id = 1; + AssetAmount value = 2; + ValueDestination witness_destination = 3; + Program control_program = 4; + repeated bytes witness_arguments = 5; + uint64 ordinal = 6; } \ No newline at end of file diff --git a/protocol/bc/crosschain_input.go b/protocol/bc/crosschain_input.go new file mode 100644 index 00000000..0ce867d8 --- /dev/null +++ b/protocol/bc/crosschain_input.go @@ -0,0 +1,30 @@ +package bc + +import "io" + +// crosschaininput is the result of a transfer of value. The value it contains +// comes from the main chain. It satisfies the Entry interface. + +func (CrossChainInput) typ() string { return "crosschaininput1" } + +func (cci *CrossChainInput) writeForHash(w io.Writer) { + mustWriteForHash(w, cci.MainchainOutputId) +} + +// SetDestination will link the CrossChainInput to the output +func (cci *CrossChainInput) SetDestination(id *Hash, val *AssetAmount, pos uint64) { + cci.WitnessDestination = &ValueDestination{ + Ref: id, + Value: val, + Position: pos, + } +} + +// NewCrossChainInput creates a new CrossChainInput. +func NewCrossChainInput(mainchainOutputID *Hash, value *AssetAmount, ordinal uint64) *CrossChainInput { + return &CrossChainInput{ + MainchainOutputId: mainchainOutputID, + Value: value, + Ordinal: ordinal, + } +} diff --git a/protocol/bc/types/crosschain_input.go b/protocol/bc/types/crosschain_input.go new file mode 100644 index 00000000..a08cfd6c --- /dev/null +++ b/protocol/bc/types/crosschain_input.go @@ -0,0 +1,40 @@ +package types + +import ( + "github.com/vapor/protocol/bc" +) + +// CrossChainInput satisfies the TypedInput interface and represents a cross-chain transaction. +type CrossChainInput struct { + AssetDefinition []byte + SpendCommitmentSuffix []byte // The unconsumed suffix of the spend commitment + Arguments [][]byte // Witness + SpendCommitment +} + +// NewCrossChainInput create a new CrossChainInput struct. +// The source is created/issued by trusted federation and hence there is no need +// to refer to it. +func NewCrossChainInput(arguments [][]byte, sourceID bc.Hash, assetID bc.AssetID, amount, sourcePos uint64, controlProgram, assetDefinition []byte) *TxInput { + sc := SpendCommitment{ + AssetAmount: bc.AssetAmount{ + AssetId: &assetID, + Amount: amount, + }, + SourceID: sourceID, + SourcePosition: sourcePos, + VMVersion: 1, + ControlProgram: controlProgram, + } + return &TxInput{ + AssetVersion: 1, + TypedInput: &CrossChainInput{ + AssetDefinition: assetDefinition, + SpendCommitment: sc, + Arguments: arguments, + }, + } +} + +// InputType is the interface function for return the input type. +func (si *CrossChainInput) InputType() uint8 { return CrossChainInputType } diff --git a/protocol/bc/types/crosschain_txoutput.go b/protocol/bc/types/crosschain_output.go similarity index 100% rename from protocol/bc/types/crosschain_txoutput.go rename to protocol/bc/types/crosschain_output.go diff --git a/protocol/bc/types/intrachain_txoutput.go b/protocol/bc/types/intrachain_output.go similarity index 100% rename from protocol/bc/types/intrachain_txoutput.go rename to protocol/bc/types/intrachain_output.go diff --git a/protocol/bc/types/map.go b/protocol/bc/types/map.go index 348c203d..8ec61676 100644 --- a/protocol/bc/types/map.go +++ b/protocol/bc/types/map.go @@ -24,6 +24,12 @@ func MapTx(oldTx *TxData) *bc.Tx { for id, e := range entries { var ord uint64 switch e := e.(type) { + case *bc.CrossChainInput: + ord = e.Ordinal + if *e.WitnessDestination.Value.AssetId == *consensus.BTMAssetID { + tx.GasInputIDs = append(tx.GasInputIDs, id) + } + case *bc.Spend: ord = e.Ordinal spentOutputIDs[*e.SpentOutputId] = true @@ -61,6 +67,7 @@ func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash var ( spends []*bc.Spend + crossIns []*bc.CrossChainInput coinbase *bc.Coinbase ) @@ -100,7 +107,6 @@ func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash } case *UnvoteInput: - // create entry for prevout prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram} src := &bc.ValueSource{ Ref: &inp.SourceID, @@ -120,6 +126,24 @@ func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash } spends = append(spends, spend) + case *CrossChainInput: + prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram} + src := &bc.ValueSource{ + Ref: &inp.SourceID, + Value: &inp.AssetAmount, + Position: inp.SourcePosition, + } + prevout := bc.NewCrossChainOutput(src, prog, 0) // ordinal doesn't matter + outputID := bc.EntryID(prevout) + crossIn := bc.NewCrossChainInput(&outputID, &inp.AssetAmount, uint64(i)) + crossIn.WitnessArguments = inp.Arguments + crossInID := addEntry(crossIn) + muxSources[i] = &bc.ValueSource{ + Ref: &crossInID, + Value: &inp.AssetAmount, + } + crossIns = append(crossIns, crossIn) + } } @@ -132,6 +156,10 @@ func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash spend.SetDestination(&muxID, spentOutput.Source.Value, spend.Ordinal) } + for _, crossIn := range crossIns { + crossIn.SetDestination(&muxID, crossIn.Value, crossIn.Ordinal) + } + if coinbase != nil { coinbase.SetDestination(&muxID, mux.Sources[0].Value, 0) } diff --git a/protocol/bc/types/spend.go b/protocol/bc/types/spend.go index 8642d35a..15b2b69f 100644 --- a/protocol/bc/types/spend.go +++ b/protocol/bc/types/spend.go @@ -6,7 +6,7 @@ import ( // SpendInput satisfies the TypedInput interface and represents a spend transaction. type SpendInput struct { - SpendCommitmentSuffix []byte // The unconsumed suffix of the output commitment + SpendCommitmentSuffix []byte // The unconsumed suffix of the spend commitment Arguments [][]byte // Witness SpendCommitment } diff --git a/protocol/bc/types/txinput.go b/protocol/bc/types/txinput.go index 2da01345..c9fa0a06 100644 --- a/protocol/bc/types/txinput.go +++ b/protocol/bc/types/txinput.go @@ -11,7 +11,7 @@ import ( // serflag variables for input types. const ( - IssuanceInputType uint8 = iota + CrossChainInputType uint8 = iota SpendInputType CoinbaseInputType UnvoteInputType @@ -40,9 +40,13 @@ func (t *TxInput) AssetAmount() bc.AssetAmount { case *SpendInput: return inp.AssetAmount + case *CrossChainInput: + return inp.AssetAmount + case *UnvoteInput: return inp.AssetAmount } + return bc.AssetAmount{} } @@ -52,8 +56,12 @@ func (t *TxInput) AssetID() bc.AssetID { case *SpendInput: return *inp.AssetId + case *CrossChainInput: + return *inp.AssetAmount.AssetId + case *UnvoteInput: return *inp.AssetId + } return bc.AssetID{} } @@ -64,8 +72,12 @@ func (t *TxInput) Amount() uint64 { case *SpendInput: return inp.Amount + case *CrossChainInput: + return inp.AssetAmount.Amount + case *UnvoteInput: return inp.Amount + } return 0 } @@ -76,8 +88,12 @@ func (t *TxInput) ControlProgram() []byte { case *SpendInput: return inp.ControlProgram + case *CrossChainInput: + return inp.ControlProgram + case *UnvoteInput: return inp.ControlProgram + } return nil @@ -89,6 +105,9 @@ func (t *TxInput) Arguments() [][]byte { case *SpendInput: return inp.Arguments + case *CrossChainInput: + return inp.Arguments + case *UnvoteInput: return inp.Arguments } @@ -101,6 +120,9 @@ func (t *TxInput) SetArguments(args [][]byte) { case *SpendInput: inp.Arguments = args + case *CrossChainInput: + inp.Arguments = args + case *UnvoteInput: inp.Arguments = args } @@ -132,6 +154,7 @@ func (t *TxInput) readFrom(r *blockchain.Reader) (err error) { if _, err = io.ReadFull(r, icType[:]); err != nil { return errors.Wrap(err, "reading input commitment type") } + switch icType[0] { case SpendInputType: si := new(SpendInput) @@ -147,10 +170,18 @@ func (t *TxInput) readFrom(r *blockchain.Reader) (err error) { return err } + case CrossChainInputType: + ci := new(CrossChainInput) + t.TypedInput = ci + if ci.SpendCommitmentSuffix, err = ci.SpendCommitment.readFrom(r, 1); err != nil { + return err + } + case UnvoteInputType: ui := new(UnvoteInput) t.TypedInput = ui if ui.UnvoteCommitmentSuffix, err = ui.SpendCommitment.readFrom(r, 1); err != nil { + return err } @@ -174,6 +205,11 @@ func (t *TxInput) readFrom(r *blockchain.Reader) (err error) { return err } + case *CrossChainInput: + if inp.Arguments, err = blockchain.ReadVarstrList(r); err != nil { + return err + } + case *UnvoteInput: if inp.Arguments, err = blockchain.ReadVarstrList(r); err != nil { return err @@ -185,8 +221,18 @@ func (t *TxInput) readFrom(r *blockchain.Reader) (err error) { } return nil }) + if err != nil { + return err + } + + switch inp := t.TypedInput.(type) { + case *CrossChainInput: + if inp.AssetDefinition, err = blockchain.ReadVarstr31(r); err != nil { + return err + } + } - return err + return nil } func (t *TxInput) writeTo(w io.Writer) error { @@ -198,8 +244,18 @@ func (t *TxInput) writeTo(w io.Writer) error { return errors.Wrap(err, "writing input commitment") } - _, err := blockchain.WriteExtensibleString(w, t.WitnessSuffix, t.writeInputWitness) - return errors.Wrap(err, "writing input witness") + if _, err := blockchain.WriteExtensibleString(w, t.WitnessSuffix, t.writeInputWitness); err != nil { + return errors.Wrap(err, "writing input witness") + } + + switch inp := t.TypedInput.(type) { + case *CrossChainInput: + if _, err := blockchain.WriteVarstr31(w, inp.AssetDefinition); err != nil { + return errors.Wrap(err, "writing AssetDefinition") + } + } + + return nil } func (t *TxInput) writeInputCommitment(w io.Writer) (err error) { @@ -214,6 +270,12 @@ func (t *TxInput) writeInputCommitment(w io.Writer) (err error) { } return inp.SpendCommitment.writeExtensibleString(w, inp.SpendCommitmentSuffix, t.AssetVersion) + case *CrossChainInput: + if _, err = w.Write([]byte{SpendInputType}); err != nil { + return err + } + return inp.SpendCommitment.writeExtensibleString(w, inp.SpendCommitmentSuffix, t.AssetVersion) + case *CoinbaseInput: if _, err = w.Write([]byte{CoinbaseInputType}); err != nil { return err @@ -241,6 +303,9 @@ func (t *TxInput) writeInputWitness(w io.Writer) error { _, err := blockchain.WriteVarstrList(w, inp.Arguments) return err + case *CrossChainInput: + _, err := blockchain.WriteVarstrList(w, inp.Arguments) + return err case *UnvoteInput: if _, err := blockchain.WriteVarstrList(w, inp.Arguments); err != nil { return err diff --git a/protocol/validation/tx.go b/protocol/validation/tx.go index 058b736d..6e0acd24 100644 --- a/protocol/validation/tx.go +++ b/protocol/validation/tx.go @@ -238,6 +238,18 @@ func checkValid(vs *validationState, e bc.Entry) (err error) { return errors.Wrap(err, "checking retirement source") } + case *bc.CrossChainInput: + _, err := vm.Verify(NewTxVMContext(vs, e, e.ControlProgram, e.WitnessArguments), consensus.DefaultGasCredit) + if err != nil { + return errors.Wrap(err, "checking cross-chain input control program") + } + + vs2 := *vs + vs2.destPos = 0 + if err = checkValidDest(&vs2, e.WitnessDestination); err != nil { + return errors.Wrap(err, "checking cross-chain input destination") + } + case *bc.Spend: if e.SpentOutputId == nil { return errors.Wrap(ErrMissingField, "spend without spent output ID") @@ -246,7 +258,6 @@ func checkValid(vs *validationState, e bc.Entry) (err error) { if err != nil { return errors.Wrap(err, "getting spend prevout") } - gasLeft, err := vm.Verify(NewTxVMContext(vs, e, spentOutput.ControlProgram, e.WitnessArguments), vs.gasStatus.GasLeft) if err != nil { return errors.Wrap(err, "checking control program") @@ -254,7 +265,6 @@ func checkValid(vs *validationState, e bc.Entry) (err error) { if err = vs.gasStatus.updateUsage(gasLeft); err != nil { return err } - eq, err := spentOutput.Source.Value.Equal(e.WitnessDestination.Value) if err != nil { return err @@ -269,7 +279,6 @@ func checkValid(vs *validationState, e bc.Entry) (err error) { e.WitnessDestination.Value.AssetId.Bytes(), ) } - vs2 := *vs vs2.destPos = 0 if err = checkValidDest(&vs2, e.WitnessDestination); err != nil { @@ -333,6 +342,12 @@ func checkValidSrc(vstate *validationState, vs *bc.ValueSource) error { } dest = ref.WitnessDestination + case *bc.CrossChainInput: + if vs.Position != 0 { + return errors.Wrapf(ErrPosition, "invalid position %d for cross-chain input source", vs.Position) + } + dest = ref.WitnessDestination + case *bc.Spend: if vs.Position != 0 { return errors.Wrapf(ErrPosition, "invalid position %d for spend source", vs.Position) @@ -346,7 +361,7 @@ func checkValidSrc(vstate *validationState, vs *bc.ValueSource) error { dest = ref.WitnessDestinations[vs.Position] default: - return errors.Wrapf(bc.ErrEntryType, "value source is %T, should be coinbase, issuance, spend, or mux", e) + return errors.Wrapf(bc.ErrEntryType, "value source is %T, should be coinbase, cross-chain input, spend, or mux", e) } if dest.Ref == nil || *dest.Ref != vstate.entryID { -- 2.11.0 From b9b4d0f75f4d5844b88e7d3bc33baae6a1e6ec4d Mon Sep 17 00:00:00 2001 From: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com> Date: Mon, 20 May 2019 09:46:04 +0800 Subject: [PATCH 07/16] test: add read/write test for cross-chain input/output (#70) * fix read/wrire CrossChainInput * add TestSerializationCrossChainTxOutput --- protocol/bc/types/txinput.go | 2 +- protocol/bc/types/txinput_test.go | 98 ++++++++++++++++++++++++++++++-------- protocol/bc/types/txoutput_test.go | 45 ++++++++++++++++- 3 files changed, 122 insertions(+), 23 deletions(-) diff --git a/protocol/bc/types/txinput.go b/protocol/bc/types/txinput.go index c9fa0a06..7b9ba0ea 100644 --- a/protocol/bc/types/txinput.go +++ b/protocol/bc/types/txinput.go @@ -271,7 +271,7 @@ func (t *TxInput) writeInputCommitment(w io.Writer) (err error) { return inp.SpendCommitment.writeExtensibleString(w, inp.SpendCommitmentSuffix, t.AssetVersion) case *CrossChainInput: - if _, err = w.Write([]byte{SpendInputType}); err != nil { + if _, err = w.Write([]byte{CrossChainInputType}); err != nil { return err } return inp.SpendCommitment.writeExtensibleString(w, inp.SpendCommitmentSuffix, t.AssetVersion) diff --git a/protocol/bc/types/txinput_test.go b/protocol/bc/types/txinput_test.go index ec78bbef..6ff94a93 100644 --- a/protocol/bc/types/txinput_test.go +++ b/protocol/bc/types/txinput_test.go @@ -26,17 +26,17 @@ func TestSerializationSpend(t *testing.T) { "52", // spend commitment length "fad5195a0c8e3b590b86a3c0a95e7529565888508aecca96e9aeda633002f409", // source id "fe9791d71b67ee62515e08723c061b5ccb952a80d804417c8aeedf7f633c524a", // assetID - "92c30f", // amount - "03", // source position - "01", // vm version - "0c", // spend program length + "92c30f", // amount + "03", // source position + "01", // vm version + "0c", // spend program length "7370656e6450726f6772616d", // spend program - "17", // witness length - "02", // argument array length - "0a", // first argument length - "617267756d656e747331", // first argument data - "0a", // second argument length - "617267756d656e747332", // second argument data + "17", // witness length + "02", // argument array length + "0a", // first argument length + "617267756d656e747331", // first argument data + "0a", // second argument length + "617267756d656e747332", // second argument data }, "") // Test convert struct to hex @@ -66,6 +66,62 @@ func TestSerializationSpend(t *testing.T) { } } +func TestSerializationCrossIn(t *testing.T) { + arguments := [][]byte{ + []byte("arguments1"), + []byte("arguments2"), + } + crossIn := NewCrossChainInput(arguments, testutil.MustDecodeHash("fad5195a0c8e3b590b86a3c0a95e7529565888508aecca96e9aeda633002f409"), testutil.MustDecodeAsset("fe9791d71b67ee62515e08723c061b5ccb952a80d804417c8aeedf7f633c524a"), 254354, 3, []byte("crossInProgram"), []byte("whatever")) + + wantHex := strings.Join([]string{ + "01", // asset version + "56", // input commitment length + "00", // cross-chain input type flag + "54", // cross-chain input commitment length + "fad5195a0c8e3b590b86a3c0a95e7529565888508aecca96e9aeda633002f409", // source id + "fe9791d71b67ee62515e08723c061b5ccb952a80d804417c8aeedf7f633c524a", // assetID + "92c30f", // amount + "03", // source position + "01", // vm version + "0e", // spend program length + "63726f7373496e50726f6772616d", // spend program + "17", // witness length + "02", // argument array length + "0a", // first argument length + "617267756d656e747331", // first argument data + "0a", // second argument length + "617267756d656e747332", // second argument data + "08", // asset definition length + "7768617465766572", // asset definition data + }, "") + + // Test convert struct to hex + var buffer bytes.Buffer + if err := crossIn.writeTo(&buffer); err != nil { + t.Fatal(err) + } + + gotHex := hex.EncodeToString(buffer.Bytes()) + if gotHex != wantHex { + t.Errorf("serialization bytes = %s want %s", gotHex, wantHex) + } + + // Test convert hex to struct + var gotCrossIn TxInput + decodeHex, err := hex.DecodeString(wantHex) + if err != nil { + t.Fatal(err) + } + + if err := gotCrossIn.readFrom(blockchain.NewReader(decodeHex)); err != nil { + t.Fatal(err) + } + + if !testutil.DeepEqual(*crossIn, gotCrossIn) { + t.Errorf("expected marshaled/unmarshaled txinput to be:\n%sgot:\n%s", spew.Sdump(*crossIn), spew.Sdump(gotCrossIn)) + } +} + func TestSerializationUnvote(t *testing.T) { arguments := [][]byte{ []byte("arguments1"), @@ -81,18 +137,18 @@ func TestSerializationUnvote(t *testing.T) { "52", // unvote commitment length "fad5195a0c8e3b590b86a3c0a95e7529565888508aecca96e9aeda633002f409", // source id "fe9791d71b67ee62515e08723c061b5ccb952a80d804417c8aeedf7f633c524a", // assetID - "92c30f", // amount - "03", // source position - "01", // vm version - "0c", // unvote program length + "92c30f", // amount + "03", // source position + "01", // vm version + "0c", // unvote program length "7370656e6450726f6772616d", // unvote program - "9901", // witness length - "02", // argument array length - "0a", // first argument length - "617267756d656e747331", // first argument data - "0a", // second argument length - "617267756d656e747332", // second argument data - "8001", //xpub length + "9901", // witness length + "02", // argument array length + "0a", // first argument length + "617267756d656e747331", // first argument data + "0a", // second argument length + "617267756d656e747332", // second argument data + "8001", //xpub length "6166353934303036613430383337643966303238646161626236643538396466306239313338646165666164353638336535323333633236343632373932313732393461386435333265363038363362636631393636323561333566623863656566666133633039363130656239326463666236353561393437663133323639", //voter xpub }, "") diff --git a/protocol/bc/types/txoutput_test.go b/protocol/bc/types/txoutput_test.go index a6c4eba0..9dc854a8 100644 --- a/protocol/bc/types/txoutput_test.go +++ b/protocol/bc/types/txoutput_test.go @@ -13,7 +13,7 @@ import ( "github.com/vapor/testutil" ) -func TestSerializationTxOutput(t *testing.T) { +func TestSerializationIntraChainTxOutput(t *testing.T) { assetID := testutil.MustDecodeAsset("81756fdab39a17163b0ce582ee4ee256fb4d1e156c692b997d608a42ecb38d47") txOutput := NewIntraChainOutput(assetID, 254354, []byte("TestSerializationTxOutput")) wantHex := strings.Join([]string{ @@ -56,6 +56,49 @@ func TestSerializationTxOutput(t *testing.T) { } } +func TestSerializationCrossChainTxOutput(t *testing.T) { + assetID := testutil.MustDecodeAsset("81756fdab39a17163b0ce582ee4ee256fb4d1e156c692b997d608a42ecb38d47") + txOutput := NewCrossChainOutput(assetID, 254354, []byte("TestSerializationTxOutput")) + wantHex := strings.Join([]string{ + "01", // asset version + "40", // serialization length + "01", // outType + "3e", // output commitment length + "81756fdab39a17163b0ce582ee4ee256fb4d1e156c692b997d608a42ecb38d47", // assetID + "92c30f", // amount + "01", // version + "19", // control program length + "5465737453657269616c697a6174696f6e54784f7574707574", // control program + "00", // witness length + }, "") + + // Test convert struct to hex + var buffer bytes.Buffer + if err := txOutput.writeTo(&buffer); err != nil { + t.Fatal(err) + } + + gotHex := hex.EncodeToString(buffer.Bytes()) + if gotHex != wantHex { + t.Errorf("serialization bytes = %s want %s", gotHex, wantHex) + } + + // Test convert hex to struct + var gotTxOutput TxOutput + decodeHex, err := hex.DecodeString(wantHex) + if err != nil { + t.Fatal(err) + } + + if err := gotTxOutput.readFrom(blockchain.NewReader(decodeHex)); err != nil { + t.Fatal(err) + } + + if !testutil.DeepEqual(*txOutput, gotTxOutput) { + t.Errorf("expected marshaled/unmarshaled txoutput to be:\n%sgot:\n%s", spew.Sdump(*txOutput), spew.Sdump(gotTxOutput)) + } +} + func TestSerializationVoteTxOutput(t *testing.T) { assetID := testutil.MustDecodeAsset("81756fdab39a17163b0ce582ee4ee256fb4d1e156c692b997d608a42ecb38d47") voteTxOutput := NewVoteOutput(assetID, 1000, []byte("TestSerializationTxOutput"), []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269")) -- 2.11.0 From c2e4075a43a3866fe8ab827a96f2c7e86252f1c0 Mon Sep 17 00:00:00 2001 From: Paladz Date: Mon, 20 May 2019 11:10:59 +0800 Subject: [PATCH 08/16] ts to ms (#71) --- config/genesis.go | 6 +-- consensus/general.go | 6 +-- mining/mining.go | 2 +- netsync/message_test.go | 12 +++--- protocol/bc/types/block_header.go | 4 +- protocol/bc/types/block_header_test.go | 78 +++++++++++++++++----------------- protocol/validation/block.go | 2 +- protocol/validation/block_test.go | 32 +++++++------- protocol/validation/tx_test.go | 2 +- test/block_test.go | 4 +- test/utxo_view/utxo_view_test_util.go | 30 ++++++------- wallet/unconfirmed.go | 2 +- 12 files changed, 90 insertions(+), 90 deletions(-) diff --git a/config/genesis.go b/config/genesis.go index 021f14d1..5f643a02 100644 --- a/config/genesis.go +++ b/config/genesis.go @@ -48,7 +48,7 @@ func mainNetGenesisBlock() *types.Block { BlockHeader: types.BlockHeader{ Version: 1, Height: 0, - Timestamp: 1524549600, + Timestamp: 1524549600000, BlockCommitment: types.BlockCommitment{ TransactionsMerkleRoot: merkleRoot, TransactionStatusHash: txStatusHash, @@ -79,7 +79,7 @@ func testNetGenesisBlock() *types.Block { BlockHeader: types.BlockHeader{ Version: 1, Height: 0, - Timestamp: 1528945000, + Timestamp: 1528945000000, BlockCommitment: types.BlockCommitment{ TransactionsMerkleRoot: merkleRoot, TransactionStatusHash: txStatusHash, @@ -110,7 +110,7 @@ func soloNetGenesisBlock() *types.Block { BlockHeader: types.BlockHeader{ Version: 1, Height: 0, - Timestamp: 1528945000, + Timestamp: 1528945000000, BlockCommitment: types.BlockCommitment{ TransactionsMerkleRoot: merkleRoot, TransactionStatusHash: txStatusHash, diff --git a/consensus/general.go b/consensus/general.go index 6b678701..868fc5b0 100644 --- a/consensus/general.go +++ b/consensus/general.go @@ -27,9 +27,9 @@ const ( TargetSecondsPerBlock = uint64(150) SeedPerRetarget = uint64(256) - // MaxTimeOffsetSeconds is the maximum number of seconds a block time is allowed to be ahead of the current time - MaxTimeOffsetSeconds = uint64(60 * 60) - MedianTimeBlocks = 11 + // MaxTimeOffsetMs is the maximum number of seconds a block time is allowed to be ahead of the current time + MaxTimeOffsetMs = uint64(60 * 60 * 1000) + MedianTimeBlocks = 11 PayToWitnessPubKeyHashDataSize = 20 PayToWitnessScriptHashDataSize = 32 diff --git a/mining/mining.go b/mining/mining.go index 9f9dece2..82149b16 100644 --- a/mining/mining.go +++ b/mining/mining.go @@ -89,7 +89,7 @@ func NewBlockTemplate(c *protocol.Chain, txPool *protocol.TxPool, accountManager Version: 1, Height: nextBlockHeight, PreviousBlockHash: preBlockHash, - Timestamp: uint64(time.Now().Unix()), + Timestamp: uint64(time.Now().UnixNano() / int64(time.Millisecond)), BlockCommitment: types.BlockCommitment{}, }, } diff --git a/netsync/message_test.go b/netsync/message_test.go index 8743df70..5c40a680 100644 --- a/netsync/message_test.go +++ b/netsync/message_test.go @@ -14,7 +14,7 @@ var testBlock = &types.Block{ BlockHeader: types.BlockHeader{ Version: 1, Height: 0, - Timestamp: 1528945000, + Timestamp: 1528945000000, BlockCommitment: types.BlockCommitment{ TransactionsMerkleRoot: bc.Hash{V0: uint64(0x11)}, TransactionStatusHash: bc.Hash{V0: uint64(0x55)}, @@ -48,7 +48,7 @@ var testHeaders = []*types.BlockHeader{ { Version: 1, Height: 0, - Timestamp: 1528945000, + Timestamp: 1528945000000, BlockCommitment: types.BlockCommitment{ TransactionsMerkleRoot: bc.Hash{V0: uint64(0x11)}, TransactionStatusHash: bc.Hash{V0: uint64(0x55)}, @@ -57,7 +57,7 @@ var testHeaders = []*types.BlockHeader{ { Version: 1, Height: 1, - Timestamp: 1528945000, + Timestamp: 1528945000000, BlockCommitment: types.BlockCommitment{ TransactionsMerkleRoot: bc.Hash{V0: uint64(0x11)}, TransactionStatusHash: bc.Hash{V0: uint64(0x55)}, @@ -66,7 +66,7 @@ var testHeaders = []*types.BlockHeader{ { Version: 1, Height: 3, - Timestamp: 1528945000, + Timestamp: 1528945000000, BlockCommitment: types.BlockCommitment{ TransactionsMerkleRoot: bc.Hash{V0: uint64(0x11)}, TransactionStatusHash: bc.Hash{V0: uint64(0x55)}, @@ -127,7 +127,7 @@ var testBlocks = []*types.Block{ BlockHeader: types.BlockHeader{ Version: 1, Height: 0, - Timestamp: 1528945000, + Timestamp: 1528945000000, BlockCommitment: types.BlockCommitment{ TransactionsMerkleRoot: bc.Hash{V0: uint64(0x11)}, TransactionStatusHash: bc.Hash{V0: uint64(0x55)}, @@ -138,7 +138,7 @@ var testBlocks = []*types.Block{ BlockHeader: types.BlockHeader{ Version: 1, Height: 0, - Timestamp: 1528945000, + Timestamp: 1528945000000, BlockCommitment: types.BlockCommitment{ TransactionsMerkleRoot: bc.Hash{V0: uint64(0x11)}, TransactionStatusHash: bc.Hash{V0: uint64(0x55)}, diff --git a/protocol/bc/types/block_header.go b/protocol/bc/types/block_header.go index 7df4c379..88bdddb7 100644 --- a/protocol/bc/types/block_header.go +++ b/protocol/bc/types/block_header.go @@ -17,14 +17,14 @@ type BlockHeader struct { Version uint64 // The version of the block. Height uint64 // The height of the block. PreviousBlockHash bc.Hash // The hash of the previous block. - Timestamp uint64 // The time of the block in seconds. + Timestamp uint64 // The time of the block in milliseconds. BlockCommitment BlockWitness } // Time returns the time represented by the Timestamp in block header. func (bh *BlockHeader) Time() time.Time { - return time.Unix(int64(bh.Timestamp), 0).UTC() + return time.Unix(0, int64(bh.Timestamp)*int64(time.Millisecond)).UTC() } // Hash returns complete hash of the block header. diff --git a/protocol/bc/types/block_header_test.go b/protocol/bc/types/block_header_test.go index 4a9237a9..2ea6e01e 100644 --- a/protocol/bc/types/block_header_test.go +++ b/protocol/bc/types/block_header_test.go @@ -19,7 +19,7 @@ func TestBlockHeader(t *testing.T) { Version: 1, Height: 432234, PreviousBlockHash: testutil.MustDecodeHash("c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0"), - Timestamp: 1522908275, + Timestamp: 1522908275000, BlockCommitment: BlockCommitment{ TransactionStatusHash: testutil.MustDecodeHash("b94301ea4e316bee00109f68d25beaca90aeff08e9bf439a37d91d7a3b5a1470"), TransactionsMerkleRoot: testutil.MustDecodeHash("ad9ac003d08ff305181a345d64fe0b02311cc1a6ec04ab73f3318d90139bfe03"), @@ -32,8 +32,8 @@ func TestBlockHeader(t *testing.T) { "01", // version "eab01a", // block height "c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0", // prev block hash - "f3f896d605", // timestamp - "40", // commitment extensible field length + "b8c2a0a3a92c", // timestamp + "40", // commitment extensible field length "ad9ac003d08ff305181a345d64fe0b02311cc1a6ec04ab73f3318d90139bfe03", // transactions merkle root "b94301ea4e316bee00109f68d25beaca90aeff08e9bf439a37d91d7a3b5a1470", // tx status hash "040102beef", //BlockWitness @@ -70,7 +70,7 @@ func TestMarshalBlockHeader(t *testing.T) { Version: 1, Height: 10000, PreviousBlockHash: testutil.MustDecodeHash("c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0"), - Timestamp: 1528945000, + Timestamp: 1528945000000, BlockCommitment: BlockCommitment{ TransactionsMerkleRoot: testutil.MustDecodeHash("ad9ac003d08ff305181a345d64fe0b02311cc1a6ec04ab73f3318d90139bfe03"), TransactionStatusHash: testutil.MustDecodeHash("b94301ea4e316bee00109f68d25beaca90aeff08e9bf439a37d91d7a3b5a1470"), @@ -82,8 +82,8 @@ func TestMarshalBlockHeader(t *testing.T) { "01", // version "904e", // block height "c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0", // prev block hash - "e8b287d905", // timestamp - "40", // commitment extensible field length + "c0fce4e1bf2c", // timestamp + "40", // commitment extensible field length "ad9ac003d08ff305181a345d64fe0b02311cc1a6ec04ab73f3318d90139bfe03", // transactions merkle root "b94301ea4e316bee00109f68d25beaca90aeff08e9bf439a37d91d7a3b5a1470", // tx status hash "040102beef", //BlockWitness @@ -94,7 +94,7 @@ func TestMarshalBlockHeader(t *testing.T) { Version: 1, Height: 9223372036854775808, // Height > MaxInt64(9223372036854775807) PreviousBlockHash: testutil.MustDecodeHash("c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0"), - Timestamp: 1528945000, + Timestamp: 1528945000000, BlockCommitment: BlockCommitment{ TransactionsMerkleRoot: testutil.MustDecodeHash("ad9ac003d08ff305181a345d64fe0b02311cc1a6ec04ab73f3318d90139bfe03"), TransactionStatusHash: testutil.MustDecodeHash("b94301ea4e316bee00109f68d25beaca90aeff08e9bf439a37d91d7a3b5a1470"), @@ -122,7 +122,7 @@ func TestMarshalBlockHeader(t *testing.T) { Version: 1, Height: 9223372036854775807, // MaxInt64(9223372036854775807) PreviousBlockHash: testutil.MustDecodeHash("c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0"), - Timestamp: 1528945000, + Timestamp: 1528945000000, BlockWitness: BlockWitness{Witness: [][]byte{[]byte{0xbe, 0xef}}}, }, wantHex: strings.Join([]string{ @@ -130,8 +130,8 @@ func TestMarshalBlockHeader(t *testing.T) { "01", // version "ffffffffffffffff7f", // block height "c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0", // prev block hash - "e8b287d905", // timestamp - "40", // commitment extensible field length + "c0fce4e1bf2c", // timestamp + "40", // commitment extensible field length "0000000000000000000000000000000000000000000000000000000000000000", // transactions merkle root "0000000000000000000000000000000000000000000000000000000000000000", // tx status hash "040102beef", //BlockWitness @@ -142,7 +142,7 @@ func TestMarshalBlockHeader(t *testing.T) { Version: 1, Height: 9223372036854775807, // MaxInt64(9223372036854775807) PreviousBlockHash: testutil.MustDecodeHash("c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0"), - Timestamp: 1528945000, + Timestamp: 1528945000000, BlockWitness: BlockWitness{Witness: [][]byte{[]byte{0xbe, 0xef}, []byte{0xab, 0xcd}, []byte{0xcd, 0x68}}}, }, wantHex: strings.Join([]string{ @@ -150,8 +150,8 @@ func TestMarshalBlockHeader(t *testing.T) { "01", // version "ffffffffffffffff7f", // block height "c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0", // prev block hash - "e8b287d905", // timestamp - "40", // commitment extensible field length + "c0fce4e1bf2c", // timestamp + "40", // commitment extensible field length "0000000000000000000000000000000000000000000000000000000000000000", // transactions merkle root "0000000000000000000000000000000000000000000000000000000000000000", // tx status hash "0a0302beef02abcd02cd68", //BlockWitness @@ -162,7 +162,7 @@ func TestMarshalBlockHeader(t *testing.T) { Version: 1, Height: 9223372036854775807, // MaxInt64(9223372036854775807) PreviousBlockHash: testutil.MustDecodeHash("c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0"), - Timestamp: 1528945000, + Timestamp: 1528945000000, BlockWitness: BlockWitness{Witness: [][]byte{[]byte{0xbe, 0xef}, nil, []byte{0xcd, 0x68}}}, }, wantHex: strings.Join([]string{ @@ -170,8 +170,8 @@ func TestMarshalBlockHeader(t *testing.T) { "01", // version "ffffffffffffffff7f", // block height "c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0", // prev block hash - "e8b287d905", // timestamp - "40", // commitment extensible field length + "c0fce4e1bf2c", // timestamp + "40", // commitment extensible field length "0000000000000000000000000000000000000000000000000000000000000000", // transactions merkle root "0000000000000000000000000000000000000000000000000000000000000000", // tx status hash "080302beef0002cd68", //BlockWitness @@ -182,7 +182,7 @@ func TestMarshalBlockHeader(t *testing.T) { Version: 1, Height: 9223372036854775807, // MaxInt64(9223372036854775807) PreviousBlockHash: testutil.MustDecodeHash("c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0"), - Timestamp: 1528945000, + Timestamp: 1528945000000, BlockWitness: BlockWitness{Witness: [][]byte{[]byte{0xbe, 0xef}, []byte{}, []byte{0xcd, 0x68}}}, }, wantHex: strings.Join([]string{ @@ -190,8 +190,8 @@ func TestMarshalBlockHeader(t *testing.T) { "01", // version "ffffffffffffffff7f", // block height "c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0", // prev block hash - "e8b287d905", // timestamp - "40", // commitment extensible field length + "c0fce4e1bf2c", // timestamp + "40", // commitment extensible field length "0000000000000000000000000000000000000000000000000000000000000000", // transactions merkle root "0000000000000000000000000000000000000000000000000000000000000000", // tx status hash "080302beef0002cd68", //BlockWitness @@ -202,7 +202,7 @@ func TestMarshalBlockHeader(t *testing.T) { Version: 1, Height: 9223372036854775807, // MaxInt64(9223372036854775807) PreviousBlockHash: testutil.MustDecodeHash("c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0"), - Timestamp: 1528945000, + Timestamp: 1528945000000, BlockWitness: BlockWitness{Witness: [][]byte{}}, }, wantHex: strings.Join([]string{ @@ -210,8 +210,8 @@ func TestMarshalBlockHeader(t *testing.T) { "01", // version "ffffffffffffffff7f", // block height "c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0", // prev block hash - "e8b287d905", // timestamp - "40", // commitment extensible field length + "c0fce4e1bf2c", // timestamp + "40", // commitment extensible field length "0000000000000000000000000000000000000000000000000000000000000000", // transactions merkle root "0000000000000000000000000000000000000000000000000000000000000000", // tx status hash "0100", //BlockWitness @@ -254,8 +254,8 @@ func TestUnmarshalBlockHeader(t *testing.T) { "01", // version "904e", // block height "c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0", // prev block hash - "e8b287d905", // timestamp - "40", // commitment extensible field length + "c0fce4e1bf2c", // timestamp + "40", // commitment extensible field length "ad9ac003d08ff305181a345d64fe0b02311cc1a6ec04ab73f3318d90139bfe03", // transactions merkle root "b94301ea4e316bee00109f68d25beaca90aeff08e9bf439a37d91d7a3b5a1470", // tx status hash "040102beef", //BlockWitness @@ -264,7 +264,7 @@ func TestUnmarshalBlockHeader(t *testing.T) { Version: 1, Height: 10000, PreviousBlockHash: testutil.MustDecodeHash("c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0"), - Timestamp: 1528945000, + Timestamp: 1528945000000, BlockCommitment: BlockCommitment{ TransactionsMerkleRoot: testutil.MustDecodeHash("ad9ac003d08ff305181a345d64fe0b02311cc1a6ec04ab73f3318d90139bfe03"), TransactionStatusHash: testutil.MustDecodeHash("b94301ea4e316bee00109f68d25beaca90aeff08e9bf439a37d91d7a3b5a1470"), @@ -278,8 +278,8 @@ func TestUnmarshalBlockHeader(t *testing.T) { "01", // version "904e", // block height "c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0", // prev block hash - "e8b287d905", // timestamp - "40", // commitment extensible field length + "c0fce4e1bf2c", // timestamp + "40", // commitment extensible field length "ad9ac003d08ff305181a345d64fe0b02311cc1a6ec04ab73f3318d90139bfe03", // transactions merkle root "b94301ea4e316bee00109f68d25beaca90aeff08e9bf439a37d91d7a3b5a1470", // tx status hash "040102beef", //BlockWitness @@ -288,7 +288,7 @@ func TestUnmarshalBlockHeader(t *testing.T) { Version: 1, Height: 10000, PreviousBlockHash: testutil.MustDecodeHash("c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0"), - Timestamp: 1528945000, + Timestamp: 1528945000000, BlockCommitment: BlockCommitment{ TransactionsMerkleRoot: testutil.MustDecodeHash("ad9ac003d08ff305181a345d64fe0b02311cc1a6ec04ab73f3318d90139bfe03"), TransactionStatusHash: testutil.MustDecodeHash("b94301ea4e316bee00109f68d25beaca90aeff08e9bf439a37d91d7a3b5a1470"), @@ -302,8 +302,8 @@ func TestUnmarshalBlockHeader(t *testing.T) { "01", // version "904e", // block height "c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0", // prev block hash - "e8b287d905", // timestamp - "40", // commitment extensible field length + "c0fce4e1bf2c", // timestamp + "40", // commitment extensible field length "ad9ac003d08ff305181a345d64fe0b02311cc1a6ec04ab73f3318d90139bfe03", // transactions merkle root "b94301ea4e316bee00109f68d25beaca90aeff08e9bf439a37d91d7a3b5a1470", // tx status hash }, ""), @@ -315,8 +315,8 @@ func TestUnmarshalBlockHeader(t *testing.T) { "01", // version "908", // block height (error with odd length) "c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0", // prev block hash - "e8b287d905", // timestamp - "40", // commitment extensible field length + "c0fce4e1bf2c", // timestamp + "40", // commitment extensible field length "ad9ac003d08ff305181a345d64fe0b02311cc1a6ec04ab73f3318d90139bfe03", // transactions merkle root "b94301ea4e316bee00109f68d25beaca90aeff08e9bf439a37d91d7a3b5a1470", // tx status hash }, ""), @@ -328,8 +328,8 @@ func TestUnmarshalBlockHeader(t *testing.T) { "01", // version "ffffffffffffffffff", // block height "c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0", // prev block hash - "e8b287d905", // timestamp - "40", // commitment extensible field length + "c0fce4e1bf2c", // timestamp + "40", // commitment extensible field length "ad9ac003d08ff305181a345d64fe0b02311cc1a6ec04ab73f3318d90139bfe03", // transactions merkle root "b94301ea4e316bee00109f68d25beaca90aeff08e9bf439a37d91d7a3b5a1470", // tx status hash "040102beef", //BlockWitness @@ -342,8 +342,8 @@ func TestUnmarshalBlockHeader(t *testing.T) { "01", // version "ffffffffffffffff7f", // block height "c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0", // prev block hash - "e8b287d905", // timestamp - "40", // commitment extensible field length + "c0fce4e1bf2c", // timestamp + "40", // commitment extensible field length "ad9ac003d08ff305181a345d64fe0b02311cc1a6ec04ab73f3318d90139bfe03", // transactions merkle root "b94301ea4e316bee00109f68d25beaca90aeff08e9bf439a37d91d7a3b5a14", // tx status hash }, ""), @@ -355,8 +355,8 @@ func TestUnmarshalBlockHeader(t *testing.T) { "01", // version "ffffffffffffffff7f", // block height "c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0", // prev block hash - "e8b287d905", // timestamp - "40", // commitment extensible field length + "c0fce4e1bf2c", // timestamp + "40", // commitment extensible field length "ad9ac003d08ff305181a345d64fe0b02311cc1a6ec04ab73f3318d90139bfe03", // transactions merkle root "b94301ea4e316bee00109f68d25beaca90aeff08e9bf439a37d91d7a3b5a1470", // tx status hash "040102beef", //BlockWitness @@ -365,7 +365,7 @@ func TestUnmarshalBlockHeader(t *testing.T) { Version: 1, Height: 9223372036854775807, // MaxInt64(9223372036854775807) PreviousBlockHash: testutil.MustDecodeHash("c34048bd60c4c13144fd34f408627d1be68f6cb4fdd34e879d6d791060ea73a0"), - Timestamp: 1528945000, + Timestamp: 1528945000000, BlockCommitment: BlockCommitment{ TransactionsMerkleRoot: testutil.MustDecodeHash("ad9ac003d08ff305181a345d64fe0b02311cc1a6ec04ab73f3318d90139bfe03"), TransactionStatusHash: testutil.MustDecodeHash("b94301ea4e316bee00109f68d25beaca90aeff08e9bf439a37d91d7a3b5a1470"), diff --git a/protocol/validation/block.go b/protocol/validation/block.go index 827750de..3ded430b 100644 --- a/protocol/validation/block.go +++ b/protocol/validation/block.go @@ -26,7 +26,7 @@ var ( ) func checkBlockTime(b *bc.Block, parent *state.BlockNode) error { - if b.Timestamp > uint64(time.Now().Unix())+consensus.MaxTimeOffsetSeconds { + if b.Timestamp > uint64(time.Now().UnixNano()/int64(time.Millisecond))+consensus.MaxTimeOffsetMs { return errBadTimestamp } diff --git a/protocol/validation/block_test.go b/protocol/validation/block_test.go index 83a5baaf..a6fcfeb6 100644 --- a/protocol/validation/block_test.go +++ b/protocol/validation/block_test.go @@ -33,14 +33,14 @@ func TestCheckBlockTime(t *testing.T) { }, { desc: "timestamp greater than max limit (blocktest#1006)", - blockTime: 9999999999, - parentTime: []uint64{1520000000}, + blockTime: 99999999990000, + parentTime: []uint64{15200000000000}, err: errBadTimestamp, }, { desc: "timestamp of the block and the parent block are both greater than max limit (blocktest#1007)", - blockTime: uint64(time.Now().Unix()) + consensus.MaxTimeOffsetSeconds + 2, - parentTime: []uint64{uint64(time.Now().Unix()) + consensus.MaxTimeOffsetSeconds + 1}, + blockTime: uint64(time.Now().UnixNano()/int64(time.Millisecond)) + consensus.MaxTimeOffsetMs + 2000, + parentTime: []uint64{uint64(time.Now().UnixNano()/int64(time.Millisecond)) + consensus.MaxTimeOffsetMs + 1000}, err: errBadTimestamp, }, } @@ -154,14 +154,14 @@ func TestValidateBlockHeader(t *testing.T) { BlockHeader: &bc.BlockHeader{ Version: 1, Height: 1, - Timestamp: 1523352601, + Timestamp: 1523352601000, PreviousBlockId: &bc.Hash{V0: 0}, }, }, parent: &state.BlockNode{ Version: 1, Height: 0, - Timestamp: 1523352600, + Timestamp: 1523352600000, Hash: bc.Hash{V0: 0}, }, err: nil, @@ -230,7 +230,7 @@ func TestValidateBlock(t *testing.T) { BlockHeader: &bc.BlockHeader{ Version: 1, Height: 1, - Timestamp: 1523352601, + Timestamp: 1523352601000, PreviousBlockId: &bc.Hash{V0: 0}, TransactionsRoot: &bc.Hash{V0: 1}, }, @@ -246,7 +246,7 @@ func TestValidateBlock(t *testing.T) { parent: &state.BlockNode{ Version: 1, Height: 0, - Timestamp: 1523352600, + Timestamp: 1523352600000, Hash: bc.Hash{V0: 0}, }, err: errMismatchedMerkleRoot, @@ -258,7 +258,7 @@ func TestValidateBlock(t *testing.T) { BlockHeader: &bc.BlockHeader{ Version: 1, Height: 1, - Timestamp: 1523352601, + Timestamp: 1523352601000, PreviousBlockId: &bc.Hash{V0: 0}, TransactionsRoot: &bc.Hash{V0: 6294987741126419124, V1: 12520373106916389157, V2: 5040806596198303681, V3: 1151748423853876189}, TransactionStatusHash: &bc.Hash{V0: 1}, @@ -275,7 +275,7 @@ func TestValidateBlock(t *testing.T) { parent: &state.BlockNode{ Version: 1, Height: 0, - Timestamp: 1523352600, + Timestamp: 1523352600000, Hash: bc.Hash{V0: 0}, }, err: errMismatchedMerkleRoot, @@ -287,7 +287,7 @@ func TestValidateBlock(t *testing.T) { BlockHeader: &bc.BlockHeader{ Version: 1, Height: 1, - Timestamp: 1523352601, + Timestamp: 1523352601000, PreviousBlockId: &bc.Hash{V0: 0}, }, Transactions: []*bc.Tx{ @@ -308,7 +308,7 @@ func TestValidateBlock(t *testing.T) { parent: &state.BlockNode{ Version: 1, Height: 0, - Timestamp: 1523352600, + Timestamp: 1523352600000, Hash: bc.Hash{V0: 0}, }, err: ErrWrongCoinbaseTransaction, @@ -329,7 +329,7 @@ func TestGasOverBlockLimit(t *testing.T) { parent := &state.BlockNode{ Version: 1, Height: 0, - Timestamp: 1523352600, + Timestamp: 1523352600000, Hash: bc.Hash{V0: 0}, } block := &bc.Block{ @@ -337,7 +337,7 @@ func TestGasOverBlockLimit(t *testing.T) { BlockHeader: &bc.BlockHeader{ Version: 1, Height: 1, - Timestamp: 1523352601, + Timestamp: 1523352601000, PreviousBlockId: &bc.Hash{V0: 0}, TransactionsRoot: &bc.Hash{V0: 1}, }, @@ -375,7 +375,7 @@ func TestSetTransactionStatus(t *testing.T) { parent := &state.BlockNode{ Version: 1, Height: 0, - Timestamp: 1523352600, + Timestamp: 1523352600000, Hash: bc.Hash{V0: 0}, } block := &bc.Block{ @@ -383,7 +383,7 @@ func TestSetTransactionStatus(t *testing.T) { BlockHeader: &bc.BlockHeader{ Version: 1, Height: 1, - Timestamp: 1523352601, + Timestamp: 1523352601000, PreviousBlockId: &bc.Hash{V0: 0}, TransactionsRoot: &bc.Hash{V0: 10011341401654852692, V1: 8144266100226420640, V2: 18332298251154128538, V3: 7663092454615786384}, TransactionStatusHash: &bc.Hash{V0: 8682965660674182538, V1: 8424137560837623409, V2: 6979974817894224946, V3: 4673809519342015041}, diff --git a/protocol/validation/tx_test.go b/protocol/validation/tx_test.go index ed0f06e8..a9a2f3d4 100644 --- a/protocol/validation/tx_test.go +++ b/protocol/validation/tx_test.go @@ -809,7 +809,7 @@ func TestTimeRange(t *testing.T) { block := &bc.Block{ BlockHeader: &bc.BlockHeader{ Height: 333, - Timestamp: 1521625823, + Timestamp: 1521625823000, }, } diff --git a/test/block_test.go b/test/block_test.go index deb54747..1aca2826 100644 --- a/test/block_test.go +++ b/test/block_test.go @@ -60,10 +60,10 @@ func TestBlockHeader(t *testing.T) { valid: false, }, { - desc: "invalid timestamp, greater than MaxTimeOffsetSeconds from system time", + desc: "invalid timestamp, greater than MaxTimeOffsetMs from system time", version: func() uint64 { return chain.BestBlockHeader().Version }, prevHeight: chain.BestBlockHeight, - timestamp: func() uint64 { return uint64(time.Now().Unix()) + consensus.MaxTimeOffsetSeconds + 60 }, + timestamp: func() uint64 { return uint64(time.Now().Unix()) + consensus.MaxTimeOffsetMs + 60 }, prevHash: chain.BestBlockHash, valid: false, }, diff --git a/test/utxo_view/utxo_view_test_util.go b/test/utxo_view/utxo_view_test_util.go index 8110b39b..3948f7e2 100644 --- a/test/utxo_view/utxo_view_test_util.go +++ b/test/utxo_view/utxo_view_test_util.go @@ -365,7 +365,7 @@ func init() { BlockHeader: types.BlockHeader{ Height: 100, PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"), - Timestamp: 1522908275, + Timestamp: 1522908275000, }, Transactions: []*types.Tx{ coinBaseTx(41250000000, "arbitrary block0"), @@ -377,7 +377,7 @@ func init() { BlockHeader: types.BlockHeader{ Height: 101, PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"), - Timestamp: 1522908275, + Timestamp: 1522908275000, }, Transactions: []*types.Tx{ coinBaseTx(41250000000, "arbitrary block1"), @@ -392,7 +392,7 @@ func init() { BlockHeader: types.BlockHeader{ Height: 102, PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"), - Timestamp: 1522908275, + Timestamp: 1522908275000, }, Transactions: []*types.Tx{ coinBaseTx(41250000000, "arbitrary block2"), @@ -404,7 +404,7 @@ func init() { BlockHeader: types.BlockHeader{ Height: 102, PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"), - Timestamp: 1522908275, + Timestamp: 1522908275000, }, Transactions: []*types.Tx{ coinBaseTx(41250000000, "arbitrary block3"), @@ -416,7 +416,7 @@ func init() { BlockHeader: types.BlockHeader{ Height: 103, PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"), - Timestamp: 1522908275, + Timestamp: 1522908275000, }, Transactions: []*types.Tx{ coinBaseTx(41250000000, "arbitrary block4"), @@ -429,7 +429,7 @@ func init() { BlockHeader: types.BlockHeader{ Height: 104, PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"), - Timestamp: 1522908275, + Timestamp: 1522908275000, }, Transactions: []*types.Tx{ coinBaseTx(41250000000, "arbitrary block5"), @@ -440,7 +440,7 @@ func init() { BlockHeader: types.BlockHeader{ Height: 105, PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"), - Timestamp: 1522908275, + Timestamp: 1522908275000, }, Transactions: []*types.Tx{ coinBaseTx(41250000000, "arbitrary block6"), @@ -452,7 +452,7 @@ func init() { BlockHeader: types.BlockHeader{ Height: 106, PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"), - Timestamp: 1522908275, + Timestamp: 1522908275000, }, Transactions: []*types.Tx{ coinBaseTx(41250000000, "arbitrary block7"), @@ -463,7 +463,7 @@ func init() { BlockHeader: types.BlockHeader{ Height: 107, PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"), - Timestamp: 1522908275, + Timestamp: 1522908275000, }, Transactions: []*types.Tx{ coinBaseTx(41250000000, "arbitrary block8"), @@ -476,7 +476,7 @@ func init() { BlockHeader: types.BlockHeader{ Height: 108, PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"), - Timestamp: 1522908275, + Timestamp: 1522908275000, }, Transactions: []*types.Tx{ coinBaseTx(41250000000, "arbitrary block9"), @@ -489,7 +489,7 @@ func init() { BlockHeader: types.BlockHeader{ Height: 105, PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"), - Timestamp: 1522908275, + Timestamp: 1522908275000, }, Transactions: []*types.Tx{ coinBaseTx(41250000000, "arbitrary block10"), @@ -505,7 +505,7 @@ func init() { BlockHeader: types.BlockHeader{ Height: 105, PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"), - Timestamp: 1522908275, + Timestamp: 1522908275000, }, Transactions: []*types.Tx{ coinBaseTx(41250000000, "arbitrary block11"), @@ -520,7 +520,7 @@ func init() { BlockHeader: types.BlockHeader{ Height: 106, PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"), - Timestamp: 1522908275, + Timestamp: 1522908275000, }, Transactions: []*types.Tx{ coinBaseTx(41250000000, "arbitrary block12"), @@ -534,7 +534,7 @@ func init() { BlockHeader: types.BlockHeader{ Height: 107, PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"), - Timestamp: 1522908275, + Timestamp: 1522908275000, }, Transactions: []*types.Tx{ coinBaseTx(41250000000, "arbitrary block13"), @@ -547,7 +547,7 @@ func init() { BlockHeader: types.BlockHeader{ Height: 106, PreviousBlockHash: testutil.MustDecodeHash("0ab29c0bd7bff3b3b7eb98802f8d5f8833884c86c0fb21559a65cc58dda99667"), - Timestamp: 1522908275, + Timestamp: 1522908275000, }, Transactions: []*types.Tx{ coinBaseTx(41250000000, "arbitrary block14"), diff --git a/wallet/unconfirmed.go b/wallet/unconfirmed.go index d634d814..4eec6a2a 100644 --- a/wallet/unconfirmed.go +++ b/wallet/unconfirmed.go @@ -94,7 +94,7 @@ func (w *Wallet) RemoveUnconfirmedTx(txD *protocol.TxDesc) { func (w *Wallet) buildAnnotatedUnconfirmedTx(tx *types.Tx) *query.AnnotatedTx { annotatedTx := &query.AnnotatedTx{ ID: tx.ID, - Timestamp: uint64(time.Now().Unix()), + Timestamp: uint64(time.Now().UnixNano() / int64(time.Millisecond)), Inputs: make([]*query.AnnotatedInput, 0, len(tx.Inputs)), Outputs: make([]*query.AnnotatedOutput, 0, len(tx.Outputs)), Size: tx.SerializedSize, -- 2.11.0 From 754b9dba8dbec3feaca8768363a27a6c8e87242a Mon Sep 17 00:00:00 2001 From: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com> Date: Mon, 20 May 2019 11:22:58 +0800 Subject: [PATCH 09/16] test: add utxo test for cross-chain tx (#72) * init utxo test for cros * fix: fix utxo test * test: add CrossChainOutput utxo test * wip: init cross-in utxo test * test: add cross-in utxo test --- wallet/utxo_test.go | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/wallet/utxo_test.go b/wallet/utxo_test.go index cabff152..825bf334 100644 --- a/wallet/utxo_test.go +++ b/wallet/utxo_test.go @@ -606,6 +606,90 @@ func TestTxOutToUtxos(t *testing.T) { }, }, }, + { + tx: types.NewTx(types.TxData{ + Inputs: []*types.TxInput{ + types.NewSpendInput([][]byte{}, bc.Hash{V0: 1}, bc.AssetID{V0: 1}, 5, 1, []byte{0x51}), + types.NewSpendInput([][]byte{}, bc.Hash{V0: 2}, *consensus.BTMAssetID, 7, 1, []byte{0x51}), + }, + Outputs: []*types.TxOutput{ + types.NewIntraChainOutput(bc.AssetID{V0: 1}, 2, []byte{0x51}), + types.NewCrossChainOutput(bc.AssetID{V0: 1}, 3, []byte{0x52}), + types.NewIntraChainOutput(*consensus.BTMAssetID, 2, []byte{0x53}), + types.NewCrossChainOutput(*consensus.BTMAssetID, 5, []byte{0x54}), + }, + }), + statusFail: false, + vaildHeight: 0, + wantUtxos: []*account.UTXO{ + &account.UTXO{ + OutputID: bc.Hash{V0: 8675398163687045889, V1: 7549510466747714094, V2: 13693077838209211470, V3: 6878568403630757599}, + AssetID: bc.AssetID{V0: 1}, + Amount: 2, + ControlProgram: []byte{0x51}, + SourceID: bc.Hash{V0: 968805671293010031, V1: 9297014342000792994, V2: 16963674611624423333, V3: 2728293460397542670}, + SourcePos: 0, + }, + &account.UTXO{ + OutputID: bc.Hash{V0: 7067560744282869147, V1: 8991714784298240423, V2: 2595857933262917893, V3: 11490631006811252506}, + AssetID: *consensus.BTMAssetID, + Amount: 2, + ControlProgram: []byte{0x53}, + SourceID: bc.Hash{V0: 968805671293010031, V1: 9297014342000792994, V2: 16963674611624423333, V3: 2728293460397542670}, + SourcePos: 2, + }, + }, + }, + { + tx: types.NewTx(types.TxData{ + Inputs: []*types.TxInput{ + types.NewCrossChainInput([][]byte{}, bc.Hash{V0: 1}, bc.AssetID{V0: 1}, 5, 1, []byte{0x51}, []byte("asset1")), + types.NewCrossChainInput([][]byte{}, bc.Hash{V0: 2}, *consensus.BTMAssetID, 7, 1, []byte{0x51}, []byte("assetbtm")), + }, + Outputs: []*types.TxOutput{ + types.NewIntraChainOutput(bc.AssetID{V0: 1}, 2, []byte{0x51}), + types.NewIntraChainOutput(bc.AssetID{V0: 1}, 3, []byte{0x52}), + types.NewIntraChainOutput(*consensus.BTMAssetID, 2, []byte{0x53}), + types.NewIntraChainOutput(*consensus.BTMAssetID, 5, []byte{0x54}), + }, + }), + statusFail: false, + vaildHeight: 0, + wantUtxos: []*account.UTXO{ + &account.UTXO{ + OutputID: bc.Hash{V0: 5017869556807322455, V1: 10783536743298812154, V2: 16502849815258393708, V3: 17463924228237024089}, + AssetID: bc.AssetID{V0: 1}, + Amount: 2, + ControlProgram: []byte{0x51}, + SourceID: bc.Hash{V0: 2128617196155893865, V1: 17686893768984327938, V2: 4126161718447850035, V3: 11059863453240564940}, + SourcePos: 0, + }, + &account.UTXO{ + OutputID: bc.Hash{V0: 8442687171321510229, V1: 178047204952239580, V2: 14256661948207077650, V3: 3922576028594028500}, + AssetID: bc.AssetID{V0: 1}, + Amount: 3, + ControlProgram: []byte{0x52}, + SourceID: bc.Hash{V0: 2128617196155893865, V1: 17686893768984327938, V2: 4126161718447850035, V3: 11059863453240564940}, + SourcePos: 1, + }, + &account.UTXO{ + OutputID: bc.Hash{V0: 15236227421929631619, V1: 17681725875373715927, V2: 6774865146044108440, V3: 2227522355677716485}, + AssetID: *consensus.BTMAssetID, + Amount: 2, + ControlProgram: []byte{0x53}, + SourceID: bc.Hash{V0: 2128617196155893865, V1: 17686893768984327938, V2: 4126161718447850035, V3: 11059863453240564940}, + SourcePos: 2, + }, + &account.UTXO{ + OutputID: bc.Hash{V0: 6086763013160396583, V1: 9766912420896403386, V2: 15586229129198962584, V3: 11214218750546954166}, + AssetID: *consensus.BTMAssetID, + Amount: 5, + ControlProgram: []byte{0x54}, + SourceID: bc.Hash{V0: 2128617196155893865, V1: 17686893768984327938, V2: 4126161718447850035, V3: 11059863453240564940}, + SourcePos: 3, + }, + }, + }, } for i, c := range cases { -- 2.11.0 From 7673e01ba118c9c021aff983f0fbe56ec125d9e3 Mon Sep 17 00:00:00 2001 From: wz Date: Mon, 20 May 2019 14:37:55 +0800 Subject: [PATCH 10/16] V0.1 votetx utxo (#73) * Modify utxo for votetx * fix review * fix test --- account/utxo_keeper.go | 1 + protocol/bc/types/map.go | 9 ++++- protocol/state/utxo_view.go | 67 +++++++++++++++++++++++++++------ protocol/validation/tx.go | 27 ++++++++++--- wallet/utxo.go | 92 ++++++++++++++++++++++++++++++++++----------- wallet/utxo_test.go | 32 +++++++++++++++- 6 files changed, 185 insertions(+), 43 deletions(-) diff --git a/account/utxo_keeper.go b/account/utxo_keeper.go index 2e169cf7..27055269 100644 --- a/account/utxo_keeper.go +++ b/account/utxo_keeper.go @@ -34,6 +34,7 @@ type UTXO struct { Amount uint64 SourcePos uint64 ControlProgram []byte + Vote []byte AccountID string Address string ControlProgramIndex uint64 diff --git a/protocol/bc/types/map.go b/protocol/bc/types/map.go index 8ec61676..4a795b5b 100644 --- a/protocol/bc/types/map.go +++ b/protocol/bc/types/map.go @@ -152,8 +152,13 @@ func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash // connect the inputs to the mux for _, spend := range spends { - spentOutput := entryMap[*spend.SpentOutputId].(*bc.IntraChainOutput) - spend.SetDestination(&muxID, spentOutput.Source.Value, spend.Ordinal) + switch spentOutput := entryMap[*spend.SpentOutputId].(type) { + case *bc.IntraChainOutput: + spend.SetDestination(&muxID, spentOutput.Source.Value, spend.Ordinal) + + case *bc.VoteOutput: + spend.SetDestination(&muxID, spentOutput.Source.Value, spend.Ordinal) + } } for _, crossIn := range crossIns { diff --git a/protocol/state/utxo_view.go b/protocol/state/utxo_view.go index 885f0acf..d1051783 100644 --- a/protocol/state/utxo_view.go +++ b/protocol/state/utxo_view.go @@ -1,10 +1,9 @@ package state import ( - "errors" - "github.com/vapor/consensus" "github.com/vapor/database/storage" + "github.com/vapor/errors" "github.com/vapor/protocol/bc" ) @@ -22,11 +21,22 @@ func NewUtxoViewpoint() *UtxoViewpoint { func (view *UtxoViewpoint) ApplyTransaction(block *bc.Block, tx *bc.Tx, statusFail bool) error { for _, prevout := range tx.SpentOutputIDs { - spentOutput, err := tx.IntraChainOutput(prevout) + assetID := bc.AssetID{} + entryOutput, err := tx.Entry(prevout) if err != nil { return err } - if statusFail && *spentOutput.Source.Value.AssetId != *consensus.BTMAssetID { + + switch output := entryOutput.(type) { + case *bc.IntraChainOutput: + assetID = *output.Source.Value.AssetId + case *bc.VoteOutput: + assetID = *output.Source.Value.AssetId + default: + return errors.Wrapf(bc.ErrEntryType, "entry %x has unexpected type %T", prevout.Bytes(), entryOutput) + } + + if statusFail && assetID != *consensus.BTMAssetID { continue } @@ -44,12 +54,23 @@ func (view *UtxoViewpoint) ApplyTransaction(block *bc.Block, tx *bc.Tx, statusFa } for _, id := range tx.TxHeader.ResultIds { - output, err := tx.IntraChainOutput(*id) + assetID := bc.AssetID{} + entryOutput, err := tx.Entry(*id) if err != nil { - // error due to it's a retirement, utxo doesn't care this output type so skip it continue } - if statusFail && *output.Source.Value.AssetId != *consensus.BTMAssetID { + + switch output := entryOutput.(type) { + case *bc.IntraChainOutput: + assetID = *output.Source.Value.AssetId + case *bc.VoteOutput: + assetID = *output.Source.Value.AssetId + default: + // due to it's a retirement, utxo doesn't care this output type so skip it + continue + } + + if statusFail && assetID != *consensus.BTMAssetID { continue } @@ -82,11 +103,22 @@ func (view *UtxoViewpoint) CanSpend(hash *bc.Hash) bool { func (view *UtxoViewpoint) DetachTransaction(tx *bc.Tx, statusFail bool) error { for _, prevout := range tx.SpentOutputIDs { - spentOutput, err := tx.IntraChainOutput(prevout) + assetID := bc.AssetID{} + entryOutput, err := tx.Entry(prevout) if err != nil { return err } - if statusFail && *spentOutput.Source.Value.AssetId != *consensus.BTMAssetID { + + switch output := entryOutput.(type) { + case *bc.IntraChainOutput: + assetID = *output.Source.Value.AssetId + case *bc.VoteOutput: + assetID = *output.Source.Value.AssetId + default: + return errors.Wrapf(bc.ErrEntryType, "entry %x has unexpected type %T", prevout.Bytes(), entryOutput) + } + + if statusFail && assetID != *consensus.BTMAssetID { continue } @@ -102,12 +134,23 @@ func (view *UtxoViewpoint) DetachTransaction(tx *bc.Tx, statusFail bool) error { } for _, id := range tx.TxHeader.ResultIds { - output, err := tx.IntraChainOutput(*id) + assetID := bc.AssetID{} + entryOutput, err := tx.Entry(*id) if err != nil { - // error due to it's a retirement, utxo doesn't care this output type so skip it continue } - if statusFail && *output.Source.Value.AssetId != *consensus.BTMAssetID { + + switch output := entryOutput.(type) { + case *bc.IntraChainOutput: + assetID = *output.Source.Value.AssetId + case *bc.VoteOutput: + assetID = *output.Source.Value.AssetId + default: + // due to it's a retirement, utxo doesn't care this output type so skip it + continue + } + + if statusFail && assetID != *consensus.BTMAssetID { continue } diff --git a/protocol/validation/tx.go b/protocol/validation/tx.go index 6e0acd24..9225eb2f 100644 --- a/protocol/validation/tx.go +++ b/protocol/validation/tx.go @@ -254,18 +254,35 @@ func checkValid(vs *validationState, e bc.Entry) (err error) { if e.SpentOutputId == nil { return errors.Wrap(ErrMissingField, "spend without spent output ID") } - spentOutput, err := vs.tx.IntraChainOutput(*e.SpentOutputId) + var ( + controlProgram *bc.Program + value *bc.AssetAmount + ) + entryOutput, err := vs.tx.Entry(*e.SpentOutputId) if err != nil { return errors.Wrap(err, "getting spend prevout") } - gasLeft, err := vm.Verify(NewTxVMContext(vs, e, spentOutput.ControlProgram, e.WitnessArguments), vs.gasStatus.GasLeft) + + switch output := entryOutput.(type) { + case *bc.IntraChainOutput: + controlProgram = output.ControlProgram + value = output.Source.Value + case *bc.VoteOutput: + controlProgram = output.ControlProgram + value = output.Source.Value + default: + return errors.Wrapf(bc.ErrEntryType, "entry %x has unexpected type %T", e.SpentOutputId.Bytes(), entryOutput) + } + + gasLeft, err := vm.Verify(NewTxVMContext(vs, e, controlProgram, e.WitnessArguments), vs.gasStatus.GasLeft) if err != nil { return errors.Wrap(err, "checking control program") } if err = vs.gasStatus.updateUsage(gasLeft); err != nil { return err } - eq, err := spentOutput.Source.Value.Equal(e.WitnessDestination.Value) + + eq, err := value.Equal(e.WitnessDestination.Value) if err != nil { return err } @@ -273,8 +290,8 @@ func checkValid(vs *validationState, e bc.Entry) (err error) { return errors.WithDetailf( ErrMismatchedValue, "previous output is for %d unit(s) of %x, spend wants %d unit(s) of %x", - spentOutput.Source.Value.Amount, - spentOutput.Source.Value.AssetId.Bytes(), + value.Amount, + value.AssetId.Bytes(), e.WitnessDestination.Value.Amount, e.WitnessDestination.Value.AssetId.Bytes(), ) diff --git a/wallet/utxo.go b/wallet/utxo.go index 7316623f..20775fdd 100644 --- a/wallet/utxo.go +++ b/wallet/utxo.go @@ -170,24 +170,47 @@ func txInToUtxos(tx *types.Tx, statusFail bool) []*account.UTXO { continue } - resOut, err := tx.IntraChainOutput(*sp.SpentOutputId) + entryOutput, err := tx.Entry(*sp.SpentOutputId) if err != nil { - log.WithFields(log.Fields{"module": logModule, "err": err}).Error("txInToUtxos fail on get resOut") + log.WithFields(log.Fields{"module": logModule, "err": err}).Error("txInToUtxos fail on get entryOutput") continue } - if statusFail && *resOut.Source.Value.AssetId != *consensus.BTMAssetID { + utxo := &account.UTXO{} + switch resOut := entryOutput.(type) { + case *bc.IntraChainOutput: + if statusFail && *resOut.Source.Value.AssetId != *consensus.BTMAssetID { + continue + } + utxo = &account.UTXO{ + OutputID: *sp.SpentOutputId, + AssetID: *resOut.Source.Value.AssetId, + Amount: resOut.Source.Value.Amount, + ControlProgram: resOut.ControlProgram.Code, + SourceID: *resOut.Source.Ref, + SourcePos: resOut.Source.Position, + } + + case *bc.VoteOutput: + if statusFail && *resOut.Source.Value.AssetId != *consensus.BTMAssetID { + continue + } + utxo = &account.UTXO{ + OutputID: *sp.SpentOutputId, + AssetID: *resOut.Source.Value.AssetId, + Amount: resOut.Source.Value.Amount, + ControlProgram: resOut.ControlProgram.Code, + SourceID: *resOut.Source.Ref, + SourcePos: resOut.Source.Position, + Vote: resOut.Vote, + } + + default: + log.WithFields(log.Fields{"module": logModule}).Error("txInToUtxos fail on get resOut") continue } - utxos = append(utxos, &account.UTXO{ - OutputID: *sp.SpentOutputId, - AssetID: *resOut.Source.Value.AssetId, - Amount: resOut.Source.Value.Amount, - ControlProgram: resOut.ControlProgram.Code, - SourceID: *resOut.Source.Ref, - SourcePos: resOut.Source.Position, - }) + utxos = append(utxos, utxo) } return utxos } @@ -195,24 +218,49 @@ func txInToUtxos(tx *types.Tx, statusFail bool) []*account.UTXO { func txOutToUtxos(tx *types.Tx, statusFail bool, vaildHeight uint64) []*account.UTXO { utxos := []*account.UTXO{} for i, out := range tx.Outputs { - bcOut, err := tx.IntraChainOutput(*tx.ResultIds[i]) + entryOutput, err := tx.Entry(*tx.ResultIds[i]) if err != nil { + log.WithFields(log.Fields{"module": logModule, "err": err}).Error("txOutToUtxos fail on get entryOutput") continue } - if statusFail && *out.AssetAmount().AssetId != *consensus.BTMAssetID { + utxo := &account.UTXO{} + switch bcOut := entryOutput.(type) { + case *bc.IntraChainOutput: + if statusFail && *out.AssetAmount().AssetId != *consensus.BTMAssetID { + continue + } + utxo = &account.UTXO{ + OutputID: *tx.OutputID(i), + AssetID: *out.AssetAmount().AssetId, + Amount: out.AssetAmount().Amount, + ControlProgram: out.ControlProgram(), + SourceID: *bcOut.Source.Ref, + SourcePos: bcOut.Source.Position, + ValidHeight: vaildHeight, + } + + case *bc.VoteOutput: + if statusFail && *out.AssetAmount().AssetId != *consensus.BTMAssetID { + continue + } + utxo = &account.UTXO{ + OutputID: *tx.OutputID(i), + AssetID: *out.AssetAmount().AssetId, + Amount: out.AssetAmount().Amount, + ControlProgram: out.ControlProgram(), + SourceID: *bcOut.Source.Ref, + SourcePos: bcOut.Source.Position, + ValidHeight: vaildHeight, + Vote: bcOut.Vote, + } + + default: + log.WithFields(log.Fields{"module": logModule}).Error("txOutToUtxos fail on get bcOut") continue } - utxos = append(utxos, &account.UTXO{ - OutputID: *tx.OutputID(i), - AssetID: *out.AssetAmount().AssetId, - Amount: out.AssetAmount().Amount, - ControlProgram: out.ControlProgram(), - SourceID: *bcOut.Source.Ref, - SourcePos: bcOut.Source.Position, - ValidHeight: vaildHeight, - }) + utxos = append(utxos, utxo) } return utxos } diff --git a/wallet/utxo_test.go b/wallet/utxo_test.go index 825bf334..5f9928de 100644 --- a/wallet/utxo_test.go +++ b/wallet/utxo_test.go @@ -18,7 +18,10 @@ import ( func TestGetAccountUtxos(t *testing.T) { testDB := dbm.NewDB("testdb", "leveldb", "temp") - defer os.RemoveAll("temp") + defer func() { + testDB.Close() + os.RemoveAll("temp") + }() cases := []struct { dbUtxos map[string]*account.UTXO @@ -207,7 +210,10 @@ func TestGetAccountUtxos(t *testing.T) { func TestFilterAccountUtxo(t *testing.T) { testDB := dbm.NewDB("testdb", "leveldb", "temp") - defer os.RemoveAll("temp") + defer func() { + testDB.Close() + os.RemoveAll("temp") + }() cases := []struct { dbPrograms map[string]*account.CtrlProgram @@ -475,6 +481,28 @@ func TestTxInToUtxos(t *testing.T) { }, }, }, + { + tx: types.NewTx(types.TxData{ + Inputs: []*types.TxInput{ + types.NewUnvoteInput([][]byte{}, bc.Hash{V0: 1}, bc.AssetID{V0: 1}, 1, 1, []byte{0x51}, []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269")), + }, + Outputs: []*types.TxOutput{ + types.NewIntraChainOutput(bc.AssetID{V0: 1}, 1, []byte{0x51}), + }, + }), + statusFail: false, + wantUtxos: []*account.UTXO{ + &account.UTXO{ + OutputID: bc.NewHash([32]byte{0x95, 0x23, 0x06, 0xa5, 0x2f, 0xc4, 0xe2, 0x36, 0x03, 0x0f, 0xe3, 0xe6, 0xb8, 0x0b, 0xcc, 0x3c, 0x1e, 0x17, 0x3e, 0x25, 0x95, 0xd0, 0xbf, 0x08, 0x11, 0x73, 0x06, 0xd4, 0x64, 0x9c, 0xfb, 0x3b}), + AssetID: bc.AssetID{V0: 1}, + Amount: 1, + ControlProgram: []byte{0x51}, + Vote: []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"), + SourceID: bc.Hash{V0: 1}, + SourcePos: 1, + }, + }, + }, } for i, c := range cases { -- 2.11.0 From 21fd15fa3624ac538e28b567d19ccc8c60ff027c Mon Sep 17 00:00:00 2001 From: wz Date: Mon, 20 May 2019 15:48:40 +0800 Subject: [PATCH 11/16] fix votetx for validation (#75) --- api/block_retrieve.go | 10 +++++++--- api/query.go | 2 ++ protocol/validation/block.go | 13 +++++++++---- protocol/validation/vmcontext.go | 27 +++++++++++++++++++-------- wallet/utxo.go | 11 ++++++++--- 5 files changed, 45 insertions(+), 18 deletions(-) diff --git a/api/block_retrieve.go b/api/block_retrieve.go index 4b85fde8..27897ffd 100644 --- a/api/block_retrieve.go +++ b/api/block_retrieve.go @@ -93,10 +93,14 @@ func (a *API) getBlock(ins BlockReq) Response { } resOutID := orig.ResultIds[0] - resOut, ok := orig.Entries[*resOutID].(*bc.IntraChainOutput) - if ok { + switch resOut := orig.Entries[*resOutID].(type) { + case *bc.IntraChainOutput: tx.MuxID = *resOut.Source.Ref - } else { + case *bc.CrossChainOutput: + tx.MuxID = *resOut.Source.Ref + case *bc.VoteOutput: + tx.MuxID = *resOut.Source.Ref + case *bc.Retirement: resRetire, _ := orig.Entries[*resOutID].(*bc.Retirement) tx.MuxID = *resRetire.Source.Ref } diff --git a/api/query.go b/api/query.go index 369443d1..a3e927bf 100644 --- a/api/query.go +++ b/api/query.go @@ -203,6 +203,8 @@ func (a *API) getUnconfirmedTx(ctx context.Context, filter struct { switch out := resOut.(type) { case *bc.IntraChainOutput: tx.MuxID = *out.Source.Ref + case *bc.VoteOutput: + tx.MuxID = *out.Source.Ref case *bc.Retirement: tx.MuxID = *out.Source.Ref } diff --git a/protocol/validation/block.go b/protocol/validation/block.go index 3ded430b..8b63df0e 100644 --- a/protocol/validation/block.go +++ b/protocol/validation/block.go @@ -46,12 +46,17 @@ func checkCoinbaseAmount(b *bc.Block, amount uint64) error { return errors.Wrap(ErrWrongCoinbaseTransaction, "have more than 1 output") } - output, err := tx.IntraChainOutput(*tx.TxHeader.ResultIds[0]) - if err != nil { - return err + var SourceAmount uint64 + switch output := tx.Entries[*tx.TxHeader.ResultIds[0]].(type) { + case *bc.IntraChainOutput: + SourceAmount = output.Source.Value.Amount + case *bc.VoteOutput: + SourceAmount = output.Source.Value.Amount + default: + return errors.Wrapf(bc.ErrEntryType, "entry %x has unexpected type %T", tx.TxHeader.ResultIds[0].Bytes(), output) } - if output.Source.Value.Amount != amount { + if SourceAmount != amount { return errors.Wrap(ErrWrongCoinbaseTransaction, "dismatch output amount") } return nil diff --git a/protocol/validation/vmcontext.go b/protocol/validation/vmcontext.go index f7b62bcf..610a8eb7 100644 --- a/protocol/validation/vmcontext.go +++ b/protocol/validation/vmcontext.go @@ -25,15 +25,23 @@ func NewTxVMContext(vs *validationState, entry bc.Entry, prog *bc.Program, args ) switch e := entry.(type) { - case *bc.Spend: - spentOutput := tx.Entries[*e.SpentOutputId].(*bc.IntraChainOutput) - a1 := spentOutput.Source.Value.AssetId.Bytes() - assetID = &a1 - amount = &spentOutput.Source.Value.Amount - destPos = &e.WitnessDestination.Position - s := e.SpentOutputId.Bytes() - spentOutputID = &s + switch spentOutput := tx.Entries[*e.SpentOutputId].(type) { + case *bc.IntraChainOutput: + a1 := spentOutput.Source.Value.AssetId.Bytes() + assetID = &a1 + amount = &spentOutput.Source.Value.Amount + destPos = &e.WitnessDestination.Position + s := e.SpentOutputId.Bytes() + spentOutputID = &s + case *bc.VoteOutput: + a1 := spentOutput.Source.Value.AssetId.Bytes() + assetID = &a1 + amount = &spentOutput.Source.Value.Amount + destPos = &e.WitnessDestination.Position + s := e.SpentOutputId.Bytes() + spentOutputID = &s + } } var txSigHash *[]byte @@ -111,6 +119,9 @@ func (ec *entryContext) checkOutput(index uint64, amount uint64, assetID []byte, case *bc.IntraChainOutput: return check(e.ControlProgram, e.Source.Value), nil + case *bc.VoteOutput: + return check(e.ControlProgram, e.Source.Value), nil + case *bc.Retirement: var prog bc.Program if expansion { diff --git a/wallet/utxo.go b/wallet/utxo.go index 20775fdd..c5d106c3 100644 --- a/wallet/utxo.go +++ b/wallet/utxo.go @@ -79,12 +79,17 @@ func (w *Wallet) detachUtxos(batch dbm.Batch, b *types.Block, txStatus *bc.Trans for txIndex := len(b.Transactions) - 1; txIndex >= 0; txIndex-- { tx := b.Transactions[txIndex] for j := range tx.Outputs { - resOut, err := tx.IntraChainOutput(*tx.ResultIds[j]) - if err != nil { + code := []byte{} + switch resOut := tx.Entries[*tx.ResultIds[j]].(type) { + case *bc.IntraChainOutput: + code = resOut.ControlProgram.Code + case *bc.VoteOutput: + code = resOut.ControlProgram.Code + default: continue } - if segwit.IsP2WScript(resOut.ControlProgram.Code) { + if segwit.IsP2WScript(code) { batch.Delete(account.StandardUTXOKey(*tx.ResultIds[j])) } else { batch.Delete(account.ContractUTXOKey(*tx.ResultIds[j])) -- 2.11.0 From 322bc6bcd6f842719322930e7589963dd823615a Mon Sep 17 00:00:00 2001 From: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com> Date: Mon, 20 May 2019 20:16:50 +0800 Subject: [PATCH 12/16] feat: build cross-out tx (#74) * wip: init for build cross_chain_out * wip: init DecodeCrossOutAction * fix: fix crossOutAction.Build() * wip: rename test * wip: init TestBuildCrossOut * feat: add TestBuildCrossOut * refactor: rename crossOutAction.ActionType * refactor: add address instead of arbitrary in build crossOutAction * fix: fix DefaultDataDir * fix: fix TestBuildCrossOut * refactor: clean up --- api/transact.go | 1 + blockchain/txbuilder/actions.go | 56 +++++++++++++++++++++++++++++++- blockchain/txbuilder/txbuilder_test.go | 58 +++++++++++++++++++++++++++++++++- config/config.go | 10 +++--- 4 files changed, 118 insertions(+), 7 deletions(-) diff --git a/api/transact.go b/api/transact.go index 25d61bca..4a6c17c2 100644 --- a/api/transact.go +++ b/api/transact.go @@ -26,6 +26,7 @@ func (a *API) actionDecoder(action string) (func([]byte) (txbuilder.Action, erro "control_address": txbuilder.DecodeControlAddressAction, "control_program": txbuilder.DecodeControlProgramAction, "retire": txbuilder.DecodeRetireAction, + "cross_chain_out": txbuilder.DecodeCrossOutAction, "spend_account": a.wallet.AccountMgr.DecodeSpendAction, "spend_account_unspent_output": a.wallet.AccountMgr.DecodeSpendUTXOAction, } diff --git a/blockchain/txbuilder/actions.go b/blockchain/txbuilder/actions.go index 185be8e5..8da65a79 100644 --- a/blockchain/txbuilder/actions.go +++ b/blockchain/txbuilder/actions.go @@ -44,9 +44,9 @@ func (a *controlAddressAction) Build(ctx context.Context, b *TemplateBuilder) er if err != nil { return err } + redeemContract := address.ScriptAddress() program := []byte{} - switch address.(type) { case *common.AddressWitnessPubKeyHash: program, err = vmutil.P2WPKHProgram(redeemContract) @@ -137,3 +137,57 @@ func (a *retireAction) Build(ctx context.Context, b *TemplateBuilder) error { func (a *retireAction) ActionType() string { return "retire" } + +// DecodeCrossOutAction convert input data to action struct +func DecodeCrossOutAction(data []byte) (Action, error) { + a := new(crossOutAction) + err := stdjson.Unmarshal(data, a) + return a, err +} + +type crossOutAction struct { + bc.AssetAmount + Address string `json:"address"` +} + +func (a *crossOutAction) Build(ctx context.Context, b *TemplateBuilder) error { + var missing []string + if a.Address == "" { + missing = append(missing, "address") + } + if a.AssetId.IsZero() { + missing = append(missing, "asset_id") + } + if a.Amount == 0 { + missing = append(missing, "amount") + } + if len(missing) > 0 { + return MissingFieldsError(missing...) + } + + address, err := common.DecodeAddress(a.Address, &consensus.MainNetParams) + if err != nil { + return err + } + + redeemContract := address.ScriptAddress() + program := []byte{} + switch address.(type) { + case *common.AddressWitnessPubKeyHash: + program, err = vmutil.P2WPKHProgram(redeemContract) + case *common.AddressWitnessScriptHash: + program, err = vmutil.P2WSHProgram(redeemContract) + default: + return errors.New("unsupport address type") + } + if err != nil { + return err + } + + out := types.NewCrossChainOutput(*a.AssetId, a.Amount, program) + return b.AddOutput(out) +} + +func (a *crossOutAction) ActionType() string { + return "cross_chain_out" +} diff --git a/blockchain/txbuilder/txbuilder_test.go b/blockchain/txbuilder/txbuilder_test.go index 2fcd6a6a..8cd14327 100644 --- a/blockchain/txbuilder/txbuilder_test.go +++ b/blockchain/txbuilder/txbuilder_test.go @@ -46,7 +46,7 @@ func newControlProgramAction(assetAmt bc.AssetAmount, script []byte) *controlPro } } -func TestBuild(t *testing.T) { +func TestBuildIntra(t *testing.T) { ctx := context.Background() assetID1 := bc.NewAssetID([32]byte{1}) @@ -87,6 +87,62 @@ func TestBuild(t *testing.T) { } } +func newCrossOutAction(assetAmt bc.AssetAmount, redeemContract []byte) *crossOutAction { + address, err := common.NewAddressWitnessPubKeyHash(redeemContract, &consensus.MainNetParams) + if err != nil { + panic(err) + } + + return &crossOutAction{ + AssetAmount: assetAmt, + Address: address.String(), + } +} + +func TestBuildCrossOut(t *testing.T) { + ctx := context.Background() + + assetID1 := bc.NewAssetID([32]byte{1}) + assetID2 := bc.NewAssetID([32]byte{2}) + + redeemContract := make([]byte, 20) + controlProgram := append([]byte{0x00, byte(len(redeemContract))}, redeemContract...) + + actions := []Action{ + newCrossOutAction(bc.AssetAmount{AssetId: &assetID2, Amount: 6}, redeemContract), + testAction(bc.AssetAmount{AssetId: &assetID1, Amount: 5}), + } + expiryTime := time.Now().Add(time.Minute) + got, err := Build(ctx, nil, actions, expiryTime, 0) + if err != nil { + testutil.FatalErr(t, err) + } + + want := &Template{ + Transaction: types.NewTx(types.TxData{ + Version: 1, + Inputs: []*types.TxInput{ + types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), assetID1, 5, 0, nil), + }, + Outputs: []*types.TxOutput{ + types.NewCrossChainOutput(assetID2, 6, controlProgram), + types.NewIntraChainOutput(assetID1, 5, []byte("change")), + }, + }), + SigningInstructions: []*SigningInstruction{{ + WitnessComponents: []witnessComponent{}, + }}, + } + + if !testutil.DeepEqual(got.Transaction.TxData, want.Transaction.TxData) { + t.Errorf("got tx:\n%s\nwant tx:\n%s", spew.Sdump(got.Transaction.TxData), spew.Sdump(want.Transaction.TxData)) + } + + if !testutil.DeepEqual(got.SigningInstructions, want.SigningInstructions) { + t.Errorf("got signing instructions:\n\t%#v\nwant signing instructions:\n\t%#v", got.SigningInstructions, want.SigningInstructions) + } +} + func mustDecodeHex(str string) []byte { data, err := hex.DecodeString(str) if err != nil { diff --git a/config/config.go b/config/config.go index 03d7d6fb..69b4882e 100644 --- a/config/config.go +++ b/config/config.go @@ -241,14 +241,14 @@ func DefaultDataDir() string { // Try to place the data folder in the user's home dir home := homeDir() if home == "" { - return "./.bytom" + return "./.vapor" } switch runtime.GOOS { case "darwin": // In order to be compatible with old data path, // copy the data from the old path to the new path - oldPath := filepath.Join(home, "Library", "Bytom") - newPath := filepath.Join(home, "Library", "Application Support", "Bytom") + oldPath := filepath.Join(home, "Library", "Vapor") + newPath := filepath.Join(home, "Library", "Application Support", "Vapor") if !isFolderNotExists(oldPath) && isFolderNotExists(newPath) { if err := os.Rename(oldPath, newPath); err != nil { log.Errorf("DefaultDataDir: %v", err) @@ -257,9 +257,9 @@ func DefaultDataDir() string { } return newPath case "windows": - return filepath.Join(home, "AppData", "Roaming", "Bytom") + return filepath.Join(home, "AppData", "Roaming", "Vapor") default: - return filepath.Join(home, ".bytom") + return filepath.Join(home, ".vapor") } } -- 2.11.0 From b64c31ed916f8a091e5453ccccadfda6db480e88 Mon Sep 17 00:00:00 2001 From: yahtoo Date: Tue, 21 May 2019 14:22:26 +0800 Subject: [PATCH 13/16] netsync: add txs msg (#78) --- netsync/handle.go | 25 ++++++++++++++++++ netsync/message.go | 40 +++++++++++++++++++++++++++++ netsync/message_test.go | 68 +++++++++++++++++++++++++++++++++++++++++++++++++ netsync/peer.go | 43 +++++++++++++++++++++++-------- netsync/tx_keeper.go | 4 +-- 5 files changed, 167 insertions(+), 13 deletions(-) diff --git a/netsync/handle.go b/netsync/handle.go index ce10e1ac..7dc35b90 100644 --- a/netsync/handle.go +++ b/netsync/handle.go @@ -323,6 +323,28 @@ func (sm *SyncManager) handleTransactionMsg(peer *peer, msg *TransactionMessage) if isOrphan, err := sm.chain.ValidateTx(tx); err != nil && err != core.ErrDustTx && !isOrphan { sm.peers.addBanScore(peer.ID(), 10, 0, "fail on validate tx transaction") } + sm.peers.markTx(peer.ID(), tx.ID) +} + +func (sm *SyncManager) handleTransactionsMsg(peer *peer, msg *TransactionsMessage) { + txs, err := msg.GetTransactions() + if err != nil { + sm.peers.addBanScore(peer.ID(), 0, 20, "fail on get txs from message") + return + } + + if len(txs) > txsMsgMaxTxNum { + sm.peers.addBanScore(peer.ID(), 20, 0, "exceeded the maximum tx number limit") + return + } + + for _, tx := range txs { + if isOrphan, err := sm.chain.ValidateTx(tx); err != nil && !isOrphan { + sm.peers.addBanScore(peer.ID(), 10, 0, "fail on validate tx transaction") + return + } + sm.peers.markTx(peer.ID(), tx.ID) + } } func (sm *SyncManager) IsListening() bool { @@ -365,6 +387,9 @@ func (sm *SyncManager) processMsg(basePeer BasePeer, msgType byte, msg Blockchai case *TransactionMessage: sm.handleTransactionMsg(peer, msg) + case *TransactionsMessage: + sm.handleTransactionsMsg(peer, msg) + case *MineBlockMessage: sm.handleMineBlockMsg(peer, msg) diff --git a/netsync/message.go b/netsync/message.go index 1c86d142..b4f702a2 100644 --- a/netsync/message.go +++ b/netsync/message.go @@ -25,6 +25,7 @@ const ( BlocksResponseByte = byte(0x15) StatusByte = byte(0x21) NewTransactionByte = byte(0x30) + NewTransactionsByte = byte(0x31) NewMineBlockByte = byte(0x40) FilterLoadByte = byte(0x50) FilterAddByte = byte(0x51) @@ -33,6 +34,7 @@ const ( MerkleResponseByte = byte(0x61) maxBlockchainResponseSize = 22020096 + 2 + txsMsgMaxTxNum = 1024 ) //BlockchainMessage is a generic message for this reactor. @@ -50,6 +52,7 @@ var _ = wire.RegisterInterface( wire.ConcreteType{&BlocksMessage{}, BlocksResponseByte}, wire.ConcreteType{&StatusMessage{}, StatusByte}, wire.ConcreteType{&TransactionMessage{}, NewTransactionByte}, + wire.ConcreteType{&TransactionsMessage{}, NewTransactionsByte}, wire.ConcreteType{&MineBlockMessage{}, NewMineBlockByte}, wire.ConcreteType{&FilterLoadMessage{}, FilterLoadByte}, wire.ConcreteType{&FilterAddMessage{}, FilterAddByte}, @@ -327,6 +330,43 @@ func (m *TransactionMessage) String() string { return fmt.Sprintf("{tx_size: %d, tx_hash: %s}", len(m.RawTx), tx.ID.String()) } +//TransactionsMessage notify new txs msg +type TransactionsMessage struct { + RawTxs [][]byte +} + +//NewTransactionsMessage construct notify new txs msg +func NewTransactionsMessage(txs []*types.Tx) (*TransactionsMessage, error) { + rawTxs := make([][]byte, 0, len(txs)) + for _, tx := range txs { + rawTx, err := tx.TxData.MarshalText() + if err != nil { + return nil, err + } + + rawTxs = append(rawTxs, rawTx) + } + return &TransactionsMessage{RawTxs: rawTxs}, nil +} + +//GetTransactions get txs from msg +func (m *TransactionsMessage) GetTransactions() ([]*types.Tx, error) { + txs := make([]*types.Tx, 0, len(m.RawTxs)) + for _, rawTx := range m.RawTxs { + tx := &types.Tx{} + if err := tx.UnmarshalText(rawTx); err != nil { + return nil, err + } + + txs = append(txs, tx) + } + return txs, nil +} + +func (m *TransactionsMessage) String() string { + return fmt.Sprintf("{tx_num: %d}", len(m.RawTxs)) +} + //MineBlockMessage new mined block msg type MineBlockMessage struct { RawBlock []byte diff --git a/netsync/message_test.go b/netsync/message_test.go index 5c40a680..14bb71fa 100644 --- a/netsync/message_test.go +++ b/netsync/message_test.go @@ -6,10 +6,78 @@ import ( "github.com/davecgh/go-spew/spew" + "github.com/vapor/consensus" "github.com/vapor/protocol/bc" "github.com/vapor/protocol/bc/types" ) +var txs = []*types.Tx{ + types.NewTx(types.TxData{ + SerializedSize: uint64(52), + Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})}, + Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 5000, nil)}, + }), + types.NewTx(types.TxData{ + SerializedSize: uint64(53), + Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01, 0x02})}, + Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 5000, nil)}, + }), + types.NewTx(types.TxData{ + SerializedSize: uint64(54), + Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01, 0x02, 0x03})}, + Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 5000, nil)}, + }), + types.NewTx(types.TxData{ + SerializedSize: uint64(54), + Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01, 0x02, 0x03})}, + Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 2000, nil)}, + }), + types.NewTx(types.TxData{ + SerializedSize: uint64(54), + Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01, 0x02, 0x03})}, + Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 10000, nil)}, + }), +} + +func TestTransactionMessage(t *testing.T) { + for _, tx := range txs { + txMsg, err := NewTransactionMessage(tx) + if err != nil { + t.Fatalf("create tx msg err:%s", err) + } + + gotTx, err := txMsg.GetTransaction() + if err != nil { + t.Fatalf("get txs from txsMsg err:%s", err) + } + if !reflect.DeepEqual(*tx.Tx, *gotTx.Tx) { + t.Errorf("txs msg test err: got %s\nwant %s", spew.Sdump(tx.Tx), spew.Sdump(gotTx.Tx)) + } + } +} + +func TestTransactionsMessage(t *testing.T) { + txsMsg, err := NewTransactionsMessage(txs) + if err != nil { + t.Fatalf("create txs msg err:%s", err) + } + + gotTxs, err := txsMsg.GetTransactions() + if err != nil { + t.Fatalf("get txs from txsMsg err:%s", err) + } + + if len(gotTxs) != len(txs) { + t.Fatal("txs msg test err: number of txs not match ") + } + + for i, tx := range txs { + if !reflect.DeepEqual(tx.Tx, gotTxs[i].Tx) { + t.Errorf("txs msg test err: got %s\nwant %s", spew.Sdump(tx.Tx), spew.Sdump(gotTxs[i].Tx)) + } + } +} + var testBlock = &types.Block{ BlockHeader: types.BlockHeader{ Version: 1, diff --git a/netsync/peer.go b/netsync/peer.go index 246f1bc1..794501b9 100644 --- a/netsync/peer.go +++ b/netsync/peer.go @@ -297,25 +297,35 @@ func (p *peer) sendMerkleBlock(block *types.Block, txStatuses *bc.TransactionSta return ok, nil } -func (p *peer) sendTransactions(txs []*types.Tx) (bool, error) { - for _, tx := range txs { - if p.isSPVNode() && !p.isRelatedTx(tx) { +func (p *peer) sendTransactions(txs []*types.Tx) error { + validTxs := make([]*types.Tx, 0, len(txs)) + for i, tx := range txs { + if p.isSPVNode() && !p.isRelatedTx(tx) || p.knownTxs.Has(tx.ID.String()) { continue } - msg, err := NewTransactionMessage(tx) - if err != nil { - return false, errors.Wrap(err, "failed to tx msg") - } - if p.knownTxs.Has(tx.ID.String()) { + validTxs = append(validTxs, tx) + if len(validTxs) != txsMsgMaxTxNum && i != len(txs)-1 { continue } + + msg, err := NewTransactionsMessage(validTxs) + if err != nil { + return err + } + if ok := p.TrySend(BlockchainChannel, struct{ BlockchainMessage }{msg}); !ok { - return ok, nil + return errors.New("failed to send txs msg") + } + + for _, validTx := range validTxs { + p.knownTxs.Add(validTx.ID.String()) } - p.knownTxs.Add(tx.ID.String()) + + validTxs = make([]*types.Tx, 0, len(txs)) } - return true, nil + + return nil } func (p *peer) sendStatus(header *types.BlockHeader) error { @@ -481,6 +491,17 @@ func (ps *peerSet) getPeerInfos() []*PeerInfo { return result } +func (ps *peerSet) markTx(peerID string, txHash bc.Hash) { + ps.mtx.Lock() + peer := ps.peers[peerID] + ps.mtx.Unlock() + + if peer == nil { + return + } + peer.markTransaction(&txHash) +} + func (ps *peerSet) peersWithoutBlock(hash *bc.Hash) []*peer { ps.mtx.RLock() defer ps.mtx.RUnlock() diff --git a/netsync/tx_keeper.go b/netsync/tx_keeper.go index 6c4a8bbb..5b95ba9d 100644 --- a/netsync/tx_keeper.go +++ b/netsync/tx_keeper.go @@ -100,8 +100,8 @@ func (sm *SyncManager) txSyncLoop() { }).Debug("txSyncLoop sending transactions") sending = true go func() { - ok, err := peer.sendTransactions(sendTxs) - if !ok { + err := peer.sendTransactions(sendTxs) + if err != nil { sm.peers.removePeer(msg.peerID) } done <- err -- 2.11.0 From d2ec2911b1f5642c1b74b450b6e69e69a4a80fa1 Mon Sep 17 00:00:00 2001 From: wz Date: Tue, 21 May 2019 15:17:38 +0800 Subject: [PATCH 14/16] add votetx output action (#79) --- api/transact.go | 1 + blockchain/txbuilder/actions.go | 58 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/api/transact.go b/api/transact.go index 4a6c17c2..be9714d2 100644 --- a/api/transact.go +++ b/api/transact.go @@ -27,6 +27,7 @@ func (a *API) actionDecoder(action string) (func([]byte) (txbuilder.Action, erro "control_program": txbuilder.DecodeControlProgramAction, "retire": txbuilder.DecodeRetireAction, "cross_chain_out": txbuilder.DecodeCrossOutAction, + "vote_output": txbuilder.DecodeVoteOutputAction, "spend_account": a.wallet.AccountMgr.DecodeSpendAction, "spend_account_unspent_output": a.wallet.AccountMgr.DecodeSpendUTXOAction, } diff --git a/blockchain/txbuilder/actions.go b/blockchain/txbuilder/actions.go index 8da65a79..d5baf78b 100644 --- a/blockchain/txbuilder/actions.go +++ b/blockchain/txbuilder/actions.go @@ -191,3 +191,61 @@ func (a *crossOutAction) Build(ctx context.Context, b *TemplateBuilder) error { func (a *crossOutAction) ActionType() string { return "cross_chain_out" } + +// DecodeVoteOutputAction convert input data to action struct +func DecodeVoteOutputAction(data []byte) (Action, error) { + a := new(voteOutputAction) + err := stdjson.Unmarshal(data, a) + return a, err +} + +type voteOutputAction struct { + bc.AssetAmount + Address string `json:"address"` + Vote json.HexBytes `json:"vote"` +} + +func (a *voteOutputAction) Build(ctx context.Context, b *TemplateBuilder) error { + var missing []string + if a.Address == "" { + missing = append(missing, "address") + } + if a.AssetId.IsZero() { + missing = append(missing, "asset_id") + } + if a.Amount == 0 { + missing = append(missing, "amount") + } + if len(a.Vote) == 0 { + missing = append(missing, "vote") + } + if len(missing) > 0 { + return MissingFieldsError(missing...) + } + + address, err := common.DecodeAddress(a.Address, &consensus.ActiveNetParams) + if err != nil { + return err + } + + redeemContract := address.ScriptAddress() + program := []byte{} + switch address.(type) { + case *common.AddressWitnessPubKeyHash: + program, err = vmutil.P2WPKHProgram(redeemContract) + case *common.AddressWitnessScriptHash: + program, err = vmutil.P2WSHProgram(redeemContract) + default: + return errors.New("unsupport address type") + } + if err != nil { + return err + } + + out := types.NewVoteOutput(*a.AssetId, a.Amount, program, a.Vote) + return b.AddOutput(out) +} + +func (a *voteOutputAction) ActionType() string { + return "vote_output" +} -- 2.11.0 From cc0bcc7e1e4fc53e669ac46ba3fe919b5c6a79c9 Mon Sep 17 00:00:00 2001 From: wz Date: Tue, 21 May 2019 19:32:35 +0800 Subject: [PATCH 15/16] unvotetx action (#80) * add votetx output action * add unvotetx action * add voteoutput change * add unit test --- account/builder.go | 79 +++++++++++++++++++++++++++++++++++--- account/utxo_keeper.go | 9 +++-- account/utxo_keeper_test.go | 92 +++++++++++++++++++++++++++++++++++++++++++-- api/transact.go | 1 + 4 files changed, 168 insertions(+), 13 deletions(-) diff --git a/account/builder.go b/account/builder.go index d8160568..027e1fbe 100644 --- a/account/builder.go +++ b/account/builder.go @@ -2,13 +2,14 @@ package account import ( "context" - "encoding/json" + stdjson "encoding/json" "github.com/vapor/blockchain/signers" "github.com/vapor/blockchain/txbuilder" "github.com/vapor/common" "github.com/vapor/consensus" "github.com/vapor/crypto/ed25519/chainkd" + "github.com/vapor/encoding/json" "github.com/vapor/errors" "github.com/vapor/protocol/bc" "github.com/vapor/protocol/bc/types" @@ -25,7 +26,7 @@ var ( //DecodeSpendAction unmarshal JSON-encoded data of spend action func (m *Manager) DecodeSpendAction(data []byte) (txbuilder.Action, error) { a := &spendAction{accounts: m} - return a, json.Unmarshal(data, a) + return a, stdjson.Unmarshal(data, a) } type spendAction struct { @@ -77,7 +78,7 @@ func (m *Manager) reserveBtmUtxoChain(builder *txbuilder.TemplateBuilder, accoun utxos := []*UTXO{} for gasAmount := uint64(0); reservedAmount < gasAmount+amount; gasAmount = calcMergeGas(len(utxos)) { reserveAmount := amount + gasAmount - reservedAmount - res, err := m.utxoKeeper.Reserve(accountID, consensus.BTMAssetID, reserveAmount, useUnconfirmed, builder.MaxTime()) + res, err := m.utxoKeeper.Reserve(accountID, consensus.BTMAssetID, reserveAmount, useUnconfirmed, nil, builder.MaxTime()) if err != nil { return nil, err } @@ -218,7 +219,7 @@ func (a *spendAction) Build(ctx context.Context, b *txbuilder.TemplateBuilder) e return errors.Wrap(err, "get account info") } - res, err := a.accounts.utxoKeeper.Reserve(a.AccountID, a.AssetId, a.Amount, a.UseUnconfirmed, b.MaxTime()) + res, err := a.accounts.utxoKeeper.Reserve(a.AccountID, a.AssetId, a.Amount, a.UseUnconfirmed, nil, b.MaxTime()) if err != nil { return errors.Wrap(err, "reserving utxos") } @@ -254,7 +255,7 @@ func (a *spendAction) Build(ctx context.Context, b *txbuilder.TemplateBuilder) e //DecodeSpendUTXOAction unmarshal JSON-encoded data of spend utxo action func (m *Manager) DecodeSpendUTXOAction(data []byte) (txbuilder.Action, error) { a := &spendUTXOAction{accounts: m} - return a, json.Unmarshal(data, a) + return a, stdjson.Unmarshal(data, a) } type spendUTXOAction struct { @@ -379,3 +380,71 @@ func (m *Manager) insertControlProgramDelayed(b *txbuilder.TemplateBuilder, acp return m.SaveControlPrograms(acps...) }) } + +//DecodeUnvoteAction unmarshal JSON-encoded data of spend action +func (m *Manager) DecodeUnvoteAction(data []byte) (txbuilder.Action, error) { + a := &unvoteAction{accounts: m} + return a, stdjson.Unmarshal(data, a) +} + +type unvoteAction struct { + accounts *Manager + bc.AssetAmount + AccountID string `json:"account_id"` + Vote json.HexBytes `json:"vote"` + UseUnconfirmed bool `json:"use_unconfirmed"` +} + +func (a *unvoteAction) ActionType() string { + return "unvote" +} + +func (a *unvoteAction) Build(ctx context.Context, b *txbuilder.TemplateBuilder) error { + var missing []string + if a.AccountID == "" { + missing = append(missing, "account_id") + } + if a.AssetId.IsZero() { + missing = append(missing, "asset_id") + } + if len(missing) > 0 { + return txbuilder.MissingFieldsError(missing...) + } + + acct, err := a.accounts.FindByID(a.AccountID) + if err != nil { + return errors.Wrap(err, "get account info") + } + + res, err := a.accounts.utxoKeeper.Reserve(a.AccountID, a.AssetId, a.Amount, a.UseUnconfirmed, a.Vote, b.MaxTime()) + if err != nil { + return errors.Wrap(err, "reserving utxos") + } + + // Cancel the reservation if the build gets rolled back. + b.OnRollback(func() { a.accounts.utxoKeeper.Cancel(res.id) }) + for _, r := range res.utxos { + txInput, sigInst, err := UtxoToInputs(acct.Signer, r) + if err != nil { + return errors.Wrap(err, "creating inputs") + } + + if err = b.AddInput(txInput, sigInst); err != nil { + return errors.Wrap(err, "adding inputs") + } + } + + if res.change > 0 { + acp, err := a.accounts.CreateAddress(a.AccountID, true) + if err != nil { + return errors.Wrap(err, "creating control program") + } + + // Don't insert the control program until callbacks are executed. + a.accounts.insertControlProgramDelayed(b, acp) + if err = b.AddOutput(types.NewVoteOutput(*a.AssetId, res.change, acp.ControlProgram, a.Vote)); err != nil { + return errors.Wrap(err, "adding change voteOutput") + } + } + return nil +} diff --git a/account/utxo_keeper.go b/account/utxo_keeper.go index 27055269..cd9beea6 100644 --- a/account/utxo_keeper.go +++ b/account/utxo_keeper.go @@ -1,6 +1,7 @@ package account import ( + "bytes" "container/list" "encoding/json" "sort" @@ -112,11 +113,11 @@ func (uk *utxoKeeper) RemoveUnconfirmedUtxo(hashes []*bc.Hash) { } } -func (uk *utxoKeeper) Reserve(accountID string, assetID *bc.AssetID, amount uint64, useUnconfirmed bool, exp time.Time) (*reservation, error) { +func (uk *utxoKeeper) Reserve(accountID string, assetID *bc.AssetID, amount uint64, useUnconfirmed bool, vote []byte, exp time.Time) (*reservation, error) { uk.mtx.Lock() defer uk.mtx.Unlock() - utxos, immatureAmount := uk.findUtxos(accountID, assetID, useUnconfirmed) + utxos, immatureAmount := uk.findUtxos(accountID, assetID, useUnconfirmed, vote) optUtxos, optAmount, reservedAmount := uk.optUTXOs(utxos, amount) if optAmount+reservedAmount+immatureAmount < amount { return nil, ErrInsufficient @@ -203,12 +204,12 @@ func (uk *utxoKeeper) expireReservation(t time.Time) { } } -func (uk *utxoKeeper) findUtxos(accountID string, assetID *bc.AssetID, useUnconfirmed bool) ([]*UTXO, uint64) { +func (uk *utxoKeeper) findUtxos(accountID string, assetID *bc.AssetID, useUnconfirmed bool, vote []byte) ([]*UTXO, uint64) { immatureAmount := uint64(0) currentHeight := uk.currentHeight() utxos := []*UTXO{} appendUtxo := func(u *UTXO) { - if u.AccountID != accountID || u.AssetID != *assetID { + if u.AccountID != accountID || u.AssetID != *assetID || !bytes.Equal(u.Vote, vote) { return } if u.ValidHeight > currentHeight { diff --git a/account/utxo_keeper_test.go b/account/utxo_keeper_test.go index bb9d0105..6cd48791 100644 --- a/account/utxo_keeper_test.go +++ b/account/utxo_keeper_test.go @@ -273,7 +273,10 @@ func TestRemoveUnconfirmedUtxo(t *testing.T) { func TestReserve(t *testing.T) { currentHeight := func() uint64 { return 9527 } testDB := dbm.NewDB("testdb", "leveldb", "temp") - defer os.RemoveAll("temp") + defer func() { + testDB.Close() + os.RemoveAll("temp") + }() cases := []struct { before utxoKeeper @@ -281,6 +284,7 @@ func TestReserve(t *testing.T) { err error reserveAmount uint64 exp time.Time + vote []byte }{ { before: utxoKeeper{ @@ -516,10 +520,60 @@ func TestReserve(t *testing.T) { err: nil, exp: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC), }, + { + before: utxoKeeper{ + db: testDB, + currentHeight: currentHeight, + unconfirmed: map[bc.Hash]*UTXO{ + bc.NewHash([32]byte{0x01}): &UTXO{ + OutputID: bc.NewHash([32]byte{0x01}), + AccountID: "testAccount", + Amount: 3, + Vote: []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"), + }, + }, + reserved: map[bc.Hash]uint64{}, + reservations: map[uint64]*reservation{}, + }, + after: utxoKeeper{ + db: testDB, + currentHeight: currentHeight, + unconfirmed: map[bc.Hash]*UTXO{ + bc.NewHash([32]byte{0x01}): &UTXO{ + OutputID: bc.NewHash([32]byte{0x01}), + AccountID: "testAccount", + Amount: 3, + Vote: []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"), + }, + }, + reserved: map[bc.Hash]uint64{ + bc.NewHash([32]byte{0x01}): 1, + }, + reservations: map[uint64]*reservation{ + 1: &reservation{ + id: 1, + utxos: []*UTXO{ + &UTXO{ + OutputID: bc.NewHash([32]byte{0x01}), + AccountID: "testAccount", + Amount: 3, + Vote: []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"), + }, + }, + change: 1, + expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC), + }, + }, + }, + reserveAmount: 2, + err: nil, + exp: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC), + vote: []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"), + }, } for i, c := range cases { - if _, err := c.before.Reserve("testAccount", &bc.AssetID{}, c.reserveAmount, true, c.exp); err != c.err { + if _, err := c.before.Reserve("testAccount", &bc.AssetID{}, c.reserveAmount, true, c.vote, c.exp); err != c.err { t.Errorf("case %d: got error %v want error %v", i, err, c.err) } checkUtxoKeeperEqual(t, i, &c.before, &c.after) @@ -684,7 +738,10 @@ func TestExpireReservation(t *testing.T) { func TestFindUtxos(t *testing.T) { currentHeight := func() uint64 { return 9527 } testDB := dbm.NewDB("testdb", "leveldb", "temp") - defer os.RemoveAll("temp") + defer func() { + testDB.Close() + os.RemoveAll("temp") + }() cases := []struct { uk utxoKeeper @@ -692,6 +749,7 @@ func TestFindUtxos(t *testing.T) { useUnconfirmed bool wantUtxos []*UTXO immatureAmount uint64 + vote []byte }{ { uk: utxoKeeper{ @@ -858,6 +916,32 @@ func TestFindUtxos(t *testing.T) { }, immatureAmount: 0, }, + { + uk: utxoKeeper{ + db: testDB, + currentHeight: currentHeight, + unconfirmed: map[bc.Hash]*UTXO{}, + }, + dbUtxos: []*UTXO{ + &UTXO{ + OutputID: bc.NewHash([32]byte{0x01}), + AccountID: "testAccount", + Amount: 6, + Vote: []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"), + }, + }, + useUnconfirmed: false, + wantUtxos: []*UTXO{ + &UTXO{ + OutputID: bc.NewHash([32]byte{0x01}), + AccountID: "testAccount", + Amount: 6, + Vote: []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"), + }, + }, + immatureAmount: 0, + vote: []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"), + }, } for i, c := range cases { @@ -869,7 +953,7 @@ func TestFindUtxos(t *testing.T) { testDB.Set(StandardUTXOKey(u.OutputID), data) } - gotUtxos, immatureAmount := c.uk.findUtxos("testAccount", &bc.AssetID{}, c.useUnconfirmed) + gotUtxos, immatureAmount := c.uk.findUtxos("testAccount", &bc.AssetID{}, c.useUnconfirmed, c.vote) if !testutil.DeepEqual(gotUtxos, c.wantUtxos) { t.Errorf("case %d: got %v want %v", i, gotUtxos, c.wantUtxos) } diff --git a/api/transact.go b/api/transact.go index be9714d2..350ed85d 100644 --- a/api/transact.go +++ b/api/transact.go @@ -30,6 +30,7 @@ func (a *API) actionDecoder(action string) (func([]byte) (txbuilder.Action, erro "vote_output": txbuilder.DecodeVoteOutputAction, "spend_account": a.wallet.AccountMgr.DecodeSpendAction, "spend_account_unspent_output": a.wallet.AccountMgr.DecodeSpendUTXOAction, + "unvote": a.wallet.AccountMgr.DecodeUnvoteAction, } decoder, ok := decoders[action] return decoder, ok -- 2.11.0 From e34f38162f5d016893e53d6f14d47ed06dafe031 Mon Sep 17 00:00:00 2001 From: muscle_boy Date: Wed, 22 May 2019 14:29:17 +0800 Subject: [PATCH 16/16] Dpos process block (#69) * add bbft process block * merge v0.1 * remove functional test * opt code * opt code * opt code * bug fix * bug fix * opt code * opt code * bug fix * add update consensus node * opt code --- .travis.yml | 3 - Makefile | 2 +- common/bit_map.go | 53 +++++ database/store.go | 31 ++- database/store_test.go | 4 +- protocol/bbft.go | 240 +++++++++++++++++++++ protocol/bbft/bbft.go | 39 ---- protocol/bbft/consensus_node_manager.go | 170 --------------- ...consensus_node_manager_test.go => bbft_test.go} | 42 ++-- protocol/block.go | 53 ++++- protocol/consensus_node_manager.go | 205 ++++++++++++++++++ protocol/protocol.go | 18 +- protocol/state/blockindex.go | 22 +- protocol/state/blockindex_test.go | 5 +- protocol/store.go | 15 +- protocol/txpool_test.go | 6 +- protocol/validation/tx.go | 2 +- test/utxo_view/utxo_view_test.go | 4 +- 18 files changed, 645 insertions(+), 269 deletions(-) create mode 100644 common/bit_map.go create mode 100644 protocol/bbft.go delete mode 100644 protocol/bbft/bbft.go delete mode 100644 protocol/bbft/consensus_node_manager.go rename protocol/{bbft/consensus_node_manager_test.go => bbft_test.go} (68%) create mode 100644 protocol/consensus_node_manager.go diff --git a/.travis.yml b/.travis.yml index 63925506..02a340a5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,9 +6,6 @@ sudo: false matrix: include: - go: 1.11.4 - - go: tip - allow_failures: - - go: tip branches: only: diff --git a/Makefile b/Makefile index 1345055c..fa8426b1 100644 --- a/Makefile +++ b/Makefile @@ -133,6 +133,6 @@ benchmark: functional-tests: @go test -timeout=5m -tags="functional" ./test -ci: test functional-tests +ci: test .PHONY: all target release-all clean test benchmark diff --git a/common/bit_map.go b/common/bit_map.go new file mode 100644 index 00000000..6dabaebd --- /dev/null +++ b/common/bit_map.go @@ -0,0 +1,53 @@ +package common + +import ( + "errors" +) + +const bitLen = 32 + +var ( + errIndexOutOfBounds = errors.New("index out of bounds error") +) + +type BitMap struct { + size uint32 + arr []int32 +} + +func NewBitMap(size uint32) *BitMap { + obj := &BitMap{size: size} + num := (size + bitLen - 1) / bitLen + arr := make([]int32, num) + obj.arr = arr + return obj +} + +func (b *BitMap) Set(index uint32) error { + if index >= b.size { + return errIndexOutOfBounds + } + + arrIndex, bitIndex := index / bitLen, index % bitLen + b.arr[arrIndex] |= (1 << bitIndex) + return nil +} + +func (b *BitMap) Clean(index uint32) error { + if index >= b.size { + return errIndexOutOfBounds + } + + arrIndex, bitIndex := index / bitLen, index % bitLen + b.arr[arrIndex] &= (^(1 << bitIndex)) + return nil +} + +func (b *BitMap) Test(index uint32) (bool, error) { + if index >= b.size { + return false, errIndexOutOfBounds + } + + arrIndex, bitIndex := index / bitLen, index % bitLen + return b.arr[arrIndex] & (1 << bitIndex) != 0, nil +} diff --git a/database/store.go b/database/store.go index c037b320..d218f0b1 100644 --- a/database/store.go +++ b/database/store.go @@ -136,7 +136,7 @@ func (s *Store) GetStoreStatus() *protocol.BlockStoreState { func (s *Store) GetVoteResult(seq uint64) (*state.VoteResult, error) { data := s.db.Get(calcVoteResultKey(seq)) if data == nil { - return nil, errors.New("can't find the vote result by given sequence") + return nil, protocol.ErrNotFoundVoteResult } vr := &state.VoteResult{} @@ -224,13 +224,22 @@ func (s *Store) SaveBlock(block *types.Block, ts *bc.TransactionStatus) error { } // SaveChainStatus save the core's newest status && delete old status -func (s *Store) SaveChainStatus(node *state.BlockNode, view *state.UtxoViewpoint) error { +func (s *Store) SaveChainStatus(node, irreversibleNode *state.BlockNode, view *state.UtxoViewpoint, voteMap map[uint64]*state.VoteResult) error { batch := s.db.NewBatch() if err := saveUtxoView(batch, view); err != nil { return err } - bytes, err := json.Marshal(protocol.BlockStoreState{Height: node.Height, Hash: &node.Hash}) + if err := saveVoteResult(batch, voteMap); err != nil { + return err + } + + bytes, err := json.Marshal(protocol.BlockStoreState{ + Height: node.Height, + Hash: &node.Hash, + IrreversibleHeight: irreversibleNode.Height, + IrreversibleHash: &irreversibleNode.Hash, + }) if err != nil { return err } @@ -240,13 +249,15 @@ func (s *Store) SaveChainStatus(node *state.BlockNode, view *state.UtxoViewpoint return nil } -// SaveVoteResult update the voting results generated by each irreversible block -func (s *Store) SaveVoteResult(vr *state.VoteResult) error { - bytes, err := json.Marshal(vr) - if err != nil { - return err - } +// saveVoteResult update the voting results generated by each irreversible block +func saveVoteResult(batch dbm.Batch, voteMap map[uint64]*state.VoteResult) error { + for _, vote := range voteMap { + bytes, err := json.Marshal(vote) + if err != nil { + return err + } - s.db.Set(calcVoteResultKey(vr.Seq), bytes) + batch.Set(calcVoteResultKey(vote.Seq), bytes) + } return nil } diff --git a/database/store_test.go b/database/store_test.go index ee8c02cd..deffc051 100644 --- a/database/store_test.go +++ b/database/store_test.go @@ -155,11 +155,11 @@ func TestSaveChainStatus(t *testing.T) { }, } - if err := store.SaveChainStatus(node, view); err != nil { + if err := store.SaveChainStatus(node, node, view, map[uint64]*state.VoteResult{}); err != nil { t.Fatal(err) } - expectStatus := &protocol.BlockStoreState{Height: node.Height, Hash: &node.Hash} + expectStatus := &protocol.BlockStoreState{Height: node.Height, Hash: &node.Hash, IrreversibleHeight: node.Height, IrreversibleHash: &node.Hash} if !testutil.DeepEqual(store.GetStoreStatus(), expectStatus) { t.Errorf("got block status:%v, expect block status:%v", store.GetStoreStatus(), expectStatus) } diff --git a/protocol/bbft.go b/protocol/bbft.go new file mode 100644 index 00000000..9315ca89 --- /dev/null +++ b/protocol/bbft.go @@ -0,0 +1,240 @@ +package protocol + +import ( + "encoding/hex" + "time" + + "github.com/vapor/crypto/ed25519" + "github.com/vapor/crypto/ed25519/chainkd" + "github.com/vapor/errors" + "github.com/vapor/math/checked" + "github.com/vapor/protocol/bc/types" + "github.com/vapor/protocol/state" +) + +var ( + errVotingOperationOverFlow = errors.New("voting operation result overflow") +) + +type bbft struct { + consensusNodeManager *consensusNodeManager +} + +func newBbft(store Store, blockIndex *state.BlockIndex) *bbft { + return &bbft{ + consensusNodeManager: newConsensusNodeManager(store, blockIndex), + } +} + +// IsConsensusPubkey determine whether a public key is a consensus node at a specified height +func (b *bbft) IsConsensusPubkey(height uint64, pubkey []byte) (bool, error) { + node, err := b.consensusNodeManager.getConsensusNode(height, hex.EncodeToString(pubkey)) + if err != nil && err != errNotFoundConsensusNode { + return false, err + } + return node != nil, nil +} + +func (b *bbft) isIrreversible(block *types.Block) bool { + signNum, err := b.validateSign(block) + if err != nil { + return false + } + + return signNum > (numOfConsensusNode * 2 / 3) +} + +// NextLeaderTime returns the start time of the specified public key as the next leader node +func (b *bbft) NextLeaderTime(pubkey []byte, bestBlockTimestamp, bestBlockHeight uint64) (*time.Time, error) { + return b.consensusNodeManager.nextLeaderTime(pubkey, bestBlockTimestamp, bestBlockHeight) +} + +func (b *bbft) ApplyBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) (err error) { + voteSeq := block.Height / roundVoteBlockNums + voteResult := voteResultMap[voteSeq] + + if voteResult == nil { + store := b.consensusNodeManager.store + voteResult, err = store.GetVoteResult(voteSeq) + if err != nil && err != ErrNotFoundVoteResult { + return err + } + } + + if voteResult == nil { + voteResult = &state.VoteResult{ + Seq: voteSeq, + NumOfVote: make(map[string]uint64), + LastBlockHeight: block.Height, + } + } + + voteResultMap[voteSeq] = voteResult + + if voteResult.LastBlockHeight+1 != block.Height { + return errors.New("bbft append block error, the block height is not equals last block height plus 1 of vote result") + } + + for _, tx := range block.Transactions { + for _, input := range tx.Inputs { + unVoteInput, ok := input.TypedInput.(*types.UnvoteInput) + if !ok { + continue + } + + pubkey := hex.EncodeToString(unVoteInput.Vote) + voteResult.NumOfVote[pubkey], ok = checked.SubUint64(voteResult.NumOfVote[pubkey], unVoteInput.Amount) + if !ok { + return errVotingOperationOverFlow + } + } + for _, output := range tx.Outputs { + voteOutput, ok := output.TypedOutput.(*types.VoteTxOutput) + if !ok { + continue + } + + pubkey := hex.EncodeToString(voteOutput.Vote) + voteResult.NumOfVote[pubkey], ok = checked.AddUint64(voteResult.NumOfVote[pubkey], voteOutput.Amount) + if !ok { + return errVotingOperationOverFlow + } + } + } + + voteResult.LastBlockHeight++ + voteResult.Finalized = (block.Height+1)%roundVoteBlockNums == 0 + return nil +} + +func (b *bbft) DetachBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) error { + voteSeq := block.Height / roundVoteBlockNums + voteResult := voteResultMap[voteSeq] + + if voteResult == nil { + store := b.consensusNodeManager.store + voteResult, err := store.GetVoteResult(voteSeq) + if err != nil { + return err + } + voteResultMap[voteSeq] = voteResult + } + + if voteResult.LastBlockHeight != block.Height { + return errors.New("bbft detach block error, the block height is not equals last block height of vote result") + } + + for _, tx := range block.Transactions { + for _, input := range tx.Inputs { + unVoteInput, ok := input.TypedInput.(*types.UnvoteInput) + if !ok { + continue + } + + pubkey := hex.EncodeToString(unVoteInput.Vote) + voteResult.NumOfVote[pubkey], ok = checked.AddUint64(voteResult.NumOfVote[pubkey], unVoteInput.Amount) + if !ok { + return errVotingOperationOverFlow + } + } + for _, output := range tx.Outputs { + voteOutput, ok := output.TypedOutput.(*types.VoteTxOutput) + if !ok { + continue + } + + pubkey := hex.EncodeToString(voteOutput.Vote) + voteResult.NumOfVote[pubkey], ok = checked.SubUint64(voteResult.NumOfVote[pubkey], voteOutput.Amount) + if !ok { + return errVotingOperationOverFlow + } + } + } + + voteResult.LastBlockHeight-- + voteResult.Finalized = false + return nil +} + +// ValidateBlock verify whether the block is valid +func (b *bbft) ValidateBlock(block *types.Block) error { + signNum, err := b.validateSign(block) + if err != nil { + return err + } + + if signNum == 0 { + return errors.New("no valid signature") + } + return nil +} + +// validateSign verify the signatures of block, and return the number of correct signature +// if some signature is invalid, they will be reset to nil +// if the block has not the signature of blocker, it will return error +func (b *bbft) validateSign(block *types.Block) (uint64, error) { + var correctSignNum uint64 + consensusNodeMap, err := b.consensusNodeManager.getConsensusNodesByVoteResult(block.Height) + if err != nil { + return 0, err + } + + hasBlockerSign := false + for pubkey, node := range consensusNodeMap { + if len(block.Witness) <= int(node.order) { + continue + } + + blocks := b.consensusNodeManager.blockIndex.NodesByHeight(block.Height) + for _, b := range blocks { + if b.Hash == block.Hash() { + continue + } + if ok, err := b.BlockWitness.Test(uint32(node.order)); err != nil && ok { + // Consensus node is signed twice with the same block height, discard the signature + block.Witness[node.order] = nil + break + } + } + + if ed25519.Verify(ed25519.PublicKey(pubkey), block.Hash().Bytes(), block.Witness[node.order]) { + correctSignNum++ + isBlocker, err := b.consensusNodeManager.isBlocker(block.Height, block.Timestamp, pubkey) + if err != nil { + return 0, err + } + if isBlocker { + hasBlockerSign = true + } + } else { + // discard the invalid signature + block.Witness[node.order] = nil + } + } + if !hasBlockerSign { + return 0, errors.New("the block has no signature of the blocker") + } + return correctSignNum, nil +} + +// SignBlock signing the block if current node is consensus node +func (b *bbft) SignBlock(block *types.Block) error { + var xprv chainkd.XPrv + xpub := [64]byte(xprv.XPub()) + node, err := b.consensusNodeManager.getConsensusNode(block.Height, hex.EncodeToString(xpub[:])) + if err != nil && err != errNotFoundConsensusNode { + return err + } + + if node == nil { + return nil + } + + block.Witness[node.order] = xprv.Sign(block.Hash().Bytes()) + return nil +} + +// UpdateConsensusNodes used to update consensus node after each round of voting +func (b *bbft) UpdateConsensusNodes(blockHeight uint64) error { + return b.consensusNodeManager.updateConsensusNodes(blockHeight) +} diff --git a/protocol/bbft/bbft.go b/protocol/bbft/bbft.go deleted file mode 100644 index e8a483f1..00000000 --- a/protocol/bbft/bbft.go +++ /dev/null @@ -1,39 +0,0 @@ -package bbft - -import ( - "time" - - "github.com/vapor/crypto/ed25519" - "github.com/vapor/errors" - "github.com/vapor/protocol/bc" - "github.com/vapor/protocol" - "github.com/vapor/database" -) - -type bbft struct { - consensusNodeManager *consensusNodeManager -} - -func newBbft(store *database.Store, chain *protocol.Chain) *bbft { - return &bbft{ - consensusNodeManager: newConsensusNodeManager(store, chain), - } -} - -// IsConsensusPubkey determine whether a public key is a consensus node at a specified height -func (b *bbft) IsConsensusPubkey(height uint64, pubkey []byte) (bool, error) { - return b.consensusNodeManager.isConsensusPubkey(height, pubkey) -} - -// NextLeaderTime returns the start time of the specified public key as the next leader node -func (b *bbft) NextLeaderTime(pubkey []byte) (*time.Time, error) { - return b.consensusNodeManager.nextLeaderTime(pubkey) -} - -// ValidateSign verify the signature of block id -func (b *bbft) ValidateSign(blockID bc.Hash, pubkey, sign []byte) error { - if ok := ed25519.Verify(ed25519.PublicKey(pubkey), blockID.Bytes(), sign); !ok { - return errors.New("validate block signature fail") - } - return nil -} diff --git a/protocol/bbft/consensus_node_manager.go b/protocol/bbft/consensus_node_manager.go deleted file mode 100644 index 8f758412..00000000 --- a/protocol/bbft/consensus_node_manager.go +++ /dev/null @@ -1,170 +0,0 @@ -package bbft - -import ( - "encoding/hex" - "fmt" - "sort" - "sync" - "time" - - "github.com/vapor/database" - "github.com/vapor/errors" - "github.com/vapor/protocol" -) - -const ( - numOfConsensusNode = 21 - roundVoteBlockNums = 1000 - - // product one block per 500 milliseconds - blockTimeInterval = 500 - blockNumEachNode = 3 -) - -var ( - errHasNoChanceProductBlock = errors.New("the node has no chance to product a block in this round of voting") -) - -type consensusNode struct { - pubkey string - voteNum uint64 - order uint64 -} - -type consensusNodeSlice []*consensusNode - -func (c consensusNodeSlice) Len() int { return len(c) } -func (c consensusNodeSlice) Less(i, j int) bool { return c[i].voteNum > c[j].voteNum } -func (c consensusNodeSlice) Swap(i, j int) { c[i], c[j] = c[j], c[i] } - -type consensusNodeManager struct { - consensusNodeMap map[string]*consensusNode - effectiveStartHeight uint64 - store *database.Store - chain *protocol.Chain - sync.RWMutex -} - -func newConsensusNodeManager(store *database.Store, chain *protocol.Chain) *consensusNodeManager { - return &consensusNodeManager{ - consensusNodeMap: make(map[string]*consensusNode), - effectiveStartHeight: 1, - chain: chain, - store: store, - } -} - -func (c *consensusNodeManager) isConsensusPubkey(height uint64, pubkey []byte) (bool, error) { - defer c.RUnlock() - c.RLock() - if height >= c.effectiveStartHeight + roundVoteBlockNums { - return false, errors.New("the vote has not been completed for the specified block height ") - } - - var err error - consensusNodeMap := c.consensusNodeMap - // query history vote result - if height < c.effectiveStartHeight { - consensusNodeMap, err = c.getConsensusNodesByVoteResult(height / roundVoteBlockNums) - if err != nil { - return false, err - } - } - - encodePubkey := hex.EncodeToString(pubkey) - _, exist := consensusNodeMap[encodePubkey] - return exist, nil -} - -func (c *consensusNodeManager) nextLeaderTime(pubkey []byte) (*time.Time, error) { - defer c.RLock() - c.RLock() - - encodePubkey := hex.EncodeToString(pubkey) - consensusNode, ok := c.consensusNodeMap[encodePubkey] - if !ok { - return nil, fmt.Errorf("pubkey:%s is not consensus node", encodePubkey) - } - - startBlockHeight := c.effectiveStartHeight - bestBlockHeight := c.chain.BestBlockHeight() - - prevRoundLastBlock, err := c.chain.GetHeaderByHeight(startBlockHeight - 1) - if err != nil { - return nil, err - } - - startTime := prevRoundLastBlock.Timestamp * 1000 + blockTimeInterval - return nextLeaderTimeHelper(startBlockHeight, bestBlockHeight, startTime, consensusNode.order) -} - -func nextLeaderTimeHelper(startBlockHeight, bestBlockHeight, startTime, nodeOrder uint64) (*time.Time, error) { - endBlockHeight := startBlockHeight + roundVoteBlockNums - // exclude genesis block - if startBlockHeight == 1 { - endBlockHeight-- - } - - roundBlockNums := uint64(blockNumEachNode * numOfConsensusNode) - latestRoundBlockHeight := startBlockHeight + (bestBlockHeight - startBlockHeight) / roundBlockNums * roundBlockNums - nextBlockHeight := latestRoundBlockHeight + blockNumEachNode * nodeOrder - - if int64(bestBlockHeight - nextBlockHeight) >= blockNumEachNode { - nextBlockHeight += roundBlockNums - if nextBlockHeight > endBlockHeight { - return nil, errHasNoChanceProductBlock - } - } - - nextLeaderTimestamp := int64(startTime + (nextBlockHeight - startBlockHeight) * blockTimeInterval) - nextLeaderTime := time.Unix(nextLeaderTimestamp / 1000, (nextLeaderTimestamp % 1000) * 1e6) - return &nextLeaderTime, nil -} - -// UpdateConsensusNodes used to update consensus node after each round of voting -func (c *consensusNodeManager) UpdateConsensusNodes(voteSeq uint64) error { - defer c.Unlock() - c.Lock() - if voteSeq <= c.effectiveStartHeight / roundVoteBlockNums { - return nil - } - - consensusNodeMap, err := c.getConsensusNodesByVoteResult(voteSeq) - if err != nil { - return err - } - - c.consensusNodeMap = consensusNodeMap - c.effectiveStartHeight = voteSeq * roundVoteBlockNums - return nil -} - -func (c *consensusNodeManager) getConsensusNodesByVoteResult(voteSeq uint64) (map[string]*consensusNode, error) { - voteResult, err := c.store.GetVoteResult(voteSeq) - if err != nil { - return nil, err - } - - if !voteResult.Finalized { - return nil, errors.New("vote result is not finalized") - } - - var nodes []*consensusNode - for pubkey, voteNum := range voteResult.NumOfVote { - nodes = append(nodes, &consensusNode{ - pubkey: pubkey, - voteNum: voteNum, - }) - } - // In principle, there is no need to sort all voting nodes. - // if there is a performance problem, consider the optimization later. - // TODO not consider the same number of votes - sort.Sort(consensusNodeSlice(nodes)) - - result := make(map[string]*consensusNode) - for i, node := range nodes { - node.order = uint64(i) - result[node.pubkey] = node - } - return result, nil -} diff --git a/protocol/bbft/consensus_node_manager_test.go b/protocol/bbft_test.go similarity index 68% rename from protocol/bbft/consensus_node_manager_test.go rename to protocol/bbft_test.go index bb534032..7af6f5b9 100644 --- a/protocol/bbft/consensus_node_manager_test.go +++ b/protocol/bbft_test.go @@ -1,4 +1,4 @@ -package bbft +package protocol import ( "testing" @@ -7,80 +7,80 @@ import ( func TestNextLeaderTime(t *testing.T) { cases := []struct { desc string - startBlockHeight uint64 - bestBlockHeight uint64 startTime uint64 + endTime uint64 + now uint64 nodeOrder uint64 wantError error wantNextLeaderTime int64 }{ { desc: "normal case", - startBlockHeight: 1000, - bestBlockHeight: 1500, startTime: 1557906284061, + endTime: 1557906784061, + now: 1557906534061, nodeOrder: 1, wantError: nil, wantNextLeaderTime: 1557906537561, }, { desc: "best block height equals to start block height", - startBlockHeight: 1000, - bestBlockHeight: 1000, startTime: 1557906284061, + endTime: 1557906784061, + now: 1557906284061, nodeOrder: 0, wantError: nil, wantNextLeaderTime: 1557906284061, }, { desc: "best block height equals to start block height", - startBlockHeight: 1000, - bestBlockHeight: 1000, startTime: 1557906284061, + endTime: 1557906784061, + now: 1557906284061, nodeOrder: 1, wantError: nil, - wantNextLeaderTime: 1557906284061 + blockNumEachNode * blockTimeInterval, + wantNextLeaderTime: 1557906284061 + blockNumEachNode*blockTimeInterval, }, { desc: "has no chance product block in this round of voting", - startBlockHeight: 1000, - bestBlockHeight: 1995, startTime: 1557906284061, + endTime: 1557906784061, + now: 1557906781561, nodeOrder: 1, wantError: errHasNoChanceProductBlock, wantNextLeaderTime: 0, }, { desc: "the node is producting block", - startBlockHeight: 1000, - bestBlockHeight: 1001, startTime: 1557906284061, + endTime: 1557906784061, + now: 1557906284561, nodeOrder: 0, wantError: nil, wantNextLeaderTime: 1557906284061, }, { desc: "the node is producting block", - startBlockHeight: 1000, - bestBlockHeight: 1067, startTime: 1557906284061, + endTime: 1557906784061, + now: 1557906317561, nodeOrder: 1, wantError: nil, - wantNextLeaderTime: 1557906284061 + 66 * blockTimeInterval, + wantNextLeaderTime: 1557906284061 + 66*blockTimeInterval, }, { desc: "first round, must exclude genesis block", - startBlockHeight: 1, - bestBlockHeight: 5, startTime: 1557906284061, + endTime: 1557906783561, + now: 1557906286561, nodeOrder: 3, wantError: nil, - wantNextLeaderTime: 1557906284061 + 9 * blockTimeInterval, + wantNextLeaderTime: 1557906284061 + 9*blockTimeInterval, }, } for i, c := range cases { - nextLeaderTime, err := nextLeaderTimeHelper(c.startBlockHeight, c.bestBlockHeight, c.startTime, c.nodeOrder) + nextLeaderTime, err := nextLeaderTimeHelper(c.startTime, c.endTime, c.now, c.nodeOrder) if err != c.wantError { t.Fatalf("case #%d (%s) want error:%v, got error:%v", i, c.desc, c.wantError, err) } diff --git a/protocol/block.go b/protocol/block.go index ad4647b5..983e6cd8 100644 --- a/protocol/block.go +++ b/protocol/block.go @@ -74,6 +74,7 @@ func (c *Chain) calcReorganizeNodes(node *state.BlockNode) ([]*state.BlockNode, } func (c *Chain) connectBlock(block *types.Block) (err error) { + irreversibleNode := c.bestIrreversibleNode bcBlock := types.MapBlock(block) if bcBlock.TransactionStatus, err = c.store.GetTransactionStatus(&bcBlock.ID); err != nil { return err @@ -87,8 +88,17 @@ func (c *Chain) connectBlock(block *types.Block) (err error) { return err } + voteResultMap := make(map[uint64]*state.VoteResult) + if err := c.bbft.ApplyBlock(voteResultMap, block); err != nil { + return err + } + node := c.index.GetNode(&bcBlock.ID) - if err := c.setState(node, utxoView); err != nil { + if c.bbft.isIrreversible(block) && block.Height > irreversibleNode.Height { + irreversibleNode = node + } + + if err := c.setState(node, irreversibleNode, utxoView, voteResultMap); err != nil { return err } @@ -101,13 +111,19 @@ func (c *Chain) connectBlock(block *types.Block) (err error) { func (c *Chain) reorganizeChain(node *state.BlockNode) error { attachNodes, detachNodes := c.calcReorganizeNodes(node) utxoView := state.NewUtxoViewpoint() - + voteResultMap := make(map[uint64]*state.VoteResult) + irreversibleNode := c.bestIrreversibleNode + for _, detachNode := range detachNodes { b, err := c.store.GetBlock(&detachNode.Hash) if err != nil { return err } + if b.Height <= irreversibleNode.Height { + return errors.New("the height of rollback block below the height of irreversible block") + } + detachBlock := types.MapBlock(b) if err := c.store.GetTransactionsUtxo(utxoView, detachBlock.Transactions); err != nil { return err @@ -119,6 +135,10 @@ func (c *Chain) reorganizeChain(node *state.BlockNode) error { if err := utxoView.DetachBlock(detachBlock, txStatus); err != nil { return err } + + if err := c.bbft.DetachBlock(voteResultMap, b); err != nil { + return err + } log.WithFields(log.Fields{"module": logModule, "height": node.Height, "hash": node.Hash.String()}).Debug("detach from mainchain") } @@ -141,20 +161,36 @@ func (c *Chain) reorganizeChain(node *state.BlockNode) error { return err } + if err := c.bbft.ApplyBlock(voteResultMap, b); err != nil { + return err + } + + if c.bbft.isIrreversible(b) && b.Height > irreversibleNode.Height { + irreversibleNode = attachNode + } + log.WithFields(log.Fields{"module": logModule, "height": node.Height, "hash": node.Hash.String()}).Debug("attach from mainchain") } - return c.setState(node, utxoView) + return c.setState(node, irreversibleNode, utxoView, voteResultMap) } // SaveBlock will validate and save block into storage func (c *Chain) saveBlock(block *types.Block) error { - bcBlock := types.MapBlock(block) + if err := c.bbft.ValidateBlock(block); err != nil { + return errors.Sub(ErrBadBlock, err) + } + parent := c.index.GetNode(&block.PreviousBlockHash) + if err := validation.ValidateBlock(types.MapBlock(block), parent); err != nil { + return errors.Sub(ErrBadBlock, err) + } - if err := validation.ValidateBlock(bcBlock, parent); err != nil { + if err := c.bbft.SignBlock(block); err != nil { return errors.Sub(ErrBadBlock, err) } + + bcBlock := types.MapBlock(block) if err := c.store.SaveBlock(block, bcBlock.TransactionStatus); err != nil { return err } @@ -222,13 +258,18 @@ func (c *Chain) blockProcesser() { // ProcessBlock is the entry for handle block insert func (c *Chain) processBlock(block *types.Block) (bool, error) { + if block.Height <= c.bestIrreversibleNode.Height { + return false, errors.New("the height of block below the height of irreversible block") + } + blockHash := block.Hash() if c.BlockExist(&blockHash) { log.WithFields(log.Fields{"module": logModule, "hash": blockHash.String(), "height": block.Height}).Info("block has been processed") return c.orphanManage.BlockExist(&blockHash), nil } - if parent := c.index.GetNode(&block.PreviousBlockHash); parent == nil { + parent := c.index.GetNode(&block.PreviousBlockHash) + if parent == nil { c.orphanManage.Add(block) return true, nil } diff --git a/protocol/consensus_node_manager.go b/protocol/consensus_node_manager.go new file mode 100644 index 00000000..d116eb0e --- /dev/null +++ b/protocol/consensus_node_manager.go @@ -0,0 +1,205 @@ +package protocol + +import ( + "encoding/hex" + "fmt" + "sort" + "sync" + "time" + + "github.com/vapor/errors" + "github.com/vapor/protocol/state" +) + +const ( + numOfConsensusNode = 21 + roundVoteBlockNums = 1000 + + // product one block per 500 milliseconds + blockTimeInterval = 500 + blockNumEachNode = 3 +) + +var ( + errHasNoChanceProductBlock = errors.New("the node has no chance to product a block in this round of voting") + errNotFoundConsensusNode = errors.New("can not found consensus node") + errVoteResultIsNotfinalized = errors.New("vote result is not finalized") +) + +type consensusNode struct { + pubkey string + voteNum uint64 + order uint64 +} + +type consensusNodeSlice []*consensusNode + +func (c consensusNodeSlice) Len() int { return len(c) } +func (c consensusNodeSlice) Less(i, j int) bool { return c[i].voteNum > c[j].voteNum } +func (c consensusNodeSlice) Swap(i, j int) { c[i], c[j] = c[j], c[i] } + +type consensusNodeManager struct { + consensusNodeMap map[string]*consensusNode + effectiveStartHeight uint64 + store Store + blockIndex *state.BlockIndex + sync.RWMutex +} + +func newConsensusNodeManager(store Store, blockIndex *state.BlockIndex) *consensusNodeManager { + return &consensusNodeManager{ + consensusNodeMap: make(map[string]*consensusNode), + effectiveStartHeight: 1, + store: store, + blockIndex: blockIndex, + } +} + +func (c *consensusNodeManager) getConsensusNode(height uint64, pubkey string) (*consensusNode, error) { + defer c.RUnlock() + c.RLock() + if height >= c.effectiveStartHeight+roundVoteBlockNums { + return nil, errors.New("the vote has not been completed for the specified block height ") + } + + var err error + consensusNodeMap := c.consensusNodeMap + // query history vote result + if height < c.effectiveStartHeight { + consensusNodeMap, err = c.getConsensusNodesByVoteResult(height) + if err != nil { + return nil, err + } + } + + node, exist := consensusNodeMap[pubkey] + if !exist { + return node, errNotFoundConsensusNode + } + return node, nil +} + +func (c *consensusNodeManager) isBlocker(height uint64, blockTimestamp uint64, pubkey string) (bool, error) { + prevVoteRoundLastBlock := c.blockIndex.NodeByHeight(height - 1) + startTimestamp := prevVoteRoundLastBlock.Timestamp + blockTimeInterval + + consensusNodeMap, err := c.getConsensusNodesByVoteResult(height) + if err != nil { + return false, err + } + + blockerNode, exist := consensusNodeMap[pubkey] + if !exist { + return false, nil + } + + begin := getLastBlockTimeInTimeRange(startTimestamp, blockTimestamp, blockerNode.order) + end := begin + blockNumEachNode*blockTimeInterval + return blockTimestamp >= begin && blockTimestamp < end, nil +} + +func (c *consensusNodeManager) nextLeaderTime(pubkey []byte, bestBlockTimestamp, bestBlockHeight uint64) (*time.Time, error) { + defer c.RUnlock() + c.RLock() + + startHeight := c.effectiveStartHeight + prevRoundLastBlock := c.blockIndex.NodeByHeight(startHeight - 1) + startTime := prevRoundLastBlock.Timestamp + blockTimeInterval + endTime := bestBlockTimestamp + (roundVoteBlockNums-bestBlockHeight%roundVoteBlockNums)*blockTimeInterval + + consensusNode, exist := c.consensusNodeMap[hex.EncodeToString(pubkey)] + if !exist { + return nil, fmt.Errorf("pubkey:%s is not consensus node", hex.EncodeToString(pubkey)) + } + + nextLeaderTime, err := nextLeaderTimeHelper(startTime, endTime, uint64(time.Now().UnixNano()/1e6), consensusNode.order) + if err != nil { + return nil, err + } + + return nextLeaderTime, nil +} + +func nextLeaderTimeHelper(startTime, endTime, now, nodeOrder uint64) (*time.Time, error) { + nextLeaderTimestamp := getLastBlockTimeInTimeRange(startTime, now, nodeOrder) + roundBlockTime := uint64(blockNumEachNode * numOfConsensusNode * blockTimeInterval) + + if int64(now-nextLeaderTimestamp) >= blockNumEachNode*blockTimeInterval { + nextLeaderTimestamp += roundBlockTime + if nextLeaderTimestamp >= endTime { + return nil, errHasNoChanceProductBlock + } + } + + nextLeaderTime := time.Unix(int64(nextLeaderTimestamp)/1000, (int64(nextLeaderTimestamp)%1000)*1e6) + return &nextLeaderTime, nil +} + +// updateConsensusNodes used to update consensus node after each round of voting +func (c *consensusNodeManager) updateConsensusNodes(bestBlockHeight uint64) error { + defer c.Unlock() + c.Lock() + + consensusNodeMap, err := c.getConsensusNodesByVoteResult(bestBlockHeight) + if err != nil && err != errVoteResultIsNotfinalized { + return err + } + + if err == errVoteResultIsNotfinalized { + return nil + } + + c.consensusNodeMap = consensusNodeMap + c.effectiveStartHeight = bestBlockHeight / roundVoteBlockNums * roundVoteBlockNums + return nil +} + +func getLastBlockTimeInTimeRange(startTimestamp, endTimestamp, order uint64) uint64 { + // One round of product block time for all consensus nodes + roundBlockTime := uint64(blockNumEachNode * numOfConsensusNode * blockTimeInterval) + // The start time of the last round of product block + lastRoundStartTime := startTimestamp + (endTimestamp-startTimestamp)/roundBlockTime*roundBlockTime + // The time of product block of the consensus in last round + return lastRoundStartTime + order*(blockNumEachNode*blockTimeInterval) +} + +func (c *consensusNodeManager) getConsensusNodesByVoteResult(blockHeight uint64) (map[string]*consensusNode, error) { + defer c.RUnlock() + c.RLock() + if blockHeight >= c.effectiveStartHeight+roundVoteBlockNums { + return nil, errors.New("the given block height is greater than current vote start height") + } + + if blockHeight >= c.effectiveStartHeight { + return c.consensusNodeMap, nil + } + + voteResult, err := c.store.GetVoteResult(blockHeight / roundVoteBlockNums) + if err != nil { + return nil, err + } + + if !voteResult.Finalized { + return nil, errVoteResultIsNotfinalized + } + + var nodes []*consensusNode + for pubkey, voteNum := range voteResult.NumOfVote { + nodes = append(nodes, &consensusNode{ + pubkey: pubkey, + voteNum: voteNum, + }) + } + // In principle, there is no need to sort all voting nodes. + // if there is a performance problem, consider the optimization later. + // TODO not consider the same number of votes + sort.Sort(consensusNodeSlice(nodes)) + + result := make(map[string]*consensusNode) + for i := 0; i < numOfConsensusNode; i++ { + node := nodes[i] + node.order = uint64(i) + result[node.pubkey] = node + } + return result, nil +} diff --git a/protocol/protocol.go b/protocol/protocol.go index 9fb2b3d6..3908c72a 100644 --- a/protocol/protocol.go +++ b/protocol/protocol.go @@ -19,10 +19,12 @@ type Chain struct { orphanManage *OrphanManage txPool *TxPool store Store + bbft *bbft processBlockCh chan *processBlockMsg - cond sync.Cond - bestNode *state.BlockNode + cond sync.Cond + bestNode *state.BlockNode + bestIrreversibleNode *state.BlockNode } // NewChain returns a new Chain using store as the underlying storage. @@ -50,6 +52,7 @@ func NewChain(store Store, txPool *TxPool) (*Chain, error) { c.bestNode = c.index.GetNode(storeStatus.Hash) c.index.SetMainChain(c.bestNode) + c.bbft = newBbft(store, c.index) go c.blockProcesser() return c, nil } @@ -77,7 +80,7 @@ func (c *Chain) initChainStatus() error { if err != nil { return err } - return c.store.SaveChainStatus(node, utxoView) + return c.store.SaveChainStatus(node, node, utxoView, map[uint64]*state.VoteResult{}) } // BestBlockHeight returns the current height of the blockchain. @@ -106,16 +109,21 @@ func (c *Chain) InMainChain(hash bc.Hash) bool { } // This function must be called with mu lock in above level -func (c *Chain) setState(node *state.BlockNode, view *state.UtxoViewpoint) error { - if err := c.store.SaveChainStatus(node, view); err != nil { +func (c *Chain) setState(node *state.BlockNode, irreversibleNode *state.BlockNode, view *state.UtxoViewpoint, voteMap map[uint64]*state.VoteResult) error { + if err := c.store.SaveChainStatus(node, irreversibleNode, view, voteMap); err != nil { return err } c.cond.L.Lock() defer c.cond.L.Unlock() + if err := c.bbft.UpdateConsensusNodes(node.Height); err != nil { + return err + } + c.index.SetMainChain(node) c.bestNode = node + c.bestIrreversibleNode = irreversibleNode log.WithFields(log.Fields{"module": logModule, "height": c.bestNode.Height, "hash": c.bestNode.Hash.String()}).Debug("chain best status has been update") c.cond.Broadcast() diff --git a/protocol/state/blockindex.go b/protocol/state/blockindex.go index 3262d8d8..61b11646 100644 --- a/protocol/state/blockindex.go +++ b/protocol/state/blockindex.go @@ -24,6 +24,7 @@ type BlockNode struct { Version uint64 Height uint64 Timestamp uint64 + BlockWitness *common.BitMap TransactionsMerkleRoot bc.Hash TransactionStatusHash bc.Hash } @@ -42,6 +43,13 @@ func NewBlockNode(bh *types.BlockHeader, parent *BlockNode) (*BlockNode, error) TransactionsMerkleRoot: bh.TransactionsMerkleRoot, TransactionStatusHash: bh.TransactionStatusHash, } + + node.BlockWitness = common.NewBitMap(uint32(len(bh.Witness))) + for i, witness := range bh.Witness { + if len(witness) != 0 { + node.BlockWitness.Set(uint32(i)) + } + } return node, nil } @@ -79,14 +87,16 @@ func (node *BlockNode) CalcPastMedianTime() uint64 { type BlockIndex struct { sync.RWMutex - index map[bc.Hash]*BlockNode - mainChain []*BlockNode + index map[bc.Hash]*BlockNode + heightIndex map[uint64][]*BlockNode + mainChain []*BlockNode } // NewBlockIndex will create a empty BlockIndex func NewBlockIndex() *BlockIndex { return &BlockIndex{ index: make(map[bc.Hash]*BlockNode), + heightIndex: make(map[uint64][]*BlockNode), mainChain: make([]*BlockNode, 0, approxNodesPerDay), } } @@ -95,6 +105,7 @@ func NewBlockIndex() *BlockIndex { func (bi *BlockIndex) AddNode(node *BlockNode) { bi.Lock() bi.index[node.Hash] = node + bi.heightIndex[node.Height] = append(bi.heightIndex[node.Height], node) bi.Unlock() } @@ -145,6 +156,13 @@ func (bi *BlockIndex) NodeByHeight(height uint64) *BlockNode { return bi.nodeByHeight(height) } +// NodesByHeight return all block nodes at the specified height. +func (bi *BlockIndex) NodesByHeight(height uint64) []*BlockNode { + bi.RLock() + defer bi.RUnlock() + return bi.heightIndex[height] +} + // SetMainChain will set the the mainChain array func (bi *BlockIndex) SetMainChain(node *BlockNode) { bi.Lock() diff --git a/protocol/state/blockindex_test.go b/protocol/state/blockindex_test.go index 28e2281a..360c0496 100644 --- a/protocol/state/blockindex_test.go +++ b/protocol/state/blockindex_test.go @@ -121,8 +121,9 @@ func TestSetMainChain(t *testing.T) { // MockBlockIndex will mock a empty BlockIndex func MockBlockIndex() *BlockIndex { return &BlockIndex{ - index: make(map[bc.Hash]*BlockNode), - mainChain: make([]*BlockNode, 0, 2), + index: make(map[bc.Hash]*BlockNode), + heightIndex: make(map[uint64][]*BlockNode), + mainChain: make([]*BlockNode, 0, 2), } } diff --git a/protocol/store.go b/protocol/store.go index c1e2d70b..68544185 100644 --- a/protocol/store.go +++ b/protocol/store.go @@ -1,12 +1,18 @@ package protocol import ( + "errors" + "github.com/vapor/database/storage" "github.com/vapor/protocol/bc" "github.com/vapor/protocol/bc/types" "github.com/vapor/protocol/state" ) +var ( + ErrNotFoundVoteResult = errors.New("can't find the vote result by given sequence") +) + // Store provides storage interface for blockchain data type Store interface { BlockExist(*bc.Hash) bool @@ -16,14 +22,17 @@ type Store interface { GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) + GetVoteResult(uint64) (*state.VoteResult, error) LoadBlockIndex(uint64) (*state.BlockIndex, error) SaveBlock(*types.Block, *bc.TransactionStatus) error - SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint) error + SaveChainStatus(*state.BlockNode, *state.BlockNode, *state.UtxoViewpoint, map[uint64]*state.VoteResult) error } // BlockStoreState represents the core's db status type BlockStoreState struct { - Height uint64 - Hash *bc.Hash + Height uint64 + Hash *bc.Hash + IrreversibleHeight uint64 + IrreversibleHash *bc.Hash } diff --git a/protocol/txpool_test.go b/protocol/txpool_test.go index 05eff7f4..ba1f672c 100644 --- a/protocol/txpool_test.go +++ b/protocol/txpool_test.go @@ -117,9 +117,10 @@ func (s *mockStore) GetStoreStatus() *BlockStoreState func (s *mockStore) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil } func (s *mockStore) GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error { return nil } func (s *mockStore) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil } +func (s *mockStore) GetVoteResult(uint64) (*state.VoteResult, error) { return nil, nil } func (s *mockStore) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil } func (s *mockStore) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil } -func (s *mockStore) SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint) error { return nil } +func (s *mockStore) SaveChainStatus(*state.BlockNode, *state.BlockNode, *state.UtxoViewpoint, map[uint64]*state.VoteResult) error { return nil } func TestAddOrphan(t *testing.T) { cases := []struct { @@ -661,9 +662,10 @@ func (s *mockStore1) GetTransactionsUtxo(utxoView *state.UtxoViewpoint, tx []*bc return nil } func (s *mockStore1) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil } +func (s *mockStore1) GetVoteResult(uint64) (*state.VoteResult, error) { return nil, nil } func (s *mockStore1) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil } func (s *mockStore1) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil } -func (s *mockStore1) SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint) error { return nil } +func (s *mockStore1) SaveChainStatus(*state.BlockNode, *state.BlockNode, *state.UtxoViewpoint, map[uint64]*state.VoteResult) error { return nil } func TestProcessTransaction(t *testing.T) { txPool := &TxPool{ diff --git a/protocol/validation/tx.go b/protocol/validation/tx.go index 9225eb2f..a7488555 100644 --- a/protocol/validation/tx.go +++ b/protocol/validation/tx.go @@ -228,7 +228,7 @@ func checkValid(vs *validationState, e bc.Entry) (err error) { vs2 := *vs vs2.sourcePos = 0 if err = checkValidSrc(&vs2, e.Source); err != nil { - return errors.Wrap(err, "checking output source") + return errors.Wrap(err, "checking vote output source") } case *bc.Retirement: diff --git a/test/utxo_view/utxo_view_test.go b/test/utxo_view/utxo_view_test.go index 017ade8b..77d7f361 100644 --- a/test/utxo_view/utxo_view_test.go +++ b/test/utxo_view/utxo_view_test.go @@ -414,7 +414,7 @@ func TestAttachOrDetachBlocks(t *testing.T) { for k, v := range c.before { utxoViewpoint.Entries[k] = v } - if err := store.SaveChainStatus(node, utxoViewpoint); err != nil { + if err := store.SaveChainStatus(node, node, utxoViewpoint, map[uint64]*state.VoteResult{}); err != nil { t.Error(err) } @@ -436,7 +436,7 @@ func TestAttachOrDetachBlocks(t *testing.T) { t.Error(err) } } - if err := store.SaveChainStatus(node, utxoViewpoint); err != nil { + if err := store.SaveChainStatus(node, node, utxoViewpoint, map[uint64]*state.VoteResult{}); err != nil { t.Error(err) } -- 2.11.0