OSDN Git Service

add timerange to txbuilder (#461)
authorPaladz <yzhu101@uottawa.ca>
Thu, 22 Mar 2018 09:19:22 +0000 (17:19 +0800)
committerGitHub <noreply@github.com>
Thu, 22 Mar 2018 09:19:22 +0000 (17:19 +0800)
* add timerange to txbuilder

* timerange support block height

* add notes to timeRangeGash

blockchain/request.go
blockchain/transact.go
blockchain/txbuilder/builder.go
blockchain/txbuilder/txbuilder.go
blockchain/txbuilder/txbuilder_test.go
protocol/tx.go
protocol/validation/validation.go
protocol/validation/validation_test.go

index 25ab297..12356bd 100644 (file)
@@ -16,9 +16,10 @@ var (
 
 // BuildRequest is main struct when building transactions
 type BuildRequest struct {
-       Tx      *types.TxData            `json:"base_transaction"`
-       Actions []map[string]interface{} `json:"actions"`
-       TTL     json.Duration            `json:"ttl"`
+       Tx        *types.TxData            `json:"base_transaction"`
+       Actions   []map[string]interface{} `json:"actions"`
+       TTL       json.Duration            `json:"ttl"`
+       TimeRange uint64                   `json:"time_range"`
 }
 
 func (bcr *BlockchainReactor) filterAliases(ctx context.Context, br *BuildRequest) error {
index d2258a2..43b3174 100644 (file)
@@ -105,7 +105,7 @@ func (bcr *BlockchainReactor) buildSingle(ctx context.Context, req *BuildRequest
        }
        maxTime := time.Now().Add(ttl)
 
-       tpl, err := txbuilder.Build(ctx, req.Tx, actions, maxTime)
+       tpl, err := txbuilder.Build(ctx, req.Tx, actions, maxTime, req.TimeRange)
        if errors.Root(err) == txbuilder.ErrAction {
                // append each of the inner errors contained in the data.
                var Errs string
index 62b7091..3e40021 100755 (executable)
@@ -21,6 +21,7 @@ type TemplateBuilder struct {
        signingInstructions []*SigningInstruction
        minTime             time.Time
        maxTime             time.Time
+       timeRange           uint64
        referenceData       []byte
        rollbacks           []func()
        callbacks           []func() error
@@ -106,6 +107,10 @@ func (b *TemplateBuilder) Build() (*Template, *types.TxData, error) {
                tpl.Local = true
        }
 
+       if b.timeRange != 0 {
+               tx.TimeRange = b.timeRange
+       }
+
        // Add all the built outputs.
        tx.Outputs = append(tx.Outputs, b.outputs...)
 
index 0c6e979..e8c791c 100755 (executable)
@@ -38,10 +38,11 @@ var (
 // Build partners then satisfy and consume inputs and destinations.
 // The final party must ensure that the transaction is
 // balanced before calling finalize.
-func Build(ctx context.Context, tx *types.TxData, actions []Action, maxTime time.Time) (*Template, error) {
+func Build(ctx context.Context, tx *types.TxData, actions []Action, maxTime time.Time, timeRange uint64) (*Template, error) {
        builder := TemplateBuilder{
-               base:    tx,
-               maxTime: maxTime,
+               base:      tx,
+               maxTime:   maxTime,
+               timeRange: timeRange,
        }
 
        // Build all of the actions, updating the builder.
index e5a904d..892492a 100755 (executable)
@@ -53,7 +53,7 @@ func TestBuild(t *testing.T) {
                testAction(bc.AssetAmount{AssetId: &assetID1, Amount: 5}),
        }
        expiryTime := time.Now().Add(time.Minute)
-       got, err := Build(ctx, nil, actions, expiryTime)
+       got, err := Build(ctx, nil, actions, expiryTime, 0)
        if err != nil {
                testutil.FatalErr(t, err)
        }
index f4fdb1a..75e1c1a 100644 (file)
@@ -35,7 +35,7 @@ func (c *Chain) ValidateTx(tx *types.Tx) error {
        gasOnlyTx := false
        gasStatus, err := validation.ValidateTx(newTx, block)
        if err != nil {
-               if !gasStatus.GasVaild {
+               if gasStatus == nil || !gasStatus.GasVaild {
                        c.txPool.AddErrCache(&newTx.ID, err)
                        return err
                }
index 8f25baf..6e3bd88 100644 (file)
@@ -13,7 +13,11 @@ import (
        "github.com/bytom/protocol/vm"
 )
 
-const muxGasCost = int64(10)
+const (
+       muxGasCost = int64(10)
+       // timeRangeGash is the block height we will reach after 100 years
+       timeRangeGash = uint64(21024000)
+)
 
 // GasState record the gas usage status
 type GasState struct {
@@ -568,12 +572,6 @@ func ValidateBlock(b, prev *bc.Block, seed *bc.Hash) error {
        coinbaseValue := consensus.BlockSubsidy(b.BlockHeader.Height)
        gasUsed := uint64(0)
        for i, tx := range b.Transactions {
-               if b.Version == 1 && tx.Version != 1 {
-                       return errors.WithDetailf(errTxVersion, "block version %d, transaction version %d", b.Version, tx.Version)
-               }
-               if tx.TimeRange > b.Timestamp {
-                       return errors.New("invalid transaction time range")
-               }
                gasStatus, err := ValidateTx(tx, b)
                gasOnlyTx := false
                if err != nil {
@@ -690,9 +688,20 @@ func validateStandardTx(tx *bc.Tx) error {
 
 // ValidateTx validates a transaction.
 func ValidateTx(tx *bc.Tx, block *bc.Block) (*GasState, error) {
+       if block.Version == 1 && tx.Version != 1 {
+               return nil, errors.WithDetailf(errTxVersion, "block version %d, transaction version %d", block.Version, tx.Version)
+       }
+
+       if tx.TimeRange > timeRangeGash && tx.TimeRange < block.Timestamp {
+               return nil, errors.New("transaction max timestamp is lower than block's")
+       } else if tx.TimeRange != 0 && tx.TimeRange < block.Height {
+               return nil, errors.New("transaction max block height is lower than block's")
+       }
+
        if tx.TxHeader.SerializedSize > consensus.MaxTxSize || tx.TxHeader.SerializedSize == 0 {
                return nil, errWrongTransactionSize
        }
+
        if len(tx.ResultIds) == 0 {
                return nil, errors.New("tx didn't have any output")
        }
index 6286d70..c87098e 100644 (file)
@@ -485,6 +485,59 @@ func TestCoinbase(t *testing.T) {
        }
 }
 
+func TestTimeRange(t *testing.T) {
+       cases := []struct {
+               timeRange uint64
+               err       bool
+       }{
+               {
+                       timeRange: 0,
+                       err:       false,
+               },
+               {
+                       timeRange: 334,
+                       err:       false,
+               },
+               {
+                       timeRange: 332,
+                       err:       true,
+               },
+               {
+                       timeRange: 1521625824,
+                       err:       false,
+               },
+               {
+                       timeRange: 1421625824,
+                       err:       true,
+               },
+       }
+
+       block := &bc.Block{
+               BlockHeader: &bc.BlockHeader{
+                       Height:    333,
+                       Timestamp: 1521625823,
+               },
+       }
+
+       tx := types.MapTx(&types.TxData{
+               SerializedSize: 1,
+               TimeRange:      0,
+               Inputs: []*types.TxInput{
+                       mockGasTxInput(),
+               },
+               Outputs: []*types.TxOutput{
+                       types.NewTxOutput(*consensus.BTMAssetID, 1, []byte{0x6a}),
+               },
+       })
+
+       for i, c := range cases {
+               tx.TimeRange = c.timeRange
+               if _, err := ValidateTx(tx, block); (err != nil) != c.err {
+                       t.Errorf("#%d got error %s, want %s", i, !c.err, c.err)
+               }
+       }
+}
+
 func TestBlockHeaderValid(t *testing.T) {
        base := bc.NewBlockHeader(1, 1, &bc.Hash{}, 1, &bc.Hash{}, &bc.Hash{}, 0, 0)
        baseBytes, _ := proto.Marshal(base)