OSDN Git Service

Txpool upgrade (#327)
authorPaladz <yzhu101@uottawa.ca>
Mon, 29 Jan 2018 02:02:00 +0000 (10:02 +0800)
committerGitHub <noreply@github.com>
Mon, 29 Jan 2018 02:02:00 +0000 (10:02 +0800)
* change the block time from ms to second

* update block header time from ms to scond

* limit block max time

* txpool add uncommit utxo

* txpool remove tx will clean the utxo map

* tx add max time

* update for code review

* add log info

26 files changed:
config/genesis.go
consensus/difficulty/difficulty.go
consensus/difficulty/difficulty_test.go
consensus/general.go
mining/mining.go
mining/sort.go [new file with mode: 0644]
protocol/bc/bc.pb.go
protocol/bc/bc.proto
protocol/bc/blockheader.go
protocol/bc/entry_test.go
protocol/bc/legacy/block_header.go
protocol/bc/legacy/block_test.go
protocol/bc/legacy/fuzz_test.go
protocol/bc/legacy/map.go
protocol/bc/legacy/transaction.go
protocol/bc/legacy/transaction_test.go
protocol/bc/legacy/tx_test.go
protocol/bc/merkle_test.go
protocol/bc/time.go [deleted file]
protocol/bc/txheader.go
protocol/mempool.go
protocol/mempool_test.go
protocol/protocol.go
protocol/tx.go
protocol/validation/block_test.go
protocol/validation/validation.go

index 3554d2f..d9b60e0 100644 (file)
@@ -49,11 +49,11 @@ func GenerateGenesisBlock() *legacy.Block {
 
        block := &legacy.Block{
                BlockHeader: legacy.BlockHeader{
-                       Version:     1,
-                       Height:      0,
-                       Nonce:       1656075,
-                       Seed:        bc.NewHash(seed),
-                       TimestampMS: 1511318565142,
+                       Version:   1,
+                       Height:    0,
+                       Nonce:     4216077,
+                       Seed:      bc.NewHash(seed),
+                       Timestamp: 1516788453,
                        BlockCommitment: legacy.BlockCommitment{
                                TransactionsMerkleRoot: merkleRoot,
                        },
index c82f0a9..ef84875 100755 (executable)
@@ -96,7 +96,7 @@ func CalcNextRequiredDifficulty(lastBH, compareBH *legacy.BlockHeader) uint64 {
        }
 
        targetTimeSpan := int64(consensus.BlocksPerRetarget * consensus.TargetSecondsPerBlock)
-       actualTimeSpan := int64(lastBH.Time().Sub(compareBH.Time()).Seconds())
+       actualTimeSpan := int64(lastBH.Timestamp - compareBH.Timestamp)
 
        oldTarget := CompactToBig(lastBH.Bits)
        newTarget := new(big.Int).Mul(oldTarget, big.NewInt(actualTimeSpan))
index 46d3a2a..81079c7 100644 (file)
@@ -9,7 +9,7 @@ import (
 )
 
 func TestCalcNextRequiredDifficulty(t *testing.T) {
-       targetTimeSpan := uint64(consensus.BlocksPerRetarget * consensus.TargetSecondsPerBlock * 1000)
+       targetTimeSpan := uint64(consensus.BlocksPerRetarget * consensus.TargetSecondsPerBlock)
        cases := []struct {
                lastBH    *legacy.BlockHeader
                compareBH *legacy.BlockHeader
@@ -18,19 +18,19 @@ func TestCalcNextRequiredDifficulty(t *testing.T) {
                //{nil, nil, powMinBits},
                //{&legacy.BlockHeader{Height: BlocksPerRetarget, Bits: 87654321}, nil, 87654321},
                {
-                       &legacy.BlockHeader{Height: consensus.BlocksPerRetarget, TimestampMS: targetTimeSpan, Bits: BigToCompact(big.NewInt(1000))},
-                       &legacy.BlockHeader{Height: 0, TimestampMS: 0},
+                       &legacy.BlockHeader{Height: consensus.BlocksPerRetarget, Timestamp: targetTimeSpan, Bits: BigToCompact(big.NewInt(1000))},
+                       &legacy.BlockHeader{Height: 0, Timestamp: 0},
                        BigToCompact(big.NewInt(1000)),
                },
                {
-                       &legacy.BlockHeader{Height: consensus.BlocksPerRetarget, TimestampMS: targetTimeSpan * 2, Bits: BigToCompact(big.NewInt(1000))},
-                       &legacy.BlockHeader{Height: 0, TimestampMS: 0},
+                       &legacy.BlockHeader{Height: consensus.BlocksPerRetarget, Timestamp: targetTimeSpan * 2, Bits: BigToCompact(big.NewInt(1000))},
+                       &legacy.BlockHeader{Height: 0, Timestamp: 0},
                        BigToCompact(big.NewInt(2000)),
                },
                {
                        &legacy.BlockHeader{Height: consensus.
-                               BlocksPerRetarget, TimestampMS: targetTimeSpan / 2, Bits: BigToCompact(big.NewInt(1000))},
-                       &legacy.BlockHeader{Height: 0, TimestampMS: 0},
+                               BlocksPerRetarget, Timestamp: targetTimeSpan / 2, Bits: BigToCompact(big.NewInt(1000))},
+                       &legacy.BlockHeader{Height: 0, Timestamp: 0},
                        BigToCompact(big.NewInt(500)),
                },
        }
index b243171..73d8f4b 100644 (file)
@@ -23,6 +23,9 @@ const (
        BlocksPerRetarget     = uint64(1024)
        TargetSecondsPerBlock = uint64(60)
 
+       // MaxTimeOffsetSeconds is the maximum number of seconds a block time is allowed to be ahead of the current time
+       MaxTimeOffsetSeconds = uint64(60 * 60)
+
        PayToWitnessPubKeyHashDataSize = 20
        PayToWitnessScriptHashDataSize = 32
 
index 0194218..65eef7b 100644 (file)
@@ -5,6 +5,7 @@
 package mining
 
 import (
+       "sort"
        "time"
 
        log "github.com/sirupsen/logrus"
@@ -82,7 +83,7 @@ func NewBlockTemplate(c *protocol.Chain, txPool *protocol.TxPool, accountManager
                        Height:            nextBlockHeight,
                        PreviousBlockHash: preBlock.Hash(),
                        Seed:              *nextBlockSeed,
-                       TimestampMS:       bc.Millis(time.Now()),
+                       Timestamp:         uint64(time.Now().Unix()),
                        TransactionStatus: *bc.NewTransactionStatus(),
                        BlockCommitment:   legacy.BlockCommitment{},
                        Bits:              difficulty.CalcNextRequiredDifficulty(&preBlock.BlockHeader, compareDiffBH),
@@ -91,7 +92,9 @@ func NewBlockTemplate(c *protocol.Chain, txPool *protocol.TxPool, accountManager
        }
        bcBlock := &bc.Block{BlockHeader: &bc.BlockHeader{Height: nextBlockHeight}}
 
-       for _, txDesc := range txPool.GetTransactions() {
+       txs := txPool.GetTransactions()
+       sort.Sort(ByTime(txs))
+       for _, txDesc := range txs {
                tx := txDesc.Tx.Tx
                gasOnlyTx := false
                if blockWeight+txDesc.Weight > consensus.MaxBlockSzie-consensus.MaxTxSize {
diff --git a/mining/sort.go b/mining/sort.go
new file mode 100644 (file)
index 0000000..90065b5
--- /dev/null
@@ -0,0 +1,9 @@
+package mining
+
+import "github.com/bytom/protocol"
+
+type ByTime []*protocol.TxDesc
+
+func (a ByTime) Len() int           { return len(a) }
+func (a ByTime) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
+func (a ByTime) Less(i, j int) bool { return a[i].Added.Unix() < a[j].Added.Unix() }
index 376a021..100517f 100644 (file)
@@ -278,7 +278,7 @@ type BlockHeader struct {
        Height            uint64             `protobuf:"varint,3,opt,name=height" json:"height,omitempty"`
        PreviousBlockId   *Hash              `protobuf:"bytes,4,opt,name=previous_block_id,json=previousBlockId" json:"previous_block_id,omitempty"`
        Seed              *Hash              `protobuf:"bytes,5,opt,name=seed" json:"seed,omitempty"`
-       TimestampMs       uint64             `protobuf:"varint,6,opt,name=timestamp_ms,json=timestampMs" json:"timestamp_ms,omitempty"`
+       Timestamp         uint64             `protobuf:"varint,6,opt,name=timestamp" json:"timestamp,omitempty"`
        TransactionsRoot  *Hash              `protobuf:"bytes,7,opt,name=transactions_root,json=transactionsRoot" json:"transactions_root,omitempty"`
        AssetsRoot        *Hash              `protobuf:"bytes,8,opt,name=assets_root,json=assetsRoot" json:"assets_root,omitempty"`
        TransactionStatus *TransactionStatus `protobuf:"bytes,9,opt,name=transaction_status,json=transactionStatus" json:"transaction_status,omitempty"`
@@ -326,9 +326,9 @@ func (m *BlockHeader) GetSeed() *Hash {
        return nil
 }
 
-func (m *BlockHeader) GetTimestampMs() uint64 {
+func (m *BlockHeader) GetTimestamp() uint64 {
        if m != nil {
-               return m.TimestampMs
+               return m.Timestamp
        }
        return 0
 }
@@ -371,9 +371,10 @@ func (m *BlockHeader) GetBits() uint64 {
 type TxHeader struct {
        Version        uint64  `protobuf:"varint,1,opt,name=version" json:"version,omitempty"`
        SerializedSize uint64  `protobuf:"varint,2,opt,name=serialized_size,json=serializedSize" json:"serialized_size,omitempty"`
-       ResultIds      []*Hash `protobuf:"bytes,3,rep,name=result_ids,json=resultIds" json:"result_ids,omitempty"`
-       Data           *Hash   `protobuf:"bytes,4,opt,name=data" json:"data,omitempty"`
-       ExtHash        *Hash   `protobuf:"bytes,5,opt,name=ext_hash,json=extHash" json:"ext_hash,omitempty"`
+       TimeRange      uint64  `protobuf:"varint,3,opt,name=time_range,json=timeRange" json:"time_range,omitempty"`
+       ResultIds      []*Hash `protobuf:"bytes,4,rep,name=result_ids,json=resultIds" json:"result_ids,omitempty"`
+       Data           *Hash   `protobuf:"bytes,5,opt,name=data" json:"data,omitempty"`
+       ExtHash        *Hash   `protobuf:"bytes,6,opt,name=ext_hash,json=extHash" json:"ext_hash,omitempty"`
 }
 
 func (m *TxHeader) Reset()                    { *m = TxHeader{} }
@@ -395,6 +396,13 @@ func (m *TxHeader) GetSerializedSize() uint64 {
        return 0
 }
 
+func (m *TxHeader) GetTimeRange() uint64 {
+       if m != nil {
+               return m.TimeRange
+       }
+       return 0
+}
+
 func (m *TxHeader) GetResultIds() []*Hash {
        if m != nil {
                return m.ResultIds
@@ -799,67 +807,68 @@ func init() {
 func init() { proto.RegisterFile("bc.proto", fileDescriptor0) }
 
 var fileDescriptor0 = []byte{
-       // 983 bytes of a gzipped FileDescriptorProto
-       0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xdd, 0x6e, 0xe3, 0x44,
-       0x14, 0x96, 0x63, 0x27, 0x76, 0x4e, 0x4a, 0xd3, 0x4e, 0xcb, 0xca, 0x5a, 0x15, 0xa9, 0x18, 0x95,
-       0xee, 0x6a, 0xa5, 0xaa, 0x9b, 0x2e, 0x88, 0x0b, 0x6e, 0x0a, 0x05, 0x36, 0x17, 0x05, 0xe4, 0xae,
-       0xf6, 0xd6, 0x9a, 0xd8, 0xb3, 0xcd, 0x88, 0xc4, 0x13, 0x66, 0xc6, 0xa1, 0xf4, 0x31, 0xb8, 0xe5,
-       0x29, 0xe0, 0x0e, 0xae, 0xf7, 0x89, 0x78, 0x02, 0xe4, 0xe3, 0xb1, 0xe3, 0xfc, 0xed, 0x26, 0xda,
-       0xdd, 0x3b, 0x9f, 0x9f, 0x39, 0x7f, 0xdf, 0xf9, 0x3c, 0x03, 0xde, 0x20, 0x3e, 0x9b, 0x48, 0xa1,
-       0x05, 0x69, 0x0c, 0xe2, 0xe0, 0x7b, 0x70, 0x9e, 0x53, 0x35, 0x24, 0xbb, 0xd0, 0x98, 0x9e, 0xfb,
-       0xd6, 0xb1, 0xf5, 0xa8, 0x15, 0x36, 0xa6, 0xe7, 0x28, 0x3f, 0xf5, 0x1b, 0x46, 0x7e, 0x8a, 0x72,
-       0xcf, 0xb7, 0x8d, 0xdc, 0x43, 0xf9, 0xc2, 0x77, 0x8c, 0x7c, 0x11, 0x7c, 0x0d, 0xee, 0xcf, 0x52,
-       0xdc, 0x4a, 0x3a, 0x26, 0x9f, 0x00, 0x4c, 0xc7, 0xd1, 0x94, 0x49, 0xc5, 0x45, 0x8a, 0x21, 0x9d,
-       0xb0, 0x3d, 0x1d, 0xbf, 0x2c, 0x14, 0x84, 0x80, 0x13, 0x8b, 0x84, 0x61, 0xec, 0x9d, 0x10, 0xbf,
-       0x83, 0x3e, 0xb8, 0x97, 0x4a, 0x31, 0xdd, 0xbf, 0x7a, 0xe7, 0x42, 0xae, 0xa1, 0x83, 0xa1, 0x2e,
-       0xc7, 0x22, 0x4b, 0x35, 0xf9, 0x1c, 0x3c, 0x9a, 0x8b, 0x11, 0x4f, 0x30, 0x68, 0xa7, 0xd7, 0x39,
-       0x1b, 0xc4, 0x67, 0x26, 0x5b, 0xe8, 0xa2, 0xb1, 0x9f, 0x90, 0x07, 0xd0, 0xa2, 0x78, 0x02, 0x53,
-       0x39, 0xa1, 0x91, 0x82, 0x3f, 0x2d, 0xe8, 0xa2, 0xf3, 0x15, 0x7b, 0xc5, 0x53, 0xae, 0xf3, 0x0e,
-       0x7a, 0xb0, 0x87, 0x9f, 0x74, 0x14, 0x0d, 0x46, 0x22, 0xfe, 0x65, 0x16, 0xdb, 0xcb, 0x63, 0xe7,
-       0xf3, 0x0c, 0x77, 0x8d, 0xc7, 0x37, 0xb9, 0x43, 0x3f, 0x21, 0x5f, 0xc2, 0x1e, 0x57, 0x2a, 0xa3,
-       0x69, 0xcc, 0xa2, 0x49, 0x31, 0x28, 0xcc, 0x64, 0xea, 0x31, 0xb3, 0x0b, 0xbb, 0xa5, 0x53, 0x39,
-       0xcc, 0x23, 0x70, 0x12, 0xaa, 0x29, 0x36, 0x5c, 0x8f, 0x8f, 0xda, 0x60, 0x04, 0x9d, 0x97, 0x74,
-       0x94, 0xb1, 0x1b, 0x91, 0xc9, 0x98, 0x91, 0x87, 0x60, 0x4b, 0xf6, 0x6a, 0xa9, 0x96, 0x5c, 0x49,
-       0x4e, 0xa0, 0x39, 0xcd, 0x5d, 0x4d, 0xd6, 0x6e, 0x35, 0x85, 0x62, 0x50, 0x61, 0x61, 0x25, 0x0f,
-       0xc1, 0x9b, 0x08, 0x85, 0x7d, 0x62, 0x4e, 0x27, 0xac, 0xe4, 0xe0, 0x57, 0xd8, 0xc3, 0x6c, 0x57,
-       0x4c, 0x69, 0x9e, 0x52, 0x9c, 0xc5, 0x07, 0x4e, 0xf9, 0x97, 0x0d, 0x1d, 0x1c, 0xe1, 0x73, 0x46,
-       0x13, 0x26, 0x89, 0x0f, 0xee, 0xfc, 0x62, 0x95, 0x22, 0x39, 0x85, 0xae, 0x62, 0x92, 0xd3, 0x11,
-       0xbf, 0x67, 0x49, 0xa4, 0xf8, 0x3d, 0x33, 0x48, 0xee, 0xce, 0xd4, 0x37, 0xfc, 0x9e, 0xe5, 0x48,
-       0x0f, 0x19, 0xbf, 0x1d, 0x6a, 0x93, 0xcc, 0x48, 0xe4, 0x19, 0xec, 0x4f, 0x24, 0x9b, 0x72, 0x91,
-       0xa9, 0x19, 0xac, 0xce, 0x42, 0x5f, 0xdd, 0xd2, 0xa5, 0xc4, 0xf5, 0x08, 0x1c, 0xc5, 0x58, 0xe2,
-       0x37, 0x17, 0xf1, 0xc9, 0xb5, 0xe4, 0x53, 0xd8, 0xd1, 0x7c, 0xcc, 0x94, 0xa6, 0xe3, 0x49, 0x34,
-       0x56, 0x7e, 0x0b, 0x33, 0x76, 0x2a, 0xdd, 0xb5, 0x22, 0x5f, 0xc0, 0xbe, 0x96, 0x34, 0x55, 0x34,
-       0xce, 0x1b, 0x56, 0x91, 0x14, 0x42, 0xfb, 0xee, 0x42, 0xb4, 0xbd, 0xba, 0x4b, 0x28, 0x84, 0x26,
-       0x8f, 0xa1, 0x83, 0xab, 0x6b, 0x0e, 0x78, 0x0b, 0x07, 0xa0, 0x30, 0xa2, 0xeb, 0x15, 0x90, 0xda,
-       0xf1, 0x48, 0x69, 0xaa, 0x33, 0xe5, 0xb7, 0xf1, 0xc4, 0xc7, 0xf9, 0x89, 0x17, 0x33, 0xeb, 0x0d,
-       0x1a, 0xc3, 0x7a, 0x49, 0x85, 0x8a, 0x1c, 0x42, 0x33, 0x15, 0x69, 0xcc, 0x7c, 0xc0, 0x1e, 0x0a,
-       0x21, 0x27, 0xf3, 0x80, 0x6b, 0xe5, 0x77, 0x50, 0x89, 0xdf, 0xc1, 0x3f, 0x16, 0x78, 0x2f, 0xee,
-       0xde, 0x1f, 0x60, 0xa7, 0x00, 0x92, 0xa9, 0x6c, 0x94, 0x73, 0x58, 0xf9, 0xf6, 0xb1, 0x3d, 0xd7,
-       0x69, 0xbb, 0xb0, 0xf5, 0x13, 0x55, 0x71, 0xc5, 0x59, 0xc5, 0x15, 0xf2, 0x19, 0x78, 0xec, 0x4e,
-       0x47, 0x43, 0xaa, 0x86, 0x4b, 0x68, 0xb9, 0xec, 0x4e, 0xe7, 0x1f, 0xc1, 0x13, 0xd8, 0x5f, 0x9a,
-       0x46, 0xbe, 0x31, 0x03, 0xae, 0xc7, 0x74, 0x82, 0x2d, 0xec, 0x84, 0x46, 0x0a, 0xfe, 0xb3, 0xc0,
-       0xbe, 0xce, 0xee, 0xc8, 0x63, 0x70, 0x15, 0x12, 0x50, 0xf9, 0x16, 0x56, 0x87, 0x9b, 0x5e, 0x23,
-       0x66, 0x58, 0xda, 0xc9, 0x09, 0xb8, 0x6f, 0x60, 0x7f, 0x69, 0x9b, 0xab, 0xd5, 0x5e, 0x53, 0x2b,
-       0xf9, 0x01, 0x0e, 0x7f, 0xe3, 0x3a, 0x65, 0x4a, 0x45, 0xc9, 0x8c, 0x91, 0xca, 0x77, 0xb0, 0x86,
-       0xc3, 0xaa, 0x86, 0x1a, 0x5d, 0xc3, 0x03, 0x73, 0xa2, 0xa6, 0x53, 0xe4, 0x09, 0xec, 0x97, 0x81,
-       0xa8, 0xbc, 0xcd, 0xc6, 0x2c, 0xd5, 0xca, 0x6f, 0x1e, 0xdb, 0x8f, 0x76, 0xc2, 0x3d, 0x63, 0xb8,
-       0x2c, 0xf5, 0xc1, 0xbf, 0x16, 0x34, 0x7f, 0x44, 0xec, 0x6b, 0xbd, 0x58, 0x1b, 0xf6, 0xd2, 0x58,
-       0xd7, 0xcb, 0xca, 0x12, 0xec, 0xd5, 0x25, 0x90, 0xaf, 0xe0, 0xa0, 0x72, 0x4e, 0xe3, 0xa1, 0x90,
-       0x2c, 0x59, 0xc5, 0xd5, 0x32, 0xe2, 0xa5, 0xf1, 0xe9, 0x27, 0x81, 0x00, 0xef, 0x5b, 0xc1, 0xd3,
-       0x01, 0x55, 0x8c, 0x7c, 0x37, 0x8b, 0x52, 0x1b, 0x9f, 0x69, 0x65, 0xf5, 0xf4, 0xc8, 0xf2, 0xf4,
-       0xc8, 0x11, 0xb4, 0xa9, 0x1c, 0x70, 0x2d, 0xa9, 0xfc, 0xdd, 0xdc, 0x69, 0x33, 0x45, 0xf0, 0xda,
-       0x82, 0xd6, 0x4f, 0x99, 0x9e, 0x64, 0x9a, 0x9c, 0x42, 0xab, 0xd8, 0x02, 0x93, 0x62, 0x69, 0x49,
-       0x8c, 0x99, 0x3c, 0x83, 0x6e, 0x2c, 0x52, 0x2d, 0xc5, 0xe8, 0x4d, 0x37, 0xc5, 0xae, 0xf1, 0xd9,
-       0xe8, 0xa2, 0x98, 0x03, 0xc1, 0x59, 0x07, 0x82, 0x0f, 0xae, 0x90, 0x09, 0x4f, 0xe9, 0x08, 0x09,
-       0xe2, 0x84, 0xa5, 0x18, 0xfc, 0x61, 0x01, 0x84, 0x4c, 0x73, 0xc9, 0x72, 0x04, 0x36, 0x6f, 0xa5,
-       0x2c, 0xaa, 0xf1, 0xd6, 0xa2, 0xec, 0x0d, 0x8a, 0x72, 0xe6, 0x8b, 0xfa, 0xdb, 0x06, 0xaf, 0x6f,
-       0xae, 0x4b, 0x72, 0x02, 0xed, 0x62, 0x17, 0x56, 0x5d, 0xc6, 0x5e, 0x61, 0xea, 0x27, 0x9b, 0x5e,
-       0x49, 0xef, 0x61, 0x98, 0x6b, 0xd6, 0xab, 0xb9, 0xe5, 0x7a, 0x5d, 0x83, 0x5f, 0xed, 0x3a, 0xbe,
-       0x63, 0x92, 0xea, 0x1d, 0x82, 0xb7, 0x49, 0xa7, 0x77, 0x50, 0xf5, 0x30, 0x7b, 0xa2, 0x84, 0x0f,
-       0xca, 0xdd, 0x5f, 0x78, 0xba, 0xac, 0xe4, 0x99, 0xbb, 0x1d, 0xcf, 0xbc, 0xb7, 0xf2, 0xac, 0x0e,
-       0x5a, 0x7b, 0x1e, 0xb4, 0xd7, 0x0d, 0x68, 0xde, 0x4c, 0x58, 0x9a, 0x90, 0x73, 0xe8, 0xaa, 0x09,
-       0x4b, 0x75, 0x24, 0x90, 0x1f, 0xab, 0x70, 0xfb, 0x08, 0x1d, 0x0a, 0xfe, 0x14, 0x77, 0xed, 0xbb,
-       0x6e, 0xd3, 0x1a, 0x54, 0x9c, 0x2d, 0x51, 0xd9, 0xe6, 0x8f, 0xb9, 0x6e, 0x8c, 0xad, 0xad, 0xc6,
-       0xe8, 0xce, 0x8d, 0x71, 0xd0, 0xc2, 0x17, 0xfc, 0xc5, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0x14,
-       0x83, 0x0d, 0x5b, 0xcd, 0x0b, 0x00, 0x00,
+       // 994 bytes of a gzipped FileDescriptorProto
+       0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xcd, 0x6e, 0xdb, 0x46,
+       0x10, 0x06, 0x45, 0x4a, 0xa4, 0x46, 0xae, 0x65, 0xaf, 0xdd, 0x80, 0x08, 0x1c, 0xc0, 0x60, 0xe1,
+       0x3a, 0x41, 0x00, 0xc3, 0xb1, 0xd3, 0xa2, 0x87, 0x5e, 0xdc, 0xba, 0x6d, 0x74, 0x70, 0x5b, 0xd0,
+       0x41, 0xae, 0xc4, 0x8a, 0xdc, 0x58, 0x8b, 0x4a, 0x5c, 0x75, 0x77, 0xa9, 0xba, 0x7e, 0x8c, 0x5e,
+       0xfb, 0x0a, 0x3d, 0xf5, 0xd8, 0x73, 0x1e, 0xa2, 0xcf, 0xd1, 0x27, 0x28, 0x76, 0xb8, 0x94, 0x28,
+       0x59, 0x4a, 0x24, 0x24, 0xb9, 0x71, 0x7e, 0x76, 0x7e, 0xbe, 0x99, 0x8f, 0xbb, 0x10, 0xf4, 0xd3,
+       0x93, 0xb1, 0x14, 0x5a, 0x90, 0x46, 0x3f, 0x8d, 0xbe, 0x07, 0xef, 0x05, 0x55, 0x03, 0xb2, 0x0d,
+       0x8d, 0xc9, 0x69, 0xe8, 0x1c, 0x3a, 0x8f, 0x5b, 0x71, 0x63, 0x72, 0x8a, 0xf2, 0xb3, 0xb0, 0x61,
+       0xe5, 0x67, 0x28, 0x9f, 0x85, 0xae, 0x95, 0xcf, 0x50, 0x3e, 0x0f, 0x3d, 0x2b, 0x9f, 0x47, 0x5f,
+       0x83, 0xff, 0xb3, 0x14, 0x37, 0x92, 0x8e, 0xc8, 0x23, 0x80, 0xc9, 0x28, 0x99, 0x30, 0xa9, 0xb8,
+       0xc8, 0x31, 0xa4, 0x17, 0xb7, 0x27, 0xa3, 0x57, 0xa5, 0x82, 0x10, 0xf0, 0x52, 0x91, 0x31, 0x8c,
+       0xbd, 0x15, 0xe3, 0x77, 0xd4, 0x03, 0xff, 0x42, 0x29, 0xa6, 0x7b, 0x97, 0xef, 0x5d, 0xc8, 0x15,
+       0x74, 0x30, 0xd4, 0xc5, 0x48, 0x14, 0xb9, 0x26, 0x9f, 0x43, 0x40, 0x8d, 0x98, 0xf0, 0x0c, 0x83,
+       0x76, 0xce, 0x3a, 0x27, 0xfd, 0xf4, 0xc4, 0x66, 0x8b, 0x7d, 0x34, 0xf6, 0x32, 0xf2, 0x00, 0x5a,
+       0x14, 0x4f, 0x60, 0x2a, 0x2f, 0xb6, 0x52, 0xf4, 0xa7, 0x03, 0x5d, 0x74, 0xbe, 0x64, 0xaf, 0x79,
+       0xce, 0xb5, 0xe9, 0xe0, 0x0c, 0x76, 0xf0, 0x93, 0x0e, 0x93, 0xfe, 0x50, 0xa4, 0xbf, 0xcc, 0x62,
+       0x07, 0x26, 0xb6, 0xc1, 0x33, 0xde, 0xb6, 0x1e, 0xdf, 0x18, 0x87, 0x5e, 0x46, 0xbe, 0x84, 0x1d,
+       0xae, 0x54, 0x41, 0xf3, 0x94, 0x25, 0xe3, 0x12, 0x28, 0xcc, 0x64, 0xeb, 0xb1, 0xd8, 0xc5, 0xdd,
+       0xca, 0xa9, 0x02, 0xf3, 0x00, 0xbc, 0x8c, 0x6a, 0x8a, 0x0d, 0xd7, 0xe3, 0xa3, 0x36, 0x1a, 0x42,
+       0xe7, 0x15, 0x1d, 0x16, 0xec, 0x5a, 0x14, 0x32, 0x65, 0xe4, 0x21, 0xb8, 0x92, 0xbd, 0xbe, 0x57,
+       0x8b, 0x51, 0x92, 0x23, 0x68, 0x4e, 0x8c, 0xab, 0xcd, 0xda, 0x9d, 0xa2, 0x50, 0x02, 0x15, 0x97,
+       0x56, 0xf2, 0x10, 0x82, 0xb1, 0x50, 0xd8, 0x27, 0xe6, 0xf4, 0xe2, 0xa9, 0x1c, 0xfd, 0x0a, 0x3b,
+       0x98, 0xed, 0x92, 0x29, 0xcd, 0x73, 0x8a, 0x58, 0x7c, 0xe4, 0x94, 0x7f, 0xb9, 0xd0, 0x41, 0x08,
+       0x5f, 0x30, 0x9a, 0x31, 0x49, 0x42, 0xf0, 0xe7, 0x17, 0xab, 0x12, 0xc9, 0x31, 0x74, 0x15, 0x93,
+       0x9c, 0x0e, 0xf9, 0x1d, 0xcb, 0x12, 0xc5, 0xef, 0x98, 0x9d, 0xe4, 0xf6, 0x4c, 0x7d, 0xcd, 0xef,
+       0x98, 0x99, 0xf4, 0x80, 0xf1, 0x9b, 0x81, 0xb6, 0xc9, 0xac, 0x44, 0x9e, 0xc3, 0xee, 0x58, 0xb2,
+       0x09, 0x17, 0x85, 0x9a, 0x8d, 0xd5, 0x5b, 0xe8, 0xab, 0x5b, 0xb9, 0x54, 0x73, 0x3d, 0x00, 0x4f,
+       0x31, 0x96, 0x85, 0xcd, 0xc5, 0xf9, 0x18, 0x2d, 0x39, 0x80, 0xb6, 0xe6, 0x23, 0xa6, 0x34, 0x1d,
+       0x8d, 0xc3, 0x56, 0xc9, 0x84, 0xa9, 0x82, 0x7c, 0x01, 0xbb, 0x5a, 0xd2, 0x5c, 0xd1, 0xd4, 0xf4,
+       0xaa, 0x12, 0x29, 0x84, 0x0e, 0xfd, 0x85, 0x40, 0x3b, 0x75, 0x97, 0x58, 0x08, 0x4d, 0x9e, 0x40,
+       0x07, 0xb7, 0xd6, 0x1e, 0x08, 0x16, 0x0e, 0x40, 0x69, 0x44, 0xd7, 0x4b, 0x20, 0xb5, 0xe3, 0x89,
+       0xd2, 0x54, 0x17, 0x2a, 0x6c, 0xe3, 0x89, 0x4f, 0xcd, 0x89, 0x97, 0x33, 0xeb, 0x35, 0x1a, 0xe3,
+       0x7a, 0x49, 0xa5, 0x8a, 0xec, 0x43, 0x33, 0x17, 0x79, 0xca, 0x42, 0xc0, 0x0e, 0x4a, 0xc1, 0xf0,
+       0xb8, 0xcf, 0xb5, 0x0a, 0x3b, 0xa8, 0xc4, 0xef, 0xe8, 0x5f, 0x07, 0x82, 0x97, 0xb7, 0x1f, 0x6e,
+       0x56, 0x8f, 0x00, 0x0c, 0x5c, 0x89, 0xa4, 0xf9, 0x0d, 0xb3, 0xf3, 0x42, 0x00, 0x63, 0xa3, 0x20,
+       0xc7, 0x00, 0x92, 0xa9, 0x62, 0x68, 0xd8, 0xad, 0x42, 0xef, 0xd0, 0x9d, 0x03, 0xa2, 0x5d, 0xda,
+       0x7a, 0x99, 0x9a, 0xb2, 0xa8, 0xb9, 0x8c, 0x45, 0xe4, 0x33, 0x08, 0xd8, 0xad, 0x4e, 0x06, 0x54,
+       0x0d, 0x70, 0x48, 0x75, 0x0f, 0x9f, 0xdd, 0x6a, 0xf3, 0x11, 0x3d, 0x85, 0xdd, 0x7b, 0x60, 0x99,
+       0x5d, 0xea, 0x73, 0x3d, 0xa2, 0x63, 0xec, 0x70, 0x2b, 0xb6, 0x52, 0xf4, 0x9f, 0x03, 0xee, 0x55,
+       0x71, 0x4b, 0x9e, 0x80, 0xaf, 0x90, 0x9a, 0x2a, 0x74, 0xb0, 0x3a, 0xe4, 0x40, 0x8d, 0xb2, 0x71,
+       0x65, 0x27, 0x47, 0xe0, 0xbf, 0xe5, 0xbf, 0x50, 0xd9, 0xe6, 0x6a, 0x75, 0x57, 0xd4, 0x4a, 0x7e,
+       0x80, 0xfd, 0xdf, 0xb8, 0xce, 0x99, 0x52, 0x49, 0x36, 0xe3, 0x6a, 0x85, 0xd0, 0xfe, 0xb4, 0x86,
+       0x1a, 0x91, 0xe3, 0x3d, 0x7b, 0xa2, 0xa6, 0x53, 0xe4, 0x29, 0xec, 0x56, 0x81, 0xa8, 0xbc, 0x29,
+       0x46, 0x2c, 0xd7, 0x2a, 0x6c, 0x1e, 0xba, 0x8f, 0xb7, 0xe2, 0x1d, 0x6b, 0xb8, 0xa8, 0xf4, 0xd1,
+       0x3f, 0x0e, 0x34, 0x7f, 0xc4, 0xd5, 0xa8, 0xf5, 0xe2, 0xac, 0xd9, 0x4b, 0x63, 0x55, 0x2f, 0x4b,
+       0x4b, 0x70, 0x97, 0x97, 0x40, 0xbe, 0x82, 0xbd, 0xa9, 0x73, 0x9e, 0x0e, 0x84, 0x64, 0xd9, 0x32,
+       0x16, 0x57, 0x11, 0x2f, 0xac, 0x4f, 0x2f, 0x8b, 0x04, 0x04, 0xdf, 0x0a, 0x9e, 0xf7, 0xa9, 0x62,
+       0xe4, 0xbb, 0x59, 0x94, 0x1a, 0x7c, 0xb6, 0x95, 0xe5, 0xe8, 0x91, 0xfb, 0xe8, 0x19, 0xf2, 0x53,
+       0xd9, 0xe7, 0x5a, 0x52, 0xf9, 0xbb, 0xbd, 0xed, 0x66, 0x8a, 0xe8, 0x8d, 0x03, 0xad, 0x9f, 0x0a,
+       0x3d, 0x2e, 0x34, 0x39, 0x86, 0x56, 0xb9, 0x05, 0x36, 0xc5, 0xbd, 0x25, 0xb1, 0x66, 0xf2, 0x1c,
+       0xba, 0xa9, 0xc8, 0xb5, 0x14, 0xc3, 0xb7, 0xdd, 0x21, 0xdb, 0xd6, 0x67, 0xad, 0x2b, 0x64, 0x6e,
+       0x08, 0xde, 0xaa, 0x21, 0x84, 0xe0, 0x0b, 0x99, 0xf1, 0x9c, 0x0e, 0x91, 0x42, 0x5e, 0x5c, 0x89,
+       0xd1, 0x1f, 0x0e, 0x40, 0xcc, 0x34, 0x97, 0xcc, 0x4c, 0x60, 0xfd, 0x56, 0xaa, 0xa2, 0x1a, 0xef,
+       0x2c, 0xca, 0x5d, 0xa3, 0x28, 0x6f, 0xbe, 0xa8, 0xbf, 0x5d, 0x08, 0x7a, 0xf6, 0x22, 0x25, 0x47,
+       0xd0, 0x2e, 0x77, 0x61, 0xd9, 0x35, 0x1d, 0x94, 0xa6, 0x5e, 0xb6, 0xee, 0x65, 0xf5, 0x01, 0xc0,
+       0x5c, 0xb1, 0x5e, 0xcd, 0x0d, 0xd7, 0xeb, 0x0a, 0xc2, 0xe9, 0xae, 0xe3, 0x0b, 0x27, 0x9b, 0xbe,
+       0x50, 0xec, 0x5f, 0x6c, 0x6f, 0xda, 0xc3, 0xec, 0xf1, 0x12, 0x3f, 0xa8, 0x76, 0x7f, 0xe1, 0x51,
+       0xb3, 0x94, 0x67, 0xfe, 0x66, 0x3c, 0x0b, 0xde, 0xc9, 0xb3, 0xfa, 0xd0, 0xda, 0xf3, 0x43, 0x7b,
+       0xd3, 0x80, 0xe6, 0xf5, 0x98, 0xe5, 0x19, 0x39, 0x85, 0xae, 0x1a, 0xb3, 0x5c, 0x27, 0x02, 0xf9,
+       0xb1, 0x6c, 0x6e, 0x9f, 0xa0, 0x43, 0xc9, 0x9f, 0xf2, 0x16, 0x7e, 0xdf, 0x6d, 0x5a, 0x31, 0x15,
+       0x6f, 0xc3, 0xa9, 0x6c, 0xf2, 0xc7, 0x5c, 0x05, 0x63, 0x6b, 0x23, 0x18, 0xfd, 0x39, 0x18, 0xfb,
+       0x2d, 0x7c, 0xdb, 0x9f, 0xff, 0x1f, 0x00, 0x00, 0xff, 0xff, 0x6f, 0xfd, 0x0b, 0x55, 0xe7, 0x0b,
+       0x00, 0x00,
 }
index 91ab9af..51d413f 100644 (file)
@@ -55,7 +55,7 @@ message BlockHeader {
   uint64            height             = 3;
   Hash              previous_block_id  = 4;
   Hash              seed               = 5;
-  uint64            timestamp_ms       = 6;
+  uint64            timestamp          = 6;
   Hash              transactions_root  = 7;
   Hash              assets_root        = 8;
   TransactionStatus transaction_status = 9;
@@ -66,9 +66,10 @@ message BlockHeader {
 message TxHeader {
   uint64        version         = 1;
   uint64        serialized_size = 2;
-  repeated Hash result_ids      = 3;
-  Hash          data            = 4;
-  Hash          ext_hash        = 5;
+  uint64        time_range      = 3;
+  repeated Hash result_ids      = 4;
+  Hash          data            = 5;
+  Hash          ext_hash        = 6;
 }
 
 message TransactionStatus {
index 5e98630..9cb74b5 100644 (file)
@@ -11,7 +11,7 @@ func (bh *BlockHeader) writeForHash(w io.Writer) {
        mustWriteForHash(w, bh.Height)
        mustWriteForHash(w, bh.PreviousBlockId)
        mustWriteForHash(w, bh.Seed)
-       mustWriteForHash(w, bh.TimestampMs)
+       mustWriteForHash(w, bh.Timestamp)
        mustWriteForHash(w, bh.TransactionsRoot)
        mustWriteForHash(w, bh.AssetsRoot)
        mustWriteForHash(w, bh.Nonce)
@@ -21,13 +21,13 @@ func (bh *BlockHeader) writeForHash(w io.Writer) {
 
 // NewBlockHeader creates a new BlockHeader and populates
 // its body.
-func NewBlockHeader(version, height uint64, previousBlockID, seed *Hash, timestampMS uint64, transactionsRoot, assetsRoot *Hash, ts *TransactionStatus, nonce, bits uint64) *BlockHeader {
+func NewBlockHeader(version, height uint64, previousBlockID, seed *Hash, timestamp uint64, transactionsRoot, assetsRoot *Hash, ts *TransactionStatus, nonce, bits uint64) *BlockHeader {
        return &BlockHeader{
                Version:           version,
                Height:            height,
                PreviousBlockId:   previousBlockID,
                Seed:              seed,
-               TimestampMs:       timestampMS,
+               Timestamp:         timestamp,
                TransactionsRoot:  transactionsRoot,
                AssetsRoot:        assetsRoot,
                TransactionStatus: ts,
index 053e6de..547056c 100644 (file)
@@ -10,8 +10,8 @@ func BenchmarkEntryID(b *testing.B) {
 
        entries := []Entry{
                NewIssuance(nil, &AssetAmount{}, &Hash{}, 0),
-               NewTxHeader(1, 1, nil, &Hash{}),
                m,
+               NewTxHeader(1, 1, 0, nil, &Hash{}),
                NewNonce(&Program{Code: []byte{1}, VmVersion: 1}),
                NewOutput(&ValueSource{}, &Program{Code: []byte{1}, VmVersion: 1}, &Hash{}, 0),
                NewRetirement(&ValueSource{}, &Hash{}, 1),
index a9fb35d..3988d0d 100644 (file)
@@ -26,10 +26,8 @@ type BlockHeader struct {
 
        Seed bc.Hash
 
-       // Time of the block in milliseconds.
-       // Must grow monotonically and can be equal
-       // to the time in the previous block.
-       TimestampMS uint64
+       // Time of the block in seconds.
+       Timestamp uint64
 
        TransactionStatus bc.TransactionStatus
 
@@ -41,7 +39,7 @@ type BlockHeader struct {
 
 // Time returns the time represented by the Timestamp in bh.
 func (bh *BlockHeader) Time() time.Time {
-       tsNano := bh.TimestampMS * uint64(time.Millisecond)
+       tsNano := bh.Timestamp * uint64(time.Second)
        return time.Unix(0, int64(tsNano)).UTC()
 }
 
@@ -110,7 +108,7 @@ func (bh *BlockHeader) readFrom(r *blockchain.Reader) (serflag uint8, err error)
        if _, err = bh.Seed.ReadFrom(r); err != nil {
                return 0, err
        }
-       if bh.TimestampMS, err = blockchain.ReadVarint63(r); err != nil {
+       if bh.Timestamp, err = blockchain.ReadVarint63(r); err != nil {
                return 0, err
        }
        if _, err = blockchain.ReadExtensibleString(r, bh.BlockCommitment.readFrom); err != nil {
@@ -151,7 +149,7 @@ func (bh *BlockHeader) writeTo(w io.Writer, serflags uint8) (err error) {
        if _, err = bh.Seed.WriteTo(w); err != nil {
                return err
        }
-       if _, err = blockchain.WriteVarint63(w, bh.TimestampMS); err != nil {
+       if _, err = blockchain.WriteVarint63(w, bh.Timestamp); err != nil {
                return err
        }
        if _, err = blockchain.WriteExtensibleString(w, nil, bh.BlockCommitment.writeTo); err != nil {
index 5fca6ed..7cece43 100644 (file)
@@ -23,7 +23,7 @@ func TestMarshalBlock(t *testing.T) {
                Transactions: []*Tx{
                        NewTx(TxData{
                                Version:        1,
-                               SerializedSize: uint64(43),
+                               SerializedSize: uint64(46),
                                Outputs: []*TxOutput{
                                        NewTxOutput(bc.AssetID{}, 1, nil, nil),
                                },
@@ -54,6 +54,7 @@ func TestMarshalBlock(t *testing.T) {
                "01" + // num transactions
                "07" + // tx 0, serialization flags
                "01" + // tx 0, tx version
+               "00" + // tx maxtime
                "00" + // tx 0, common witness extensible string length
                "00" + // tx 0, inputs count
                "01" + // tx 0, outputs count
@@ -170,7 +171,7 @@ func TestSmallBlock(t *testing.T) {
                "00" + // nonce
                "00" + // bits
                "01" + // num transactions
-               "070100000000") // transaction
+               "07010000000000") // transaction
        want, _ := hex.DecodeString(wantHex)
        if !bytes.Equal(got, want) {
                t.Errorf("small block bytes = %x want %x", got, want)
index cc52409..91ab678 100644 (file)
@@ -3,7 +3,7 @@ package legacy
 import "testing"
 
 func TestFuzzUnknownAssetVersion(t *testing.T) {
-       const rawTx = `07010001f1b72b0001012b00089def834ab929327f3f479177e2d8c293f2f7fc4f251db8547896c0eeafb984261a73767178584c246400b50150935a092ffad7ec9fbac4f4486db6c3b8cd5b9f51cf697248584dde286a722000012b766baa20627e83fdad13dd98436fa7cbdd1412d50ef65528edb7e2ed8f2675b2a0b209235151ad696c00c0030040b984261ad6e71876ec4c2464012b766baa209d44ee5b6ebf6c408772ead7713f1a66b9de7655ff452513487be1fb10de7d985151ad696c00c02a7b2274657374223a225175657279546573742e7465737442616c616e636551756572792e74657374227d`
+       const rawTx = `0701000001f1b72b0001012b00089def834ab929327f3f479177e2d8c293f2f7fc4f251db8547896c0eeafb984261a73767178584c246400b50150935a092ffad7ec9fbac4f4486db6c3b8cd5b9f51cf697248584dde286a722000012b766baa20627e83fdad13dd98436fa7cbdd1412d50ef65528edb7e2ed8f2675b2a0b209235151ad696c00c0030040b984261ad6e71876ec4c2464012b766baa209d44ee5b6ebf6c408772ead7713f1a66b9de7655ff452513487be1fb10de7d985151ad696c00c02a7b2274657374223a225175657279546573742e7465737442616c616e636551756572792e74657374227d`
 
        var want Tx
        err := want.UnmarshalText([]byte(rawTx))
index d88a6d8..0246857 100644 (file)
@@ -234,14 +234,14 @@ func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash
        }
 
        refdatahash := hashData(tx.ReferenceData)
-       h := bc.NewTxHeader(tx.Version, tx.SerializedSize, resultIDs, &refdatahash)
+       h := bc.NewTxHeader(tx.Version, tx.SerializedSize, tx.TimeRange, resultIDs, &refdatahash)
        headerID = addEntry(h)
 
        return headerID, h, entryMap
 }
 
 func mapBlockHeader(old *BlockHeader) (bhID bc.Hash, bh *bc.BlockHeader) {
-       bh = bc.NewBlockHeader(old.Version, old.Height, &old.PreviousBlockHash, &old.Seed, old.TimestampMS, &old.TransactionsMerkleRoot, &old.AssetsMerkleRoot, &old.TransactionStatus, old.Nonce, old.Bits)
+       bh = bc.NewBlockHeader(old.Version, old.Height, &old.PreviousBlockHash, &old.Seed, old.Timestamp, &old.TransactionsMerkleRoot, &old.AssetsMerkleRoot, &old.TransactionStatus, old.Nonce, old.Bits)
        bhID = bc.EntryID(bh)
        return
 }
index f48d37b..2c878eb 100644 (file)
@@ -85,6 +85,8 @@ type TxData struct {
        Inputs         []*TxInput
        Outputs        []*TxOutput
 
+       TimeRange uint64
+
        // The unconsumed suffix of the common fields extensible string
        CommonFieldsSuffix []byte
 
@@ -121,6 +123,7 @@ func (tx *TxData) UnmarshalText(p []byte) error {
 }
 
 func (tx *TxData) readFrom(r *blockchain.Reader) (err error) {
+       tx.SerializedSize = uint64(r.Len())
        var serflags [1]byte
        if _, err = io.ReadFull(r, serflags[:]); err != nil {
                return errors.Wrap(err, "reading serialization flags")
@@ -134,8 +137,9 @@ func (tx *TxData) readFrom(r *blockchain.Reader) (err error) {
                return errors.Wrap(err, "reading transaction version")
        }
 
-       tx.SerializedSize = uint64(r.Len())
-
+       if tx.TimeRange, err = blockchain.ReadVarint63(r); err != nil {
+               return err
+       }
        // Common witness
        tx.CommonWitnessSuffix, err = blockchain.ReadExtensibleString(r, tx.readCommonWitness)
        if err != nil {
@@ -201,6 +205,9 @@ func (tx *TxData) writeTo(w io.Writer, serflags byte) error {
                return errors.Wrap(err, "writing transaction version")
        }
 
+       if _, err := blockchain.WriteVarint63(w, tx.TimeRange); err != nil {
+               return errors.Wrap(err, "writing transaction maxtime")
+       }
        // common witness
        if _, err := blockchain.WriteExtensibleString(w, tx.CommonWitnessSuffix, tx.writeCommonWitness); err != nil {
                return errors.Wrap(err, "writing common witness")
index d7d3c47..981388c 100644 (file)
@@ -16,7 +16,7 @@ import (
 )
 
 func TestTransactionTrailingGarbage(t *testing.T) {
-       const validTxHex = `070100000101270eac870dfde1e0feaa4fac6693dee38da2afe7f5cc83ce2b024f04a2400fd6e20a0104deadbeef027b7d0000`
+       const validTxHex = `07010000000101270eac870dfde1e0feaa4fac6693dee38da2afe7f5cc83ce2b024f04a2400fd6e20a0104deadbeef027b7d0000`
 
        var validTx Tx
        err := validTx.UnmarshalText([]byte(validTxHex))
@@ -47,23 +47,24 @@ func TestTransaction(t *testing.T) {
                {
                        tx: NewTx(TxData{
                                Version:        1,
-                               SerializedSize: uint64(4),
+                               SerializedSize: uint64(7),
                                Inputs:         nil,
                                Outputs:        nil,
                                ReferenceData:  nil,
                        }),
                        hex: ("07" + // serflags
                                "01" + // transaction version
+                               "00" + // tx maxtime
                                "00" + // common witness extensible string length
                                "00" + // inputs count
                                "00" + // outputs count
                                "00"), // reference data
-                       hash: mustDecodeHash("3629cd98d6707aab6055e125ea16be6a4e8e8c60aa195126ab7ee0cc246ab430"),
+                       hash: mustDecodeHash("196ffe40c99e0c25bc2b7347db147e626a13132a8d404b92e270ec6e8df24234"),
                },
                {
                        tx: NewTx(TxData{
                                Version:        1,
-                               SerializedSize: uint64(156),
+                               SerializedSize: uint64(159),
                                Inputs: []*TxInput{
                                        NewIssuanceInput([]byte{10, 9, 8}, 1000000000000, []byte("input"), initialBlockHash, issuanceScript, [][]byte{[]byte{1, 2, 3}}, nil),
                                },
@@ -74,6 +75,7 @@ func TestTransaction(t *testing.T) {
                        }),
                        hex: ("07" + // serflags
                                "01" + // transaction version
+                               "00" + // tx maxtime
                                "00" + // common witness extensible string length
                                "01" + // inputs count
                                "01" + // input 0, asset version
@@ -103,12 +105,12 @@ func TestTransaction(t *testing.T) {
                                "066f7574707574" + // output 0, reference data
                                "00" + // output 0, output witness
                                "0869737375616e6365"), // reference data
-                       hash: mustDecodeHash("191646bc995127b369a1459a58759368d8f1b95adfda87c9c858165a49f67659"),
+                       hash: mustDecodeHash("7a9e4f4b87d8af099081d0dfec77fe33ccf288d586308d8a14a640b72ca474f8"),
                },
                {
                        tx: NewTx(TxData{
                                Version:        1,
-                               SerializedSize: uint64(224),
+                               SerializedSize: uint64(227),
                                Inputs: []*TxInput{
                                        NewSpendInput(nil, mustDecodeHash("dd385f6fe25d91d8c1bd0fa58951ad56b0c5229dcc01f61d9f9e8b9eb92d3292"), bc.AssetID{}, 1000000000000, 1, []byte{1}, bc.Hash{}, []byte("input")),
                                },
@@ -120,6 +122,7 @@ func TestTransaction(t *testing.T) {
                        }),
                        hex: ("07" + // serflags
                                "01" + // transaction version
+                               "00" + // tx maxtime
                                "00" + // common witness extensible string length
                                "01" + // inputs count
                                "01" + // input 0, asset version
@@ -154,7 +157,7 @@ func TestTransaction(t *testing.T) {
                                "00" + // output 1, reference data
                                "00" + // output 1, output witness
                                "0c646973747269627574696f6e"), // reference data
-                       hash: mustDecodeHash("52611aef626501b815b0d80312fba172a5055b06458bbe32b980fd5e41ba8f46"),
+                       hash: mustDecodeHash("4074fc31692af33defcee32189eaa8cb6219db259883707009b048d7165812ca"),
                },
        }
        for i, test := range cases {
@@ -229,6 +232,7 @@ func TestHasIssuance(t *testing.T) {
 func TestInvalidIssuance(t *testing.T) {
        hex := ("07" + // serflags
                "01" + // transaction version
+               "00" + // tx maxtime
                "00" + // common witness extensible string length
                "01" + // inputs count
                "01" + // input 0, asset version
index 430e2d7..119a41b 100644 (file)
@@ -15,11 +15,11 @@ func TestTxHashes(t *testing.T) {
        }{
                {
                        txdata: &TxData{},
-                       hash:   mustDecodeHash("02439cf4a8d801d10e84f5b3818226e38dac889dc626b7a1b5888b49510b38fe"),
+                       hash:   mustDecodeHash("221ed254e69ffaefc0c52baff161392001f8c3ce5c120e4d2cba26eef0bf9500"),
                },
                {
                        txdata: sampleTx(),
-                       hash:   mustDecodeHash("360eab1b2563e85d9a3f290f3f2c0d99c622c89088f8c2e2003000fbee62cca0"), // todo: verify this value,
+                       hash:   mustDecodeHash("0fd4368e2348690af748eb1b4d5a661dd7ee2cf3b6555ce788aea391d9c10718"), // todo: verify this value,
                },
        }
 
index a5e3458..7b1c72f 100644 (file)
@@ -20,7 +20,7 @@ func TestMerkleRoot(t *testing.T) {
                                []byte("00000"),
                        },
                },
-               want: mustDecodeHash("c1b9e0b7f761e15b590834a01fe7a10e602d9ee6a4c674392a2b106242f29e8b"),
+               want: mustDecodeHash("ddf6b62a276929250336a294b1f1863fe979a0f418f02aa9d098fca775573c3c"),
        }, {
                witnesses: [][][]byte{
                        [][]byte{
@@ -32,7 +32,7 @@ func TestMerkleRoot(t *testing.T) {
                                []byte("111111"),
                        },
                },
-               want: mustDecodeHash("1719bd4ff9fdf4de4b8e403a9302c30162e61bec1e688c21173c7c2aec4792bb"),
+               want: mustDecodeHash("c5ca521b644f9b3a393e046566a9ca8f2eafd9f46c7cebbed38fa5cc2ebb3e4c"),
        }, {
                witnesses: [][][]byte{
                        [][]byte{
@@ -45,7 +45,7 @@ func TestMerkleRoot(t *testing.T) {
                                []byte("222222"),
                        },
                },
-               want: mustDecodeHash("1719bd4ff9fdf4de4b8e403a9302c30162e61bec1e688c21173c7c2aec4792bb"),
+               want: mustDecodeHash("c5ca521b644f9b3a393e046566a9ca8f2eafd9f46c7cebbed38fa5cc2ebb3e4c"),
        }}
 
        for _, c := range cases {
diff --git a/protocol/bc/time.go b/protocol/bc/time.go
deleted file mode 100644 (file)
index c6290cd..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-package bc
-
-import "time"
-
-// Millis converts a time.Time to a number of milliseconds since 1970.
-func Millis(t time.Time) uint64 {
-       return uint64(t.UnixNano()) / uint64(time.Millisecond)
-}
-
-// DurationMillis converts a time.Duration to a number of milliseconds.
-func DurationMillis(d time.Duration) uint64 {
-       return uint64(d / time.Millisecond)
-}
-
-// MillisDuration coverts milliseconds to a time.Duration.
-func MillisDuration(m uint64) time.Duration {
-       return time.Duration(m) * time.Millisecond
-}
index 723ac0b..8eefd40 100644 (file)
@@ -10,16 +10,18 @@ import "io"
 func (TxHeader) typ() string { return "txheader" }
 func (h *TxHeader) writeForHash(w io.Writer) {
        mustWriteForHash(w, h.Version)
+       mustWriteForHash(w, h.TimeRange)
        mustWriteForHash(w, h.ResultIds)
        mustWriteForHash(w, h.Data)
        mustWriteForHash(w, h.ExtHash)
 }
 
 // NewTxHeader creates an new TxHeader.
-func NewTxHeader(version, serializedSize uint64, resultIDs []*Hash, data *Hash) *TxHeader {
+func NewTxHeader(version, serializedSize, timeRange uint64, resultIDs []*Hash, data *Hash) *TxHeader {
        return &TxHeader{
                Version:        version,
                SerializedSize: serializedSize,
+               TimeRange:      timeRange,
                ResultIds:      resultIDs,
                Data:           data,
        }
index 6337bf3..0c8d788 100644 (file)
@@ -6,16 +6,23 @@ import (
        "sync/atomic"
        "time"
 
+       "github.com/golang/groupcache/lru"
+
+       "github.com/bytom/blockchain/txdb/storage"
+       "github.com/bytom/consensus"
        "github.com/bytom/protocol/bc"
        "github.com/bytom/protocol/bc/legacy"
-       "github.com/golang/groupcache/lru"
+       "github.com/bytom/protocol/state"
+       log "github.com/sirupsen/logrus"
 )
 
 var (
        maxCachedErrTxs = 1000
        maxNewTxChSize  = 1000
+       maxNewTxNum     = 10000
        // ErrTransactionNotExist is the pre-defined error message
        ErrTransactionNotExist = errors.New("transaction are not existed in the mempool")
+       ErrPoolIsFull          = errors.New("transaction pool reach the max number")
 )
 
 // TxDesc store tx and related info for mining strategy
@@ -33,6 +40,7 @@ type TxPool struct {
        lastUpdated int64
        mtx         sync.RWMutex
        pool        map[bc.Hash]*TxDesc
+       utxo        map[bc.Hash]bc.Hash
        errCache    *lru.Cache
        newTxCh     chan *legacy.Tx
 }
@@ -42,6 +50,7 @@ func NewTxPool() *TxPool {
        return &TxPool{
                lastUpdated: time.Now().Unix(),
                pool:        make(map[bc.Hash]*TxDesc),
+               utxo:        make(map[bc.Hash]bc.Hash),
                errCache:    lru.New(maxCachedErrTxs),
                newTxCh:     make(chan *legacy.Tx, maxNewTxChSize),
        }
@@ -53,7 +62,14 @@ func (mp *TxPool) GetNewTxCh() chan *legacy.Tx {
 }
 
 // AddTransaction add a verified transaction to pool
-func (mp *TxPool) AddTransaction(tx *legacy.Tx, height, fee uint64) *TxDesc {
+func (mp *TxPool) AddTransaction(tx *legacy.Tx, gasOnlyTx bool, height, fee uint64) (*TxDesc, error) {
+       mp.mtx.Lock()
+       defer mp.mtx.Unlock()
+
+       if len(mp.pool) >= maxNewTxNum {
+               return nil, ErrPoolIsFull
+       }
+
        txD := &TxDesc{
                Tx:       tx,
                Added:    time.Now(),
@@ -63,14 +79,22 @@ func (mp *TxPool) AddTransaction(tx *legacy.Tx, height, fee uint64) *TxDesc {
                FeePerKB: fee * 1000 / tx.TxHeader.SerializedSize,
        }
 
-       mp.mtx.Lock()
-       defer mp.mtx.Unlock()
-
        mp.pool[tx.Tx.ID] = txD
        atomic.StoreInt64(&mp.lastUpdated, time.Now().Unix())
 
+       for _, id := range tx.TxHeader.ResultIds {
+               output, err := tx.Output(*id)
+               if err != nil {
+                       return nil, err
+               }
+               if !gasOnlyTx || *output.Source.Value.AssetId == *consensus.BTMAssetID {
+                       mp.utxo[*id] = tx.Tx.ID
+               }
+       }
+
        mp.newTxCh <- tx
-       return txD
+       log.WithField("tx_id", tx.Tx.ID).Info("Add tx to mempool")
+       return txD, nil
 }
 
 // AddErrCache add a failed transaction record to lru cache
@@ -98,10 +122,18 @@ func (mp *TxPool) RemoveTransaction(txHash *bc.Hash) {
        mp.mtx.Lock()
        defer mp.mtx.Unlock()
 
-       if _, ok := mp.pool[*txHash]; ok {
-               delete(mp.pool, *txHash)
-               atomic.StoreInt64(&mp.lastUpdated, time.Now().Unix())
+       txD, ok := mp.pool[*txHash]
+       if !ok {
+               return
+       }
+
+       for _, output := range txD.Tx.TxHeader.ResultIds {
+               delete(mp.utxo, *output)
        }
+       delete(mp.pool, *txHash)
+       atomic.StoreInt64(&mp.lastUpdated, time.Now().Unix())
+
+       log.WithField("tx_id", txHash).Info("remove tx from mempool")
 }
 
 // GetTransaction return the TxDesc by hash
@@ -130,6 +162,20 @@ func (mp *TxPool) GetTransactions() []*TxDesc {
        return txDs
 }
 
+// GetTransactionUTXO return unconfirmed utxo
+func (mp *TxPool) GetTransactionUTXO(tx *bc.Tx) *state.UtxoViewpoint {
+       mp.mtx.RLock()
+       defer mp.mtx.RUnlock()
+
+       view := state.NewUtxoViewpoint()
+       for _, prevout := range tx.SpentOutputIDs {
+               if _, ok := mp.utxo[prevout]; ok {
+                       view.Entries[prevout] = storage.NewUtxoEntry(false, 0, false)
+               }
+       }
+       return view
+}
+
 // IsTransactionInPool check wheather a transaction in pool or not
 func (mp *TxPool) IsTransactionInPool(txHash *bc.Hash) bool {
        mp.mtx.RLock()
index aee1552..4ad559a 100644 (file)
@@ -14,7 +14,7 @@ func TestTxPool(t *testing.T) {
        txB := mockCoinbaseTx(2000, 2324)
        txC := mockCoinbaseTx(3000, 9322)
 
-       p.AddTransaction(txA, 1000, 5000000000)
+       p.AddTransaction(txA, false, 1000, 5000000000)
        if !p.IsTransactionInPool(&txA.ID) {
                t.Errorf("fail to find added txA in tx pool")
        } else {
@@ -27,7 +27,7 @@ func TestTxPool(t *testing.T) {
        if p.IsTransactionInPool(&txB.ID) {
                t.Errorf("shouldn't find txB in tx pool")
        }
-       p.AddTransaction(txB, 1, 5000000000)
+       p.AddTransaction(txB, false, 1, 5000000000)
        if !p.IsTransactionInPool(&txB.ID) {
                t.Errorf("shouldn find txB in tx pool")
        }
index 578c557..0eded1b 100755 (executable)
@@ -200,13 +200,13 @@ func (c *Chain) InMainChain(height uint64, hash bc.Hash) bool {
 }
 
 // TimestampMS returns the latest known block timestamp.
-func (c *Chain) TimestampMS() uint64 {
+func (c *Chain) Timestamp() uint64 {
        c.state.cond.L.Lock()
        defer c.state.cond.L.Unlock()
        if c.state.block == nil {
                return 0
        }
-       return c.state.block.TimestampMS
+       return c.state.block.Timestamp
 }
 
 // BestBlock returns the chain tail block
index 3001239..00721ba 100644 (file)
@@ -2,6 +2,7 @@ package protocol
 
 import (
        "github.com/bytom/errors"
+       "github.com/bytom/protocol/bc"
        "github.com/bytom/protocol/bc/legacy"
        "github.com/bytom/protocol/validation"
 )
@@ -14,22 +15,33 @@ var ErrBadTx = errors.New("invalid transaction")
 // performing full validation.
 func (c *Chain) ValidateTx(tx *legacy.Tx) error {
        newTx := tx.Tx
+       block := legacy.MapBlock(c.BestBlock())
        if ok := c.txPool.HaveTransaction(&newTx.ID); ok {
                return c.txPool.GetErrCache(&newTx.ID)
        }
 
-       oldBlock, err := c.GetBlockByHash(c.state.hash)
-       if err != nil {
+       // validate the UTXO
+       view := c.txPool.GetTransactionUTXO(tx.Tx)
+       if err := c.GetTransactionsUtxo(view, []*bc.Tx{newTx}); err != nil {
+               c.txPool.AddErrCache(&newTx.ID, err)
                return err
        }
-       block := legacy.MapBlock(oldBlock)
-       fee, gasVaild, err := validation.ValidateTx(newTx, block)
-
-       if !gasVaild && err != nil {
+       if err := view.ApplyTransaction(block, newTx, false); err != nil {
                c.txPool.AddErrCache(&newTx.ID, err)
                return err
        }
 
-       c.txPool.AddTransaction(tx, block.BlockHeader.Height, fee)
-       return errors.Sub(ErrBadTx, err)
+       // validate the BVM contract
+       gasOnlyTx := false
+       fee, gasVaild, err := validation.ValidateTx(newTx, block)
+       if err != nil {
+               if !gasVaild {
+                       c.txPool.AddErrCache(&newTx.ID, err)
+                       return err
+               }
+               gasOnlyTx = true
+       }
+
+       _, err = c.txPool.AddTransaction(tx, gasOnlyTx, block.BlockHeader.Height, fee)
+       return err
 }
index bf62804..883dbb6 100644 (file)
@@ -17,7 +17,7 @@ func generate(tb testing.TB, prev *bc.Block) *bc.Block {
                        Version:           1,
                        Height:            prev.Height + 1,
                        PreviousBlockHash: prev.ID,
-                       TimestampMS:       prev.TimestampMs + 1,
+                       Timestamp:         prev.Timestamp + 1,
                        BlockCommitment:   legacy.BlockCommitment{},
                },
        }
index 803f8c5..42604df 100644 (file)
@@ -2,6 +2,7 @@ package validation
 
 import (
        "fmt"
+       "time"
 
        "github.com/bytom/consensus"
        "github.com/bytom/consensus/algorithm"
@@ -85,6 +86,7 @@ type validationState struct {
 }
 
 var (
+       errBadTimestamp             = errors.New("block timestamp is great than limit")
        errGasCalculate             = errors.New("gas usage calculate got a math error")
        errEmptyResults             = errors.New("transaction has no results")
        errMismatchedAssetID        = errors.New("mismatched asset id")
@@ -529,6 +531,9 @@ func ValidateBlock(b, prev *bc.Block, seedCaches *seed.SeedCaches) error {
                        return err
                }
        }
+       if b.Timestamp > uint64(time.Now().Unix())+consensus.MaxTimeOffsetSeconds {
+               return errBadTimestamp
+       }
 
        if b.BlockHeader.SerializedSize > consensus.MaxBlockSzie {
                return errWrongBlockSize
@@ -551,7 +556,9 @@ func ValidateBlock(b, prev *bc.Block, seedCaches *seed.SeedCaches) error {
                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")
+               }
                txBTMValue, gasVaild, err := ValidateTx(tx, b)
                gasOnlyTx := false
                if err != nil {
@@ -616,8 +623,8 @@ func validateBlockAgainstPrev(b, prev *bc.Block) error {
        if prev.ID != *b.PreviousBlockId {
                return errors.WithDetailf(errMismatchedBlock, "previous block ID %x, current block wants %x", prev.ID.Bytes(), b.PreviousBlockId.Bytes())
        }
-       if b.TimestampMs <= prev.TimestampMs {
-               return errors.WithDetailf(errMisorderedBlockTime, "previous block time %d, current block time %d", prev.TimestampMs, b.TimestampMs)
+       if b.Timestamp <= prev.Timestamp {
+               return errors.WithDetailf(errMisorderedBlockTime, "previous block time %d, current block time %d", prev.Timestamp, b.Timestamp)
        }
        if *b.Seed != *algorithm.CreateSeed(b.Height, prev.Seed, []*bc.Hash{&prev.ID}) {
                return errors.New("wrong block seed")
@@ -668,7 +675,6 @@ func ValidateTx(tx *bc.Tx, block *bc.Block) (uint64, bool, error) {
        if tx.TxHeader.SerializedSize > consensus.MaxTxSize {
                return 0, false, errWrongTransactionSize
        }
-
        if len(tx.ResultIds) == 0 {
                return 0, false, errors.New("tx didn't have any output")
        }