Browse Source

consensus & account txs are all in Block.Data.Txs

pull/9/head
Jae Kwon 10 years ago
parent
commit
03d1af711a
5 changed files with 132 additions and 77 deletions
  1. +52
    -47
      blocks/block.go
  2. +4
    -5
      blocks/block_test.go
  3. +6
    -6
      blocks/codec_test.go
  4. +3
    -3
      blocks/tx.go
  5. +67
    -16
      mempool/mempool.go

+ 52
- 47
blocks/block.go View File

@ -17,7 +17,7 @@ const (
type Block struct { type Block struct {
Header Header
Validation Validation
Txs
Data
// Volatile // Volatile
hash []byte hash []byte
@ -27,14 +27,14 @@ func ReadBlock(r io.Reader, n *int64, err *error) *Block {
return &Block{ return &Block{
Header: ReadHeader(r, n, err), Header: ReadHeader(r, n, err),
Validation: ReadValidation(r, n, err), Validation: ReadValidation(r, n, err),
Txs: ReadTxs(r, n, err),
Data: ReadData(r, n, err),
} }
} }
func (b *Block) WriteTo(w io.Writer) (n int64, err error) { func (b *Block) WriteTo(w io.Writer) (n int64, err error) {
WriteBinary(w, &b.Header, &n, &err) WriteBinary(w, &b.Header, &n, &err)
WriteBinary(w, &b.Validation, &n, &err) WriteBinary(w, &b.Validation, &n, &err)
WriteBinary(w, &b.Txs, &n, &err)
WriteBinary(w, &b.Data, &n, &err)
return return
} }
@ -50,7 +50,7 @@ func (b *Block) Hash() []byte {
hashes := [][]byte{ hashes := [][]byte{
b.Header.Hash(), b.Header.Hash(),
b.Validation.Hash(), b.Validation.Hash(),
b.Txs.Hash(),
b.Data.Hash(),
} }
// Merkle hash from sub-hashes. // Merkle hash from sub-hashes.
return merkle.HashFromByteSlices(hashes) return merkle.HashFromByteSlices(hashes)
@ -79,6 +79,21 @@ func (b *Block) ToBlockPartSet() *BlockPartSet {
return NewBlockPartSet(b.Height, parts) return NewBlockPartSet(b.Height, parts)
} }
// Makes an empty next block.
func (b *Block) MakeNextBlock() *Block {
return &Block{
Header: Header{
Name: b.Header.Name,
Height: b.Header.Height + 1,
//Fees: uint64(0),
Time: time.Now(),
PrevHash: b.Hash(),
//ValidationStateHash: nil,
//AccountStateHash: nil,
},
}
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/* /*
@ -133,15 +148,14 @@ func (bp *BlockPart) Hash() []byte {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/* Header is part of a Block */
type Header struct { type Header struct {
Name string
Height uint32
Fees uint64
Time time.Time
PrevHash []byte
ValidationHash []byte
TxsHash []byte
Name string
Height uint32
Fees uint64
Time time.Time
PrevHash []byte
ValidationStateHash []byte
AccountStateHash []byte
// Volatile // Volatile
hash []byte hash []byte
@ -152,13 +166,13 @@ func ReadHeader(r io.Reader, n *int64, err *error) (h Header) {
return Header{} return Header{}
} }
return Header{ return Header{
Name: ReadString(r, n, err),
Height: ReadUInt32(r, n, err),
Fees: ReadUInt64(r, n, err),
Time: ReadTime(r, n, err),
PrevHash: ReadByteSlice(r, n, err),
ValidationHash: ReadByteSlice(r, n, err),
TxsHash: ReadByteSlice(r, n, err),
Name: ReadString(r, n, err),
Height: ReadUInt32(r, n, err),
Fees: ReadUInt64(r, n, err),
Time: ReadTime(r, n, err),
PrevHash: ReadByteSlice(r, n, err),
ValidationStateHash: ReadByteSlice(r, n, err),
AccountStateHash: ReadByteSlice(r, n, err),
} }
} }
@ -168,8 +182,8 @@ func (h *Header) WriteTo(w io.Writer) (n int64, err error) {
WriteUInt64(w, h.Fees, &n, &err) WriteUInt64(w, h.Fees, &n, &err)
WriteTime(w, h.Time, &n, &err) WriteTime(w, h.Time, &n, &err)
WriteByteSlice(w, h.PrevHash, &n, &err) WriteByteSlice(w, h.PrevHash, &n, &err)
WriteByteSlice(w, h.ValidationHash, &n, &err)
WriteByteSlice(w, h.TxsHash, &n, &err)
WriteByteSlice(w, h.ValidationStateHash, &n, &err)
WriteByteSlice(w, h.AccountStateHash, &n, &err)
return return
} }
@ -187,10 +201,10 @@ func (h *Header) Hash() []byte {
} }
} }
/* Validation is part of a block */
//-----------------------------------------------------------------------------
type Validation struct { type Validation struct {
Signatures []Signature Signatures []Signature
Txs []Tx
// Volatile // Volatile
hash []byte hash []byte
@ -198,30 +212,20 @@ type Validation struct {
func ReadValidation(r io.Reader, n *int64, err *error) Validation { func ReadValidation(r io.Reader, n *int64, err *error) Validation {
numSigs := ReadUInt32(r, n, err) numSigs := ReadUInt32(r, n, err)
numAdjs := ReadUInt32(r, n, err)
sigs := make([]Signature, 0, numSigs) sigs := make([]Signature, 0, numSigs)
for i := uint32(0); i < numSigs; i++ { for i := uint32(0); i < numSigs; i++ {
sigs = append(sigs, ReadSignature(r, n, err)) sigs = append(sigs, ReadSignature(r, n, err))
} }
tx := make([]Tx, 0, numAdjs)
for i := uint32(0); i < numAdjs; i++ {
tx = append(tx, ReadTx(r, n, err))
}
return Validation{ return Validation{
Signatures: sigs, Signatures: sigs,
Txs: tx,
} }
} }
func (v *Validation) WriteTo(w io.Writer) (n int64, err error) { func (v *Validation) WriteTo(w io.Writer) (n int64, err error) {
WriteUInt32(w, uint32(len(v.Signatures)), &n, &err) WriteUInt32(w, uint32(len(v.Signatures)), &n, &err)
WriteUInt32(w, uint32(len(v.Txs)), &n, &err)
for _, sig := range v.Signatures { for _, sig := range v.Signatures {
WriteBinary(w, sig, &n, &err) WriteBinary(w, sig, &n, &err)
} }
for _, tx := range v.Txs {
WriteBinary(w, tx, &n, &err)
}
return return
} }
@ -239,40 +243,41 @@ func (v *Validation) Hash() []byte {
} }
} }
/* Txs is part of a block */
type Txs struct {
//-----------------------------------------------------------------------------
type Data struct {
Txs []Tx Txs []Tx
// Volatile // Volatile
hash []byte hash []byte
} }
func ReadTxs(r io.Reader, n *int64, err *error) Txs {
func ReadData(r io.Reader, n *int64, err *error) Data {
numTxs := ReadUInt32(r, n, err) numTxs := ReadUInt32(r, n, err)
txs := make([]Tx, 0, numTxs) txs := make([]Tx, 0, numTxs)
for i := uint32(0); i < numTxs; i++ { for i := uint32(0); i < numTxs; i++ {
txs = append(txs, ReadTx(r, n, err)) txs = append(txs, ReadTx(r, n, err))
} }
return Txs{Txs: txs}
return Data{Txs: txs}
} }
func (txs *Txs) WriteTo(w io.Writer) (n int64, err error) {
WriteUInt32(w, uint32(len(txs.Txs)), &n, &err)
for _, tx := range txs.Txs {
func (data *Data) WriteTo(w io.Writer) (n int64, err error) {
WriteUInt32(w, uint32(len(data.Txs)), &n, &err)
for _, tx := range data.Txs {
WriteBinary(w, tx, &n, &err) WriteBinary(w, tx, &n, &err)
} }
return return
} }
func (txs *Txs) Hash() []byte {
if txs.hash != nil {
return txs.hash
func (data *Data) Hash() []byte {
if data.hash != nil {
return data.hash
} else { } else {
bs := make([]Binary, 0, len(txs.Txs))
for i, tx := range txs.Txs {
bs := make([]Binary, 0, len(data.Txs))
for i, tx := range data.Txs {
bs[i] = Binary(tx) bs[i] = Binary(tx)
} }
txs.hash = merkle.HashFromBinarySlice(bs)
return txs.hash
data.hash = merkle.HashFromBinarySlice(bs)
return data.hash
} }
} }

