Skip to content
This repository has been archived by the owner on May 13, 2022. It is now read-only.

Commit

Permalink
Use TxHash for contract address generation.
Browse files Browse the repository at this point in the history
This gives us more predictable addresses for proposal mechanism.

Signed-off-by: Silas Davis <silas@monax.io>
  • Loading branch information
Silas Davis committed Nov 23, 2018
1 parent b9988e6 commit 381ed8a
Show file tree
Hide file tree
Showing 9 changed files with 32 additions and 59 deletions.
13 changes: 6 additions & 7 deletions crypto/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import (
"encoding/json"
"fmt"

"github.com/tendermint/tendermint/crypto/tmhash"

"github.com/hyperledger/burrow/binary"
"github.com/tmthrgd/go-hex"
"golang.org/x/crypto/ripemd160"
)

type Addressable interface {
Expand Down Expand Up @@ -186,12 +187,10 @@ func (address *Address) Size() int {
return binary.Word160Length
}

func NewContractAddress(caller Address, sequence uint64) (newAddr Address) {
temp := make([]byte, 32+8)
copy(temp, caller[:])
binary.PutUint64BE(temp[32:], uint64(sequence))
hasher := ripemd160.New()
hasher.Write(temp) // does not error
func NewContractAddress(caller Address, nonce []byte) (newAddr Address) {
hasher := tmhash.New()
hasher.Write(caller[:]) // does not error
hasher.Write(nonce)
copy(newAddr[:], hasher.Sum(nil))
return
}
8 changes: 3 additions & 5 deletions crypto/address_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,11 @@ func TestNewContractAddress(t *testing.T) {
53, 100, 101, 250, 227,
60, 64, 108, 226, 194,
151, 157, 230, 11, 203,
}, 1)
}, []byte{1})

assert.Equal(t, Address{
73, 234, 48, 252, 174,
115, 27, 222, 54, 116,
47, 133, 144, 21, 73,
245, 21, 234, 26, 50,
0xe2, 0x9d, 0x64, 0x7d, 0xce, 0xd6, 0x48, 0x12, 0xd4, 0x44,
0xa6, 0x7d, 0x80, 0x5, 0xcd, 0x6, 0x9, 0xb2, 0x2f, 0x49,
}, addr)
}

Expand Down
13 changes: 1 addition & 12 deletions execution/contexts/call_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,21 +109,11 @@ func (ctx *CallContext) Precheck() (*acm.Account, *acm.Account, error) {
}

