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

Commit 93b81bd

Browse files
Silas Davisseanyoung
Silas Davis
authored andcommitted
Support Vent consuming events from Ethereum web3 JSONRPC
Provided an interface for Vent chain connection o abstract over Burrow and web3-supporting Ethereum chains and implemented for Burrow and web3 Also fix: - Non-minimal size encoding in RLP (leading zeros) - Eth-compliant hex strings - EthRawTx hash and payload where incorrect (ChainID not in payload only in digest) - ChainID handling for mainline Ethereum Added: - NotEqual and Not operators to query grammar Signed-off-by: Silas Davis <[email protected]>
1 parent d80be06 commit 93b81bd

File tree

94 files changed

+14011
-2936
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+14011
-2936
lines changed

Diff for: .github/workflows/master.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ on:
33
push:
44
branches:
55
- master
6+
- release
67

78
jobs:
89
cover:

Diff for: .github/workflows/test.yaml

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ jobs:
3636
runs-on: ubuntu-latest
3737
steps:
3838
- uses: actions/checkout@v2
39-
- run: make test_integration_vent_postgres
39+
- run: make test_integration_ethereum
40+
- run: make test_integration_vent_complete
4041

4142
docker:
4243
runs-on: ubuntu-latest

Diff for: .gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,5 @@ node_modules
2626
js/dist
2727

2828
helm/package
29+
build/
30+
.pid

Diff for: Makefile

+34-4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ BIN_PATH?=$(GOPATH)/bin
2424
HELM_PATH?=helm/package
2525
HELM_PACKAGE=$(HELM_PATH)/burrow-$(VERSION).tgz
2626
ARCH?=linux-amd64
27+
PID_DIR=.pid
2728

2829
export GO111MODULE=on
2930

@@ -226,9 +227,38 @@ test_integration_vent:
226227
# Include sqlite adapter with tests - will build with CGO but that's probably fine
227228
go test -count=1 -v -tags 'integration sqlite' ./vent/...
228229

229-
.PHONY: test_integration_vent_postgres
230-
test_integration_vent_postgres:
231-
docker-compose run burrow make test_integration_vent
230+
.PHONY: test_integration_vent_complete
231+
test_integration_vent_complete:
232+
docker-compose run burrow make test_integration_vent test_integration_vent_ethereum
233+
234+
.PHONY: test_integration_vent_ethereum
235+
test_integration_vent_ethereum: start_ganache
236+
go test -count=1 -v -tags 'integration !sqlite ethereum' ./vent/...
237+
$(MAKE) stop_ganache
238+
239+
.PHONY: test_integration_ethereum
240+
test_integration_ethereum: start_ganache
241+
go test -v -tags 'integration ethereum' ./rpc/...
242+
$(MAKE) stop_ganache
243+
244+
$(PID_DIR)/ganache.pid:
245+
mkdir -p $(PID_DIR)
246+
yarn --cwd vent/test/eth install
247+
@echo "Starting ganache in background..."
248+
{ yarn --cwd vent/test/eth ganache & echo $$! > $@; }
249+
@sleep 3
250+
@echo "Ganache process started (pid at $@)"
251+
252+
.PHONY: start_ganache
253+
start_ganache: $(PID_DIR)/ganache.pid
254+
255+
.PHONY: stop_ganache
256+
stop_ganache: $(PID_DIR)/ganache.pid
257+
@kill $(shell cat $<) && echo "Ganache process stopped." && rm $< || rm $<
258+
259+
.PHONY: postgres
260+
postgres:
261+
docker-compose up
232262

233263
.PHONY: test_restore
234264
test_restore:
@@ -241,7 +271,7 @@ test_integration:
241271
@go test -count=1 -v -tags integration ./integration/...
242272

243273
.PHONY: test_integration_all
244-
test_integration_all: test_keys test_deploy test_integration_vent_postgres test_restore test_truffle test_integration
274+
test_integration_all: test_keys test_deploy test_integration_vent_complete test_restore test_truffle test_integration
245275

