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 6ec0e84
Show file tree
Hide file tree
Showing 16 changed files with 34 additions and 159 deletions.
16 changes: 0 additions & 16 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,4 @@
# [Hyperledger Burrow](/~https://github.com/hyperledger/burrow) Changelog
## [Unreleased]
### Security

### Changed

### Fixed

### Added
- [Deploy] burrow deploy now prints events generated during transactions

### Removed

### Deprecated


## [0.23.1] - 2018-11-14
### Fixed
- [EVM] state/Cache no longer allows SetStorage on accounts that do not exist
Expand Down Expand Up @@ -336,7 +321,6 @@ This release marks the start of Eris-DB as the full permissioned blockchain node
- [Blockchain] Fix getBlocks to respect block height cap.


[Unreleased]: /~https://github.com/hyperledger/burrow/compare/v0.23.1...HEAD
[0.23.1]: /~https://github.com/hyperledger/burrow/compare/v0.23.0...v0.23.1
[0.23.0]: /~https://github.com/hyperledger/burrow/compare/v0.22.0...v0.23.0
[0.22.0]: /~https://github.com/hyperledger/burrow/compare/v0.21.0...v0.22.0
Expand Down
1 change: 0 additions & 1 deletion cmd/burrow/commands/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,5 +137,4 @@ func (f *PlainFormatter) appendMessageData(b *bytes.Buffer, key string, value in
stringVal = fmt.Sprint(value)
}
b.WriteString(stringVal)
b.WriteString(" ")
}
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
40 changes: 0 additions & 40 deletions deploy/jobs/jobs_contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"strings"

"github.com/hyperledger/burrow/execution/errors"
"github.com/hyperledger/burrow/execution/exec"

"github.com/hyperledger/burrow/crypto"
compilers "github.com/hyperledger/burrow/deploy/compile"
Expand Down Expand Up @@ -438,9 +437,6 @@ func CallJob(call *def.Call, tx *payload.CallTx, do *def.DeployArgs, client *def
return "", nil, txe.Exception.AsError()
}
}

logEvents(txe, do)

var result string

// Formally process the return
Expand Down Expand Up @@ -486,45 +482,9 @@ func deployFinalize(do *def.DeployArgs, client *def.Client, tx payload.Payload)
return nil, err
}

// The contructor can generate events
logEvents(txe, do)

if !txe.Receipt.CreatesContract || txe.Receipt.ContractAddress == crypto.ZeroAddress {
// Shouldn't get ZeroAddress when CreatesContract is true, but still
return nil, fmt.Errorf("result from SignAndBroadcast does not contain address for the deployed contract")
}
return &txe.Receipt.ContractAddress, nil
}

func logEvents(txe *exec.TxExecution, do *def.DeployArgs) {
for _, event := range txe.Events {
eventLog := event.GetLog()

if eventLog == nil {
continue
}

var eventID abi.EventID
copy(eventID[:], eventLog.GetTopic(0).Bytes())

evAbi, err := abi.FindEventSpec(do.BinPath, eventID)
if err != nil {
log.Errorf("Could not find ABI for Event with ID %x\n", eventID)
continue
}

vals := make([]interface{}, len(evAbi.Inputs))
for i := range vals {
vals[i] = new(string)
}

if err = abi.UnpackEvent(evAbi, eventLog.Topics, eventLog.Data, vals...); err == nil {
fields := log.Fields{}
for i := range vals {
val := vals[i].(*string)
fields[evAbi.Inputs[i].Name] = *val
}
log.WithFields(fields).Info("Event " + evAbi.Name)
}
}
}
3 changes: 1 addition & 2 deletions execution/contexts/call_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,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
2 changes: 1 addition & 1 deletion execution/evm/abi/abi.go
Original file line number Diff line number Diff line change
Expand Up @@ -1098,7 +1098,7 @@ func UnpackRevert(data []byte) (message *string, err error) {
/*
* Given a eventSpec, get all the fields (topic fields or not)
*/
func UnpackEvent(eventSpec *EventSpec, topics []burrow_binary.Word256, data []byte, args ...interface{}) error {
func UnpackEvent(eventSpec EventSpec, topics []burrow_binary.Word256, data []byte, args ...interface{}) error {
// First unpack the topic fields
topicIndex := 0
if !eventSpec.Anonymous {
Expand Down
35 changes: 0 additions & 35 deletions execution/evm/abi/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@ package abi

import (
"fmt"
"io"
"os"
"path"
"path/filepath"

"github.com/hyperledger/burrow/deploy/compile"
"github.com/hyperledger/burrow/execution/errors"
log "github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -154,38 +151,6 @@ func readAbi(root, contract string) (string, error) {
return string(sol.Abi), nil
}

// FindEventSpec helps when you have an event but you do not know what contract
// it came from. Events can be emitted from contracts called from other contracts,
// so you are not likely to know what abi to use. Therefore, this will go through
// all the files in the directory and see if a matching event spec can be found.
func FindEventSpec(abiDir string, eventID EventID) (evAbi *EventSpec, err error) {
err = filepath.Walk(abiDir, func(path string, fi os.FileInfo, err error) error {
ext := filepath.Ext(path)
if fi.IsDir() || !(ext == ".bin" || ext == ".abi") {
return nil
}
if err == nil {
abiSpc, err := ReadAbiSpecFile(path)
if err != nil {
return errors.Wrap(err, "Error parsing abi file "+path)
}

a, ok := abiSpc.EventsById[eventID]
if ok {
evAbi = &a
return io.EOF
}
}
return nil
})

if err == io.EOF {
err = nil
}

return
}

func stripHex(s string) string {
if len(s) > 1 {
if s[:2] == "0x" {
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
9 changes: 7 additions & 2 deletions execution/evm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -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, Word256Length)
copy(nonce, vm.tx.Hash())
PutUint64BE(nonce, 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
6 changes: 3 additions & 3 deletions integration/rpctransact/call_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ func TestLogEvents(t *testing.T) {
var direction string
var depth int64
evAbi := spec.Events["ChangeLevel"]
err = abi.UnpackEvent(&evAbi, log.Topics, log.Data, &direction, &depth)
err = abi.UnpackEvent(evAbi, log.Topics, log.Data, &direction, &depth)
require.NoError(t, err)
assert.Equal(t, evAbi.EventID.Bytes(), log.Topics[0].Bytes())
assert.Equal(t, int64(18), depth)
Expand All @@ -307,7 +307,7 @@ func TestEventEmitter(t *testing.T) {
data := abi.GetPackingTypes(evAbi.Inputs)
// Check signature
assert.Equal(t, evAbi.EventID.Bytes(), log.Topics[0].Bytes())
err = abi.UnpackEvent(&evAbi, log.Topics, log.Data.Bytes(), data...)
err = abi.UnpackEvent(evAbi, log.Topics, log.Data.Bytes(), data...)
require.NoError(t, err)

h := sha3.NewKeccak256()
Expand Down Expand Up @@ -346,7 +346,7 @@ func TestEventEmitterBytes32isString(t *testing.T) {
data[i] = new(string)
}
}
err = abi.UnpackEvent(&evAbi, log.Topics, log.Data.Bytes(), data...)
err = abi.UnpackEvent(evAbi, log.Topics, log.Data.Bytes(), data...)
require.NoError(t, err)

h := sha3.NewKeccak256()
Expand Down
Loading

0 comments on commit 6ec0e84

Please sign in to comment.