func (ctx *CallContext) Check(inAcc *acm.Account, value uint64) error {
createContract := ctx.tx.Address == nil
// The mempool does not call txs until
// the proposer determines the order of txs.
// So mempool will skip the actual .Call(),
// and only deduct from the caller's balance.
inAcc.Balance -= value
if createContract {
// This is done by DeriveNewAccount when runCall == true
ctx.Logger.TraceMsg("Incrementing sequence number since creates contract",
"tag", "sequence",
"account", inAcc.Address,
"old_sequence", inAcc.Sequence,
"new_sequence", inAcc.Sequence+1)
inAcc.Sequence++
}
err := ctx.StateWriter.UpdateAccount(inAcc)
if err != nil {
return err
Expand Down Expand Up @@ -152,8 +142,7 @@ func (ctx *CallContext) Deliver(inAcc, outAcc *acm.Account, value uint64) error
// get or create callee
if createContract {
// We already checked for permission
txCache.IncSequence(caller)
callee = crypto.NewContractAddress(caller, txCache.GetSequence(caller))
callee = crypto.NewContractAddress(caller, ctx.txe.TxHash)
code = ctx.tx.Data
txCache.CreateAccount(callee)
ctx.Logger.TraceMsg("Creating new contract",
Expand Down
10 changes: 0 additions & 10 deletions execution/evm/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ type Writer interface {
UnsetPermission(address crypto.Address, permFlag permission.PermFlag)
AddRole(address crypto.Address, role string) bool
RemoveRole(address crypto.Address, role string) bool
IncSequence(address crypto.Address)
}

type State struct {
Expand Down Expand Up @@ -265,15 +264,6 @@ func (st *State) RemoveRole(address crypto.Address, role string) bool {
return removed
}

func (st *State) IncSequence(address crypto.Address) {
acc := st.mustAccount(address)
if acc == nil {
return
}
acc.Sequence++
st.updateAccount(acc)
}

// Helpers

func (st *State) account(address crypto.Address) *acm.Account {
Expand Down
5 changes: 0 additions & 5 deletions execution/evm/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,13 @@ func TestState_Sync(t *testing.T) {
st.CreateAccount(address)
amt := uint64(1232)
st.AddToBalance(address, amt)
st.IncSequence(address)
require.Nil(t, st.Error())

var err error
err = st.Sync()
require.Nil(t, err)
acc, err := backend.GetAccount(address)
require.NoError(t, err)
assert.Equal(t, acc.Balance, amt)
assert.Equal(t, uint64(1), acc.Sequence)
}

func TestState_NewCache(t *testing.T) {
Expand All @@ -64,8 +61,6 @@ func TestState_NewCache(t *testing.T) {
cache.CreateAccount(address)
amt := uint64(1232)
cache.AddToBalance(address, amt)
cache.IncSequence(address)
require.Nil(t, st.Error())

var err error
assert.Equal(t, uint64(0), st.GetBalance(address))
Expand Down
11 changes: 8 additions & 3 deletions execution/evm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import (

const (
DataStackInitialCapacity = 1024
callStackCapacity = 100 // TODO ensure usage.
uint64Length = 8
)

type Params struct {
Expand All @@ -58,6 +58,7 @@ type VM struct {
logger *logging.Logger
debugOpcodes bool
dumpTokens bool
sequence uint64
}

func NewVM(params Params, origin crypto.Address, tx *txs.Tx, logger *logging.Logger, options ...func(*VM)) *VM {
Expand Down Expand Up @@ -741,8 +742,12 @@ func (vm *VM) execute(callState Interface, eventSink EventSink, caller, callee c

// TODO charge for gas to create account _ the code length * GasCreateByte
useGasNegative(gas, GasCreateAccount, callState)
callState.IncSequence(callee)
newAccount := crypto.NewContractAddress(callee, callState.GetSequence(callee))

vm.sequence++
nonce := make([]byte, txs.HashLength+uint64Length)
copy(nonce, vm.tx.Hash())
PutUint64BE(nonce[txs.HashLength:], vm.sequence)
newAccount := crypto.NewContractAddress(callee, nonce)

// Check the CreateContract permission for this account
EnsurePermission(callState, callee, permission.CreateContract)
Expand Down
18 changes: 11 additions & 7 deletions execution/execution_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ func TestCallPermission(t *testing.T) {
fmt.Println("\n##### SIMPLE CONTRACT")

// create simple contract
simpleContractAddr := crypto.NewContractAddress(users[0].GetAddress(), 100)
simpleContractAddr := crypto.NewContractAddress(users[0].GetAddress(), []byte{100})
simpleAcc := &acm.Account{
Address: simpleContractAddr,
Balance: 0,
Expand All @@ -327,7 +327,7 @@ func TestCallPermission(t *testing.T) {

// create contract that calls the simple contract
contractCode := callContractCode(simpleContractAddr)
caller1ContractAddr := crypto.NewContractAddress(users[0].GetAddress(), 101)
caller1ContractAddr := crypto.NewContractAddress(users[0].GetAddress(), []byte{101})
caller1Acc := &acm.Account{
Address: caller1ContractAddr,
Balance: 10000,
Expand Down Expand Up @@ -368,7 +368,7 @@ func TestCallPermission(t *testing.T) {
fmt.Println("\n##### CALL TO CONTRACT CALLING SIMPLE CONTRACT (FAIL)")

contractCode2 := callContractCode(caller1ContractAddr)
caller2ContractAddr := crypto.NewContractAddress(users[0].GetAddress(), 102)
caller2ContractAddr := crypto.NewContractAddress(users[0].GetAddress(), []byte{102})
caller2Acc := &acm.Account{
Address: caller2ContractAddr,
Balance: 1000,
Expand Down Expand Up @@ -432,7 +432,7 @@ func TestCreatePermission(t *testing.T) {
require.NoError(t, err)

// ensure the contract is there
contractAddr := crypto.NewContractAddress(tx.Input.Address, tx.Input.Sequence)
contractAddr := crypto.NewContractAddress(tx.Input.Address, txHash(tx))
contractAcc := getAccount(exe.stateCache, contractAddr)
if contractAcc == nil {
t.Fatalf("failed to create contract %s", contractAddr)
Expand All @@ -456,7 +456,7 @@ func TestCreatePermission(t *testing.T) {
require.NoError(t, err)

// ensure the contract is there
contractAddr = crypto.NewContractAddress(tx.Input.Address, tx.Input.Sequence)
contractAddr = crypto.NewContractAddress(tx.Input.Address, txHash(tx))
contractAcc = getAccount(exe.stateCache, contractAddr)
if contractAcc == nil {
t.Fatalf("failed to create contract %s", contractAddr)
Expand Down Expand Up @@ -496,7 +496,7 @@ func TestCreatePermission(t *testing.T) {
fmt.Println("\n##### CALL to empty address")
code := callContractCode(crypto.Address{})

contractAddr = crypto.NewContractAddress(users[0].GetAddress(), 110)
contractAddr = crypto.NewContractAddress(users[0].GetAddress(), []byte{110})
contractAcc = &acm.Account{
Address: contractAddr,
Balance: 1000,
Expand Down Expand Up @@ -609,7 +609,7 @@ func TestCreateAccountPermission(t *testing.T) {
// call to contract that calls unknown account - without create_account perm
// create contract that calls the simple contract
contractCode := callContractCode(users[9].GetAddress())
caller1ContractAddr := crypto.NewContractAddress(users[4].GetAddress(), 101)
caller1ContractAddr := crypto.NewContractAddress(users[4].GetAddress(), []byte{101})
caller1Acc := &acm.Account{
Address: caller1ContractAddr,
Balance: 0,
Expand Down Expand Up @@ -1597,6 +1597,10 @@ func (te *testExecutor) updateAccounts(t *testing.T, accounts ...*acm.Account) {
}
}

func txHash(tx payload.Payload) []byte {
return txs.Enclose(testChainID, tx).Tx.Hash()
}

func (te *testExecutor) signExecuteCommit(tx payload.Payload, signers ...acm.AddressableSigner) error {
txEnv := txs.Enclose(testChainID, tx)
err := txEnv.Sign(signers...)
Expand Down
9 changes: 0 additions & 9 deletions txs/payload/call_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,6 @@ func (tx *CallTx) String() string {
return fmt.Sprintf("CallTx{%v -> %s: %v}", tx.Input, tx.Address, tx.Data)
}

// Returns the contract address that this CallTx would create if CallTx.Address == nil otherwise returns nil
func (tx *CallTx) CreatesContractAddress() *crypto.Address {
if tx.Address != nil {
return nil
}
address := crypto.NewContractAddress(tx.Input.Address, tx.Input.Sequence)
return &address
}

func (tx *CallTx) Any() *Any {
return &Any{
CallTx: tx,
Expand Down
4 changes: 3 additions & 1 deletion txs/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import (
"github.com/hyperledger/burrow/txs/payload"
)

const HashLength = tmhash.Size

// Tx is the canonical object that we serialise to produce the SignBytes that we sign
type Tx struct {
ChainID string
Expand Down Expand Up @@ -184,7 +186,7 @@ func (tx *Tx) GenerateReceipt() *Receipt {
if callTx, ok := tx.Payload.(*payload.CallTx); ok {
receipt.CreatesContract = callTx.Address == nil
if receipt.CreatesContract {
receipt.ContractAddress = crypto.NewContractAddress(callTx.Input.Address, callTx.Input.Sequence)
receipt.ContractAddress = crypto.NewContractAddress(callTx.Input.Address, tx.Hash())
} else {
receipt.ContractAddress = *callTx.Address
}
Expand Down

0 comments on commit 381ed8a

Please sign in to comment.