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 {
Header
Validation
Txs
Data
// Volatile
hash []byte
@ -27,14 +27,14 @@ func ReadBlock(r io.Reader, n *int64, err *error) *Block {
return &Block{
Header: ReadHeader(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) {
WriteBinary(w, &b.Header, &n, &err)
WriteBinary(w, &b.Validation, &n, &err)
WriteBinary(w, &b.Txs, &n, &err)
WriteBinary(w, &b.Data, &n, &err)
return
}
@ -50,7 +50,7 @@ func (b *Block) Hash() []byte {
hashes := [][]byte{
b.Header.Hash(),
b.Validation.Hash(),
b.Txs.Hash(),
b.Data.Hash(),
}
// Merkle hash from sub-hashes.
return merkle.HashFromByteSlices(hashes)
@ -79,6 +79,21 @@ func (b *Block) ToBlockPartSet() *BlockPartSet {
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 {
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
hash []byte
@ -152,13 +166,13 @@ func ReadHeader(r io.Reader, n *int64, err *error) (h 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)
WriteTime(w, h.Time, &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
}
@ -187,10 +201,10 @@ func (h *Header) Hash() []byte {
}
}
/* Validation is part of a block */
//-----------------------------------------------------------------------------
type Validation struct {
Signatures []Signature
Txs []Tx
// Volatile
hash []byte
@ -198,30 +212,20 @@ type Validation struct {
func ReadValidation(r io.Reader, n *int64, err *error) Validation {
numSigs := ReadUInt32(r, n, err)
numAdjs := ReadUInt32(r, n, err)
sigs := make([]Signature, 0, numSigs)
for i := uint32(0); i < numSigs; i++ {
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{
Signatures: sigs,
Txs: tx,
}
}
func (v *Validation) WriteTo(w io.Writer) (n int64, err error) {
WriteUInt32(w, uint32(len(v.Signatures)), &n, &err)
WriteUInt32(w, uint32(len(v.Txs)), &n, &err)
for _, sig := range v.Signatures {
WriteBinary(w, sig, &n, &err)
}
for _, tx := range v.Txs {
WriteBinary(w, tx, &n, &err)
}
return
}
@ -239,40 +243,41 @@ func (v *Validation) Hash() []byte {
}
}
/* Txs is part of a block */
type Txs struct {
//-----------------------------------------------------------------------------
type Data struct {
Txs []Tx
// Volatile
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)
txs := make([]Tx, 0, numTxs)
for i := uint32(0); i < numTxs; i++ {
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)
}
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 {
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)
}
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),
}
// Consensus Txs
// Validation Txs
bond := &Bond{
Signature: randSig(),
@ -106,15 +106,14 @@ func TestBlock(t *testing.T) {
Time: randTime(),
PrevHash: randBytes(32),
ValidationHash: randBytes(32),
TxsHash: randBytes(32),
DataHash: randBytes(32),
},
Validation: Validation{
Signatures: []Signature{randSig(), randSig()},
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),
PrevHash: []byte("prevhash"),
ValidationHash: []byte("validationhash"),
TxsHash: []byte("txshash"),
DataHash: []byte("datahash"),
}
buf := bytes.NewBuffer(nil)
@ -46,7 +46,7 @@ type HHeader struct {
Time uint64 `json:"T"`
PrevHash []byte `json:"PH"`
ValidationHash []byte `json:"VH"`
TxsHash []byte `json:"DH"`
DataHash []byte `json:"DH"`
}
func BenchmarkTestJSON(b *testing.B) {
@ -59,7 +59,7 @@ func BenchmarkTestJSON(b *testing.B) {
Time: 123,
PrevHash: []byte("prevhash"),
ValidationHash: []byte("validationhash"),
TxsHash: []byte("txshash"),
DataHash: []byte("datahash"),
}
h2 := &HHeader{}
@ -88,7 +88,7 @@ func BenchmarkTestGob(b *testing.B) {
Time: time.Unix(123, 0),
PrevHash: []byte("prevhash"),
ValidationHash: []byte("validationhash"),
TxsHash: []byte("txshash"),
DataHash: []byte("datahash"),
}
h2 := &Header{}
@ -117,7 +117,7 @@ func BenchmarkTestMsgPack(b *testing.B) {
Time: time.Unix(123, 0),
PrevHash: []byte("prevhash"),
ValidationHash: []byte("validationhash"),
TxsHash: []byte("txshash"),
DataHash: []byte("datahash"),
}
h2 := &Header{}
@ -146,7 +146,7 @@ func BenchmarkTestMsgPack2(b *testing.B) {
Time: time.Unix(123, 0),
PrevHash: []byte("prevhash"),
ValidationHash: []byte("validationhash"),
TxsHash: []byte("txshash"),
DataHash: []byte("datahash"),
}
h2 := &Header{}
var mh codec.MsgpackHandle


+ 3
- 3
blocks/tx.go View File

@ -22,7 +22,7 @@ Account Txs:
1. Send Send coins to account
2. Name Associate account with a name
Consensus Txs:
Validation Txs:
3. Bond New validator posts a bond
4. Unbond Validator leaves
5. Timeout Validator times out
@ -35,7 +35,7 @@ type Tx interface {
Type() byte
GetSequence() uint64
GetSignature() *Signature
//IsConsensus() bool
//IsValidation() bool
Binary
}
@ -44,7 +44,7 @@ const (
TX_TYPE_SEND = byte(0x01)
TX_TYPE_NAME = byte(0x02)
// Consensus transactions
// Validation transactions
TX_TYPE_BOND = byte(0x11)
TX_TYPE_UNBOND = byte(0x12)
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.
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.
*/
//-----------------------------------------------------------------------------
package mempool
import (
"sync"
. "github.com/tendermint/tendermint/blocks"
. "github.com/tendermint/tendermint/state"
)
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{
state: state,
lastBlock: lastBlock,
state: state,
}
}
// Apply tx to the state and remember it.
func (mem *Mempool) AddTx(tx Tx) (err error) {
mem.mtx.Lock()
defer mem.mtx.Unlock()
// Add the tx to the state.
err = mem.state.CommitTx(tx)
if err != nil {
return err
@ -46,3 +46,54 @@ func (mem *Mempool) AddTx(tx Tx) (err error) {
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