From: wz Date: Fri, 31 May 2019 05:53:01 +0000 (+0800) Subject: add time limit for votetx (#102) X-Git-Tag: v1.0.5~208^2~89 X-Git-Url: http://git.osdn.net/view?p=bytom%2Fvapor.git;a=commitdiff_plain;h=66c756fddf8697d20f2b8b9fc96bdc7956c86d4c add time limit for votetx (#102) * add time limit for votetx * fix --- diff --git a/consensus/general.go b/consensus/general.go index a03b990e..d556c796 100644 --- a/consensus/general.go +++ b/consensus/general.go @@ -22,6 +22,9 @@ const ( baseSubsidy = uint64(41250000000) InitialBlockSubsidy = uint64(140700041250000000) + //config parameter for vote + VotePendingBlockNumber = uint64(10000) + // config for pow mining BlocksPerRetarget = uint64(2016) TargetSecondsPerBlock = uint64(150) diff --git a/database/storage/utxo_entry.go b/database/storage/utxo_entry.go index b0edbdba..de1c466a 100644 --- a/database/storage/utxo_entry.go +++ b/database/storage/utxo_entry.go @@ -4,6 +4,7 @@ const ( NormalUTXOType uint32 = iota CoinbaseUTXOType CrosschainUTXOType + VoteUTXOType ) // NewUtxoEntry will create a new utxo entry diff --git a/database/store_test.go b/database/store_test.go index e9d7527c..45ff0168 100644 --- a/database/store_test.go +++ b/database/store_test.go @@ -169,6 +169,8 @@ func TestSaveChainStatus(t *testing.T) { bc.Hash{V0: 1, V1: 1, V2: 3, V3: 4}: &storage.UtxoEntry{Type: storage.NormalUTXOType, BlockHeight: 100, Spent: true}, bc.Hash{V0: 1, V1: 1, V2: 3, V3: 5}: &storage.UtxoEntry{Type: storage.CrosschainUTXOType, BlockHeight: 100, Spent: false}, bc.Hash{V0: 1, V1: 1, V2: 3, V3: 6}: &storage.UtxoEntry{Type: storage.CrosschainUTXOType, BlockHeight: 100, Spent: true}, + bc.Hash{V0: 1, V1: 3, V2: 3, V3: 7}: &storage.UtxoEntry{Type: storage.VoteUTXOType, BlockHeight: 100, Spent: false}, + bc.Hash{V0: 1, V1: 3, V2: 3, V3: 7}: &storage.UtxoEntry{Type: storage.VoteUTXOType, BlockHeight: 100, Spent: true}, }, } @@ -188,6 +190,9 @@ func TestSaveChainStatus(t *testing.T) { if (utxo.Type == storage.CrosschainUTXOType) && (!utxo.Spent) { continue } + if (utxo.Type == storage.VoteUTXOType) && (utxo.Spent) { + continue + } gotUtxo, err := store.GetUtxo(&hash) if err != nil { diff --git a/database/utxo_view.go b/database/utxo_view.go index b4bfa450..f05dafda 100644 --- a/database/utxo_view.go +++ b/database/utxo_view.go @@ -77,7 +77,7 @@ func saveUtxoView(batch dbm.Batch, view *state.UtxoViewpoint) error { continue } - if (entry.Type == storage.NormalUTXOType) && (entry.Spent) { + if (entry.Type == storage.NormalUTXOType || entry.Type == storage.VoteUTXOType) && (entry.Spent) { batch.Delete(calcUtxoKey(&key)) continue } diff --git a/database/utxo_view_test.go b/database/utxo_view_test.go index a59f07e4..b9b2663a 100644 --- a/database/utxo_view_test.go +++ b/database/utxo_view_test.go @@ -14,7 +14,10 @@ import ( func TestSaveUtxoView(t *testing.T) { testDB := dbm.NewDB("testdb", "leveldb", "temp") batch := testDB.NewBatch() - defer os.RemoveAll("temp") + defer func() { + testDB.Close() + os.RemoveAll("temp") + }() cases := []struct { hash bc.Hash @@ -51,6 +54,16 @@ func TestSaveUtxoView(t *testing.T) { utxoEntry: storage.NewUtxoEntry(storage.CrosschainUTXOType, 0, false), exist: false, }, + { + hash: bc.Hash{V0: 6}, + utxoEntry: storage.NewUtxoEntry(storage.VoteUTXOType, 0, true), + exist: false, + }, + { + hash: bc.Hash{V0: 7}, + utxoEntry: storage.NewUtxoEntry(storage.VoteUTXOType, 0, false), + exist: true, + }, } view := state.NewUtxoViewpoint() diff --git a/protocol/state/utxo_view.go b/protocol/state/utxo_view.go index c8071444..419ed39d 100644 --- a/protocol/state/utxo_view.go +++ b/protocol/state/utxo_view.go @@ -62,15 +62,26 @@ func (view *UtxoViewpoint) ApplyTransaction(block *bc.Block, tx *bc.Tx, statusFa if !ok { return errors.New("fail to find utxo entry") } - if entry.Type == storage.CrosschainUTXOType { - return errors.New("look up spentOutputID but find utxo from mainchain") - } + if entry.Spent { return errors.New("utxo has been spent") } - if (entry.Type == storage.CoinbaseUTXOType) && ((entry.BlockHeight + consensus.CoinbasePendingBlockNumber) > block.Height) { - return errors.New("coinbase utxo is not ready for use") + + switch entry.Type { + case storage.CrosschainUTXOType: + return errors.New("look up spentOutputID but find utxo from mainchain") + + case storage.CoinbaseUTXOType: + if (entry.BlockHeight + consensus.CoinbasePendingBlockNumber) > block.Height { + return errors.New("coinbase utxo is not ready for use") + } + + case storage.VoteUTXOType: + if (entry.BlockHeight + consensus.VotePendingBlockNumber) > block.Height { + return errors.New("Coin is within the voting lock time") + } } + entry.SpendOutput() } @@ -81,11 +92,14 @@ func (view *UtxoViewpoint) ApplyTransaction(block *bc.Block, tx *bc.Tx, statusFa continue } + utxoType := storage.NormalUTXOType + switch output := entryOutput.(type) { case *bc.IntraChainOutput: assetID = *output.Source.Value.AssetId case *bc.VoteOutput: assetID = *output.Source.Value.AssetId + utxoType = storage.VoteUTXOType default: // due to it's a retirement, utxo doesn't care this output type so skip it continue @@ -95,7 +109,6 @@ func (view *UtxoViewpoint) ApplyTransaction(block *bc.Block, tx *bc.Tx, statusFa continue } - utxoType := storage.NormalUTXOType if block != nil && len(block.Transactions) > 0 && block.Transactions[0].ID == tx.ID { utxoType = storage.CoinbaseUTXOType } @@ -148,11 +161,13 @@ func (view *UtxoViewpoint) DetachTransaction(tx *bc.Tx, statusFail bool) error { return err } + utxoType := storage.NormalUTXOType switch output := entryOutput.(type) { case *bc.IntraChainOutput: assetID = *output.Source.Value.AssetId case *bc.VoteOutput: assetID = *output.Source.Value.AssetId + utxoType = storage.VoteUTXOType default: return errors.Wrapf(bc.ErrEntryType, "entry %x has unexpected type %T", prevout.Bytes(), entryOutput) } @@ -171,7 +186,7 @@ func (view *UtxoViewpoint) DetachTransaction(tx *bc.Tx, statusFail bool) error { } if !ok { - view.Entries[prevout] = storage.NewUtxoEntry(storage.NormalUTXOType, 0, false) + view.Entries[prevout] = storage.NewUtxoEntry(utxoType, 0, false) continue } entry.UnspendOutput() @@ -184,11 +199,13 @@ func (view *UtxoViewpoint) DetachTransaction(tx *bc.Tx, statusFail bool) error { continue } + utxoType := storage.NormalUTXOType switch output := entryOutput.(type) { case *bc.IntraChainOutput: assetID = *output.Source.Value.AssetId case *bc.VoteOutput: assetID = *output.Source.Value.AssetId + utxoType = storage.VoteUTXOType default: // due to it's a retirement, utxo doesn't care this output type so skip it continue @@ -198,7 +215,7 @@ func (view *UtxoViewpoint) DetachTransaction(tx *bc.Tx, statusFail bool) error { continue } - view.Entries[*id] = storage.NewUtxoEntry(storage.NormalUTXOType, 0, true) + view.Entries[*id] = storage.NewUtxoEntry(utxoType, 0, true) } return nil } diff --git a/protocol/state/utxo_view_test.go b/protocol/state/utxo_view_test.go index cf4935f7..e2697fab 100644 --- a/protocol/state/utxo_view_test.go +++ b/protocol/state/utxo_view_test.go @@ -19,6 +19,16 @@ var defaultEntry = map[bc.Hash]bc.Entry{ }, } +var voteEntry = map[bc.Hash]bc.Entry{ + bc.Hash{V0: 0}: &bc.VoteOutput{ + Source: &bc.ValueSource{ + Value: &bc.AssetAmount{ + AssetId: &bc.AssetID{V0: 0}, + }, + }, + }, +} + var gasOnlyTxEntry = map[bc.Hash]bc.Entry{ bc.Hash{V1: 0}: &bc.IntraChainOutput{ Source: &bc.ValueSource{ @@ -283,6 +293,65 @@ func TestApplyBlock(t *testing.T) { gasOnlyTx: true, err: false, }, + { + block: &bc.Block{ + BlockHeader: &bc.BlockHeader{ + TransactionStatus: bc.NewTransactionStatus(), + }, + Transactions: []*bc.Tx{ + &bc.Tx{ + TxHeader: &bc.TxHeader{ + ResultIds: []*bc.Hash{}, + }, + SpentOutputIDs: []bc.Hash{ + bc.Hash{V0: 0}, + }, + Entries: voteEntry, + }, + }, + }, + inputView: &UtxoViewpoint{ + Entries: map[bc.Hash]*storage.UtxoEntry{ + bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.VoteUTXOType, 0, false), + }, + }, + fetchView: &UtxoViewpoint{ + Entries: map[bc.Hash]*storage.UtxoEntry{ + bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.VoteUTXOType, 0, true), + }, + }, + err: true, + }, + { + block: &bc.Block{ + BlockHeader: &bc.BlockHeader{ + Height: 10001, + TransactionStatus: bc.NewTransactionStatus(), + }, + Transactions: []*bc.Tx{ + &bc.Tx{ + TxHeader: &bc.TxHeader{ + ResultIds: []*bc.Hash{}, + }, + SpentOutputIDs: []bc.Hash{ + bc.Hash{V0: 0}, + }, + Entries: voteEntry, + }, + }, + }, + inputView: &UtxoViewpoint{ + Entries: map[bc.Hash]*storage.UtxoEntry{ + bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.VoteUTXOType, 1, false), + }, + }, + fetchView: &UtxoViewpoint{ + Entries: map[bc.Hash]*storage.UtxoEntry{ + bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.VoteUTXOType, 1, true), + }, + }, + err: false, + }, } for i, c := range cases { @@ -470,6 +539,31 @@ func TestDetachBlock(t *testing.T) { gasOnlyTx: true, err: false, }, + { + block: &bc.Block{ + BlockHeader: &bc.BlockHeader{ + TransactionStatus: bc.NewTransactionStatus(), + }, + Transactions: []*bc.Tx{ + &bc.Tx{ + TxHeader: &bc.TxHeader{ + ResultIds: []*bc.Hash{}, + }, + SpentOutputIDs: []bc.Hash{ + bc.Hash{V0: 0}, + }, + Entries: voteEntry, + }, + }, + }, + inputView: NewUtxoViewpoint(), + fetchView: &UtxoViewpoint{ + Entries: map[bc.Hash]*storage.UtxoEntry{ + bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.VoteUTXOType, 0, false), + }, + }, + err: false, + }, } for i, c := range cases {