246276
.PHONY: test_integration_all_no_postgres
247277
test_integration_all_no_postgres: test_keys test_deploy test_integration_vent test_restore test_truffle test_integration

Diff for: acm/balance/balance.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
)
88

99
var (
10-
eth = new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)
10+
ethInWei = new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)
1111
)
1212

1313
type Balances []Balance
@@ -134,9 +134,9 @@ func (bs Balances) HasPower() bool {
134134
func NativeToWei(n uint64) *big.Int {
135135
// 1 native unit to 1 ether (wei)
136136
x := new(big.Int).SetUint64(n)
137-
return new(big.Int).Mul(x, eth)
137+
return new(big.Int).Mul(x, ethInWei)
138138
}
139139

140140
func WeiToNative(x *big.Int) *big.Int {
141-
return new(big.Int).Div(x, eth)
141+
return new(big.Int).Div(x, ethInWei)
142142
}

Diff for: cmd/burrow/commands/vent.go

+20-6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"time"
1111

1212
"github.com/hyperledger/burrow/config/source"
13+
"github.com/hyperledger/burrow/crypto"
1314
"github.com/hyperledger/burrow/execution/evm/abi"
1415
"github.com/hyperledger/burrow/logging/logconfig"
1516
"github.com/hyperledger/burrow/vent/config"
@@ -29,9 +30,11 @@ func Vent(output Output) func(cmd *cli.Cmd) {
2930
cfg := config.DefaultVentConfig()
3031

3132
dbOpts := sqlDBOpts(cmd, cfg)
32-
grpcAddrOpt := cmd.StringOpt("grpc-addr", cfg.GRPCAddr, "Address to connect to the Hyperledger Burrow gRPC server")
33-
httpAddrOpt := cmd.StringOpt("http-addr", cfg.HTTPAddr, "Address to bind the HTTP server")
33+
grpcAddrOpt := cmd.StringOpt("chain-addr", cfg.ChainAddress, "Address to connect to the Hyperledger Burrow gRPC server")
34+
httpAddrOpt := cmd.StringOpt("http-addr", cfg.HTTPListenAddress, "Address to bind the HTTP server")
3435
logLevelOpt := cmd.StringOpt("log-level", cfg.LogLevel, "Logging level (error, warn, info, debug)")
36+
watchAddressesOpt := cmd.StringsOpt("watch", nil, "Add contract address to global watch filter")
37+
minimumHeightOpt := cmd.IntOpt("minimum-height", 0, "Add contract address to global watch filter")
3538
abiFileOpt := cmd.StringsOpt("abi", cfg.AbiFileOrDirs, "EVM Contract ABI file or folder")
3639
specFileOrDirOpt := cmd.StringsOpt("spec", cfg.SpecFileOrDirs, "SQLSol specification file or folder")
3740
dbBlockOpt := cmd.BoolOpt("blocks", false, "Create block tables and persist related data")
@@ -44,9 +47,18 @@ func Vent(output Output) func(cmd *cli.Cmd) {
4447
cfg.DBAdapter = *dbOpts.adapter
4548
cfg.DBURL = *dbOpts.url
4649
cfg.DBSchema = *dbOpts.schema
47-
cfg.GRPCAddr = *grpcAddrOpt
48-
cfg.HTTPAddr = *httpAddrOpt
50+
cfg.ChainAddress = *grpcAddrOpt
51+
cfg.HTTPListenAddress = *httpAddrOpt
4952
cfg.LogLevel = *logLevelOpt
53+
cfg.WatchAddresses = make([]crypto.Address, len(*watchAddressesOpt))
54+
cfg.MinimumHeight = uint64(*minimumHeightOpt)
55+
var err error
56+
for i, wa := range *watchAddressesOpt {
57+
cfg.WatchAddresses[i], err = crypto.AddressFromHexString(wa)
58+
if err != nil {
59+
output.Fatalf("could not parse watch address: %w", err)
60+
}
61+
}
5062
cfg.AbiFileOrDirs = *abiFileOpt
5163
cfg.SpecFileOrDirs = *specFileOrDirOpt
5264
if *dbBlockOpt {
@@ -65,8 +77,10 @@ func Vent(output Output) func(cmd *cli.Cmd) {
6577
}
6678
}
6779

68-
cmd.Spec = "--spec=<spec file or dir> [--abi=<abi file or dir>] [--db-adapter] [--db-url] [--db-schema] " +
69-
"[--blocks] [--txs] [--grpc-addr] [--http-addr] [--log-level] [--announce-every=<duration>]"
80+
cmd.Spec = "--spec=<spec file or dir>... [--abi=<abi file or dir>...] " +
81+
"[--watch=<contract address>...] [--minimum-height=<lowest height from which to read>] " +
82+
"[--db-adapter] [--db-url] [--db-schema] [--blocks] [--txs] [--chain-addr] [--http-addr] " +
83+
"[--log-level] [--announce-every=<duration>]"
7084

7185
cmd.Action = func() {
7286
log, err := logconfig.New().NewLogger()

Diff for: core/kernel.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/hyperledger/burrow/consensus/tendermint"
2121
"github.com/hyperledger/burrow/crypto"
2222
"github.com/hyperledger/burrow/dump"
23+
"github.com/hyperledger/burrow/rpc/web3"
2324

2425
// GRPC Codec
2526
_ "github.com/hyperledger/burrow/encoding"
@@ -52,7 +53,7 @@ type Kernel struct {
5253
// Expose these public-facing interfaces to allow programmatic extension of the Kernel by other projects
5354
Emitter *event.Emitter
5455
Service *rpc.Service
55-
EthService *rpc.EthService
56+
EthService *web3.EthService
5657
Launchers []process.Launcher
5758
State *state.State
5859
Blockchain *bcm.Blockchain

Diff for: core/processes.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ func TendermintLauncher(kern *Kernel) process.Launcher {
143143
nodeRegState := kern.State
144144
validatorState := kern.State
145145
kern.Service = rpc.NewService(accountState, nameRegState, nodeRegState, kern.Blockchain, validatorState, nodeView, kern.Logger)
146-
kern.EthService = rpc.NewEthService(accountState, eventsState, kern.Blockchain, validatorState, nodeView, kern.Transactor, kern.keyStore, kern.Logger)
146+
kern.EthService = web3.NewEthService(accountState, eventsState, kern.Blockchain, validatorState, nodeView, kern.Transactor, kern.keyStore, kern.Logger)
147147

148148
if err := kern.Node.Start(); err != nil {
149149
return nil, fmt.Errorf("%s error starting Tendermint node: %v", errHeader, err)

Diff for: crypto/crypto.go

+4
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,7 @@ type Signer interface {
7474
type Signable interface {
7575
SignBytes(chainID string) ([]byte, error)
7676
}
77+
78+
func (pk *PrivateKey) GetAddress() Address {
79+
return pk.GetPublicKey().GetAddress()
80+
}

Diff for: crypto/signature.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,12 @@ func (sig *Signature) String() string {
118118
}
119119

120120
func GetEthChainID(chainID string) *big.Int {
121-
return new(big.Int).SetBytes(Keccak256([]byte(chainID)))
121+
b := new(big.Int)
122+
id, ok := b.SetString(chainID, 10)
123+
if ok {
124+
return id
125+
}
126+
return b.SetBytes([]byte(chainID))
122127
}
123128

124129
func GetEthSignatureRecoveryID(chainID string, parity *big.Int) *big.Int {

Diff for: deploy/compile/compilers_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func TestLocalMulti(t *testing.T) {
4040
expectedSolcResponse := BlankSolcResponse()
4141
actualOutput, err := exec.Command("solc", "--combined-json", "bin,abi", "contractImport1.sol").CombinedOutput()
4242
if err != nil {
43-
t.Fatal(err)
43+
t.Fatalf("solc failed %v: %s", err, actualOutput)
4444
}
4545

4646
warning, responseJSON := extractWarningJSON(strings.TrimSpace(string(actualOutput)))
@@ -85,7 +85,7 @@ func TestLocalSingle(t *testing.T) {
8585
shellCmd := exec.Command("solc", "--combined-json", "bin,abi", "simpleContract.sol")
8686
actualOutput, err := shellCmd.CombinedOutput()
8787
if err != nil {
88-
t.Fatal(err)
88+
t.Fatalf("solc failed %v: %s", err, actualOutput)
8989
}
9090

9191
warning, responseJSON := extractWarningJSON(strings.TrimSpace(string(actualOutput)))

Diff for: encoding/hex/hex.go

-53
This file was deleted.

Diff for: encoding/hex/hex_test.go

-26
This file was deleted.

Diff for: encoding/rlp/rlp.go

+25-12
Original file line numberDiff line numberDiff line change
@@ -90,15 +90,22 @@ func Decode(src []byte, dst interface{}) error {
9090
}
9191
}
9292
case reflect.Struct:
93-
if val.NumField() != len(fields) {
94-
return fmt.Errorf("wrong number of fields; have %d, want %d", len(fields), val.NumField())
95-
}
93+
rt := val.Type()
94+
numExportedFields := 0
9695
for i := 0; i < val.NumField(); i++ {
97-
err := decodeField(val.Field(i), fields[i])
98-
if err != nil {
99-
return err
96+
// Skip unexported fields
97+
if rt.Field(i).PkgPath == "" {
98+
err := decodeField(val.Field(i), fields[numExportedFields])
99+
if err != nil {
100+
return err
101+
}
102+
numExportedFields++
100103
}
101104
}
105+
if numExportedFields != len(fields) {
106+
return fmt.Errorf("wrong number of fields; have %d, want %d", len(fields), numExportedFields)
107+
}
108+
102109
default:
103110
return fmt.Errorf("cannot decode into unsupported type %v", reflect.TypeOf(dst))
104111
}
@@ -146,11 +153,11 @@ func encodeLength(n int, offset magicOffset) []byte {
146153
if n <= ShortLength {
147154
return []uint8{uint8(offset) + uint8(n)}
148155
}
149-
150156
i := uint64(n)
151157
b := make([]byte, 8)
152158
binary.BigEndian.PutUint64(b, i)
153-
byteLengthOfLength := bits.Len64(i)/8 + 1
159+
// Byte-wise ceiling
160+
byteLengthOfLength := (bits.Len64(i) + 7) / 8
154161
// > If a string is more than 55 bytes long, the RLP encoding consists of a single byte with value 0xb7
155162
// > plus the length in bytes of the length of the string in binary form, followed by the length of the string,
156163
// > followed by the string
@@ -186,12 +193,18 @@ func encodeList(val reflect.Value) ([]byte, error) {
186193
func encodeStruct(val reflect.Value) ([]byte, error) {
187194
out := make([][]byte, 0)
188195

196+
rt := val.Type()
197+
189198
for i := 0; i < val.NumField(); i++ {
190-
data, err := encode(val.Field(i))
191-
if err != nil {
192-
return nil, err
199+
field := val.Field(i)
200+
// Skip unexported fields
201+
if rt.Field(i).PkgPath == "" {
202+
data, err := encode(field)
203+
if err != nil {
204+
return nil, err
205+
}
206+
out = append(out, data)
193207
}
194-
out = append(out, data)
195208
}
196209
sum := bytes.Join(out, []byte{})
197210
length := encodeLength(len(sum), SliceOffset)

0 commit comments

Comments
 (0)