+ 4
- 5
blocks/block_test.go View File

@ -63,7 +63,7 @@ func TestBlock(t *testing.T) {
PubKey: randBytes(32), PubKey: randBytes(32),
} }
// Consensus Txs
// Validation Txs
bond := &Bond{ bond := &Bond{
Signature: randSig(), Signature: randSig(),
@ -106,15 +106,14 @@ func TestBlock(t *testing.T) {
Time: randTime(), Time: randTime(),
PrevHash: randBytes(32), PrevHash: randBytes(32),
ValidationHash: randBytes(32), ValidationHash: randBytes(32),
TxsHash: randBytes(32),
DataHash: randBytes(32),
}, },
Validation: Validation{ Validation: Validation{
Signatures: []Signature{randSig(), randSig()}, Signatures: []Signature{randSig(), randSig()},
Txs: []Txs{bond, unbond, timeout, dupeout}, Txs: []Txs{bond, unbond, timeout, dupeout},
}, },
Txs: Txs{
Txs: []Tx{sendTx, nameTx},
hash: nil,
Data: Data{
Txs: []Tx{sendTx, nameTx},
}, },
} }


+ 6
- 6
blocks/codec_test.go View File

@ -21,7 +21,7 @@ func BenchmarkTestCustom(b *testing.B) {
Time: time.Unix(123, 0), Time: time.Unix(123, 0),
PrevHash: []byte("prevhash"), PrevHash: []byte("prevhash"),
ValidationHash: []byte("validationhash"), ValidationHash: []byte("validationhash"),
TxsHash: []byte("txshash"),
DataHash: []byte("datahash"),
} }
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)
@ -46,7 +46,7 @@ type HHeader struct {
Time uint64 `json:"T"` Time uint64 `json:"T"`
PrevHash []byte `json:"PH"` PrevHash []byte `json:"PH"`
ValidationHash []byte `json:"VH"` ValidationHash []byte `json:"VH"`
TxsHash []byte `json:"DH"`
DataHash []byte `json:"DH"`
} }
func BenchmarkTestJSON(b *testing.B) { func BenchmarkTestJSON(b *testing.B) {
@ -59,7 +59,7 @@ func BenchmarkTestJSON(b *testing.B) {
Time: 123, Time: 123,
PrevHash: []byte("prevhash"), PrevHash: []byte("prevhash"),
ValidationHash: []byte("validationhash"), ValidationHash: []byte("validationhash"),
TxsHash: []byte("txshash"),
DataHash: []byte("datahash"),
} }
h2 := &HHeader{} h2 := &HHeader{}
@ -88,7 +88,7 @@ func BenchmarkTestGob(b *testing.B) {
Time: time.Unix(123, 0), Time: time.Unix(123, 0),
PrevHash: []byte("prevhash"), PrevHash: []byte("prevhash"),
ValidationHash: []byte("validationhash"), ValidationHash: []byte("validationhash"),
TxsHash: []byte("txshash"),
DataHash: []byte("datahash"),
} }
h2 := &Header{} h2 := &Header{}
@ -117,7 +117,7 @@ func BenchmarkTestMsgPack(b *testing.B) {
Time: time.Unix(123, 0), Time: time.Unix(123, 0),
PrevHash: []byte("prevhash"), PrevHash: []byte("prevhash"),
ValidationHash: []byte("validationhash"), ValidationHash: []byte("validationhash"),
TxsHash: []byte("txshash"),
DataHash: []byte("datahash"),
} }
h2 := &Header{} h2 := &Header{}
@ -146,7 +146,7 @@ func BenchmarkTestMsgPack2(b *testing.B) {
Time: time.Unix(123, 0), Time: time.Unix(123, 0),
PrevHash: []byte("prevhash"), PrevHash: []byte("prevhash"),
ValidationHash: []byte("validationhash"), ValidationHash: []byte("validationhash"),
TxsHash: []byte("txshash"),
DataHash: []byte("datahash"),
} }
h2 := &Header{} h2 := &Header{}
var mh codec.MsgpackHandle var mh codec.MsgpackHandle


