Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

R4R: Fixed Length TxBytes #118

Merged
merged 8 commits into from
Mar 2, 2019
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Query sidechain state
- Plasma configuration file
### Changed
- Fixed Length TxBytes (811), compatible with rootchain v1.0.0
- Made UTXO model modular
- Transaction verification to be compatible with rootchain
- Decrease dependency on amino encoding
Expand Down
129 changes: 92 additions & 37 deletions plasma/transaction.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package plasma

import (
"bytes"
"crypto/sha256"
"fmt"
"github.com/FourthState/plasma-mvp-sidechain/utils"
Expand All @@ -21,21 +22,21 @@ type Transaction struct {
}

type txList struct {
BlkNum0 []byte
TxIndex0 uint16
OIndex0 uint8
DepositNonce0 []byte
Input0ConfirmSigs [][65]byte
BlkNum1 []byte
TxIndex1 uint16
OIndex1 uint8
DepositNonce1 []byte
Input1ConfirmSigs [][65]byte
BlkNum0 [32]byte
TxIndex0 [32]byte
OIndex0 [32]byte
DepositNonce0 [32]byte
Input0ConfirmSigs [130]byte
BlkNum1 [32]byte
TxIndex1 [32]byte
OIndex1 [32]byte
DepositNonce1 [32]byte
Input1ConfirmSigs [130]byte
NewOwner0 common.Address
Amount0 []byte
Amount0 [32]byte
NewOwner1 common.Address
Amount1 []byte
Fee []byte
Amount1 [32]byte
Fee [32]byte
}

type rawTx struct {
Expand All @@ -57,14 +58,17 @@ func (tx *Transaction) DecodeRLP(s *rlp.Stream) error {
return err
}

tx.Input0 = NewInput(NewPosition(new(big.Int).SetBytes(t.Tx.BlkNum0), t.Tx.TxIndex0, t.Tx.OIndex0, new(big.Int).SetBytes(t.Tx.DepositNonce0)),
t.Sigs[0], t.Tx.Input0ConfirmSigs)
tx.Input1 = NewInput(NewPosition(new(big.Int).SetBytes(t.Tx.BlkNum1), t.Tx.TxIndex1, t.Tx.OIndex1, new(big.Int).SetBytes(t.Tx.DepositNonce1)),
t.Sigs[1], t.Tx.Input1ConfirmSigs)
confirmSigs0 := parseSig(t.Tx.Input0ConfirmSigs)
confirmSigs1 := parseSig(t.Tx.Input1ConfirmSigs)

tx.Input0 = NewInput(NewPosition(big.NewInt(new(big.Int).SetBytes(t.Tx.BlkNum0[:]).Int64()), uint16(new(big.Int).SetBytes(t.Tx.TxIndex0[:]).Int64()), uint8(new(big.Int).SetBytes(t.Tx.OIndex0[:]).Int64()), big.NewInt(new(big.Int).SetBytes(t.Tx.DepositNonce0[:]).Int64())),
t.Sigs[0], confirmSigs0)
tx.Input1 = NewInput(NewPosition(big.NewInt(new(big.Int).SetBytes(t.Tx.BlkNum1[:]).Int64()), uint16(new(big.Int).SetBytes(t.Tx.TxIndex1[:]).Int64()), uint8(new(big.Int).SetBytes(t.Tx.OIndex1[:]).Int64()), big.NewInt(new(big.Int).SetBytes(t.Tx.DepositNonce1[:]).Int64())),
t.Sigs[1], confirmSigs1)
// set signatures if applicable
tx.Output0 = NewOutput(t.Tx.NewOwner0, new(big.Int).SetBytes(t.Tx.Amount0))
tx.Output1 = NewOutput(t.Tx.NewOwner1, new(big.Int).SetBytes(t.Tx.Amount1))
tx.Fee = new(big.Int).SetBytes(t.Tx.Fee)
tx.Output0 = NewOutput(t.Tx.NewOwner0, big.NewInt(new(big.Int).SetBytes(t.Tx.Amount0[:]).Int64()))
tx.Output1 = NewOutput(t.Tx.NewOwner1, big.NewInt(new(big.Int).SetBytes(t.Tx.Amount1[:]).Int64()))
tx.Fee = big.NewInt(new(big.Int).SetBytes(t.Tx.Fee[:]).Int64())

return nil
}
Expand Down Expand Up @@ -155,7 +159,7 @@ func (tx Transaction) toTxList() txList {

// pointer safety if a transaction
// object was ever created with Transaction{}

txList := txList{}
if tx.Input0.BlockNum == nil {
tx.Input0.BlockNum = utils.Big0
} else if tx.Input1.BlockNum == nil {
Expand All @@ -178,21 +182,72 @@ func (tx Transaction) toTxList() txList {
tx.Fee = utils.Big0
}

return txList{
BlkNum0: tx.Input0.BlockNum.Bytes(),
TxIndex0: tx.Input0.TxIndex,
OIndex0: tx.Input0.OutputIndex,
DepositNonce0: tx.Input0.DepositNonce.Bytes(),
Input0ConfirmSigs: tx.Input0.ConfirmSignatures,
BlkNum1: tx.Input1.BlockNum.Bytes(),
TxIndex1: tx.Input1.TxIndex,
OIndex1: tx.Input1.OutputIndex,
DepositNonce1: tx.Input1.DepositNonce.Bytes(),
Input1ConfirmSigs: tx.Input1.ConfirmSignatures,
NewOwner0: tx.Output0.Owner,
Amount0: tx.Output0.Amount.Bytes(),
NewOwner1: tx.Output1.Owner,
Amount1: tx.Output1.Amount.Bytes(),
Fee: tx.Fee.Bytes(),
// fill in txList with values
// Input 0
if len(tx.Input0.BlockNum.Bytes()) > 0 {
copy(txList.BlkNum0[32-len(tx.Input0.BlockNum.Bytes()):], tx.Input0.BlockNum.Bytes())
}
txList.TxIndex0[31] = byte(tx.Input0.TxIndex)
txList.TxIndex0[30] = byte(tx.Input0.TxIndex >> 8)
txList.OIndex0[31] = byte(tx.Input0.OutputIndex)
if len(tx.Input0.DepositNonce.Bytes()) > 0 {
copy(txList.DepositNonce0[32-len(tx.Input0.DepositNonce.Bytes()):], tx.Input0.DepositNonce.Bytes())
}
switch len(tx.Input0.ConfirmSignatures) {
case 1:
copy(txList.Input0ConfirmSigs[:65], tx.Input0.ConfirmSignatures[0][:])
case 2:
copy(txList.Input0ConfirmSigs[:65], tx.Input0.ConfirmSignatures[0][:])
copy(txList.Input0ConfirmSigs[65:], tx.Input0.ConfirmSignatures[1][:])
}

// Input 1
if len(tx.Input1.BlockNum.Bytes()) > 0 {
copy(txList.BlkNum1[32-len(tx.Input1.BlockNum.Bytes()):], tx.Input1.BlockNum.Bytes())
}
txList.TxIndex1[31] = byte(tx.Input1.TxIndex)
txList.TxIndex1[30] = byte(tx.Input1.TxIndex >> 8)
txList.OIndex1[31] = byte(tx.Input1.OutputIndex)
if len(tx.Input1.DepositNonce.Bytes()) > 0 {
copy(txList.DepositNonce1[32-len(tx.Input1.DepositNonce.Bytes()):], tx.Input1.DepositNonce.Bytes())
}

switch len(tx.Input1.ConfirmSignatures) {
case 1:
copy(txList.Input1ConfirmSigs[:65], tx.Input1.ConfirmSignatures[0][:])
case 2:
copy(txList.Input1ConfirmSigs[:65], tx.Input1.ConfirmSignatures[0][:])
copy(txList.Input1ConfirmSigs[65:], tx.Input1.ConfirmSignatures[1][:])
}

// Outputs and Fee
txList.NewOwner0 = tx.Output0.Owner
if len(tx.Output0.Amount.Bytes()) > 0 {
copy(txList.Amount0[32-len(tx.Output0.Amount.Bytes()):], tx.Output0.Amount.Bytes())
}
txList.NewOwner1 = tx.Output1.Owner
if len(tx.Output1.Amount.Bytes()) > 0 {
copy(txList.Amount1[32-len(tx.Output1.Amount.Bytes()):], tx.Output1.Amount.Bytes())
}
if len(tx.Fee.Bytes()) > 0 {
copy(txList.Fee[32-len(tx.Fee.Bytes()):], tx.Fee.Bytes())
}
return txList
}

// Helpers
// Convert 130 byte input confirm sigs to 65 byte slices
func parseSig(sig [130]byte) [][65]byte {
if bytes.Equal(sig[:65], make([]byte, 65)) {
return [][65]byte{}
} else if bytes.Equal(sig[65:], make([]byte, 65)) {
newSig := make([][65]byte, 1)
copy(newSig[0][:], sig[:65])
return newSig
} else {
newSig := make([][65]byte, 2)
copy(newSig[0][:], sig[:65])
copy(newSig[1][:], sig[65:])
return newSig
}
}
15 changes: 11 additions & 4 deletions plasma/transaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,29 @@ func TestTransactionSerialization(t *testing.T) {

// contstruct a transaction
tx := &Transaction{}
pos, _ := FromPositionString("(1.1.1.1)")
tx.Input0 = NewInput(pos, [65]byte{}, nil)
pos, _ := FromPositionString("(1.10000.1.0)")
confirmSig0 := make([][65]byte, 1)
copy(confirmSig0[0][65-len([]byte("confirm sig")):], []byte("confirm sig"))
tx.Input0 = NewInput(pos, [65]byte{}, confirmSig0)
tx.Input0.Signature[1] = byte(1)
pos, _ = FromPositionString("(0.0.0.0)")
tx.Input1 = NewInput(pos, [65]byte{}, nil)
pos, _ = FromPositionString("(0.0.0.1)")
confirmSig1 := make([][65]byte, 2)
copy(confirmSig1[0][65-len([]byte("the second confirm sig")):], []byte("the second confirm sig"))
copy(confirmSig1[1][65-len([]byte("a very long string turned into bytes")):], []byte("a very long string turned into bytes"))
tx.Input1 = NewInput(pos, [65]byte{}, confirmSig1)
tx.Output0 = NewOutput(common.HexToAddress("1"), one)
tx.Output1 = NewOutput(common.HexToAddress("0"), zero)
tx.Fee = big.NewInt(1)

bytes, err := rlp.EncodeToBytes(tx)
require.NoError(t, err, "error serializing transaction")
require.Equal(t, 811, len(bytes), "encoded bytes should sum to 811")

recoveredTx := &Transaction{}
err = rlp.DecodeBytes(bytes, recoveredTx)
require.NoError(t, err, "error deserializing transaction")

require.EqualValues(t, tx, recoveredTx, "serialized and deserialized transaction not deeply equal")
require.True(t, reflect.DeepEqual(tx, recoveredTx), "serialized and deserialized transactions not deeply equal")
}

Expand Down