+ 3
- 3
blocks/tx.go View File

@ -22,7 +22,7 @@ Account Txs:
1. Send Send coins to account 1. Send Send coins to account
2. Name Associate account with a name 2. Name Associate account with a name
Consensus Txs:
Validation Txs:
3. Bond New validator posts a bond 3. Bond New validator posts a bond
4. Unbond Validator leaves 4. Unbond Validator leaves
5. Timeout Validator times out 5. Timeout Validator times out
@ -35,7 +35,7 @@ type Tx interface {
Type() byte Type() byte
GetSequence() uint64 GetSequence() uint64
GetSignature() *Signature GetSignature() *Signature
//IsConsensus() bool
//IsValidation() bool
Binary Binary
} }
@ -44,7 +44,7 @@ const (
TX_TYPE_SEND = byte(0x01) TX_TYPE_SEND = byte(0x01)
TX_TYPE_NAME = byte(0x02) TX_TYPE_NAME = byte(0x02)
// Consensus transactions
// Validation transactions
TX_TYPE_BOND = byte(0x11) TX_TYPE_BOND = byte(0x11)
TX_TYPE_UNBOND = byte(0x12) TX_TYPE_UNBOND = byte(0x12)
TX_TYPE_TIMEOUT = byte(0x13) TX_TYPE_TIMEOUT = byte(0x13)


+ 67
- 16
mempool/mempool.go View File

@ -1,12 +1,3 @@
package mempool
import (
"sync"
. "github.com/tendermint/tendermint/blocks"
. "github.com/tendermint/tendermint/state"
)
/* /*
Mempool receives new transactions and applies them to the latest committed state. Mempool receives new transactions and applies them to the latest committed state.
If the transaction is acceptable, then it broadcasts a fingerprint to peers. If the transaction is acceptable, then it broadcasts a fingerprint to peers.
@ -20,24 +11,33 @@ When this node happens to be the next proposer, it simply takes the recently
modified state (and the associated transactions) and use that as the proposal. modified state (and the associated transactions) and use that as the proposal.
*/ */
//-----------------------------------------------------------------------------
package mempool
import (
"sync"
. "github.com/tendermint/tendermint/blocks"
. "github.com/tendermint/tendermint/state"
)
type Mempool struct { type Mempool struct {
mtx sync.Mutex
state *State
txs []Tx
mtx sync.Mutex
lastBlock *Block
state *State
txs []Tx
} }
func NewMempool(state *State) *Mempool {
func NewMempool(lastBlock *Block, state *State) *Mempool {
return &Mempool{ return &Mempool{
state: state,
lastBlock: lastBlock,
state: state,
} }
} }
// Apply tx to the state and remember it.
func (mem *Mempool) AddTx(tx Tx) (err error) { func (mem *Mempool) AddTx(tx Tx) (err error) {
mem.mtx.Lock() mem.mtx.Lock()
defer mem.mtx.Unlock() defer mem.mtx.Unlock()
// Add the tx to the state.
err = mem.state.CommitTx(tx) err = mem.state.CommitTx(tx)
if err != nil { if err != nil {
return err return err
@ -46,3 +46,54 @@ func (mem *Mempool) AddTx(tx Tx) (err error) {
return nil return nil
} }
} }
// Returns a new block from the current state and associated transactions.
// The block's Validation is empty, and some parts of the header too.
func (mem *Mempool) MakeProposal() (*Block, *State) {
mem.mtx.Lock()
defer mem.mtx.Unlock()
nextBlock := mem.lastBlock.MakeNextBlock()
nextBlock.Data.Txs = mem.txs
return nextBlock, mem.state
}
// Txs that are present in block are discarded from mempool.
// Txs that have become invalid in the new state are also discarded.
func (mem *Mempool) ResetForBlockandState(block *Block, state *State) {
mem.mtx.Lock()
defer mem.mtx.Unlock()
mem.lastBlock = block
mem.state = state.Copy()
// First, create a lookup map of txns in new block.
blockTxsMap := make(map[string]struct{})
for _, tx := range block.Data.Txs {
txHash := BinaryHash(tx)
blockTxsMap[string(txHash)] = struct{}{}
}
// Next, filter all txs from mem.txs that are in blockTxsMap
txs := []Tx{}
for _, tx := range mem.txs {
txHash := BinaryHash(tx)
if _, ok := blockTxsMap[string(txHash)]; ok {
continue
} else {
txs = append(txs, tx)
}
}
// Next, filter all txs that aren't valid given new state.
validTxs := []Tx{}
for _, tx := range txs {
err := mem.state.CommitTx(tx)
if err != nil {
validTxs = append(validTxs, tx)
} else {
// tx is no longer valid.
}
}
// We're done!
mem.txs = validTxs
}

Loading…
Cancel
Save