diff --git a/.circleci/Dockerfile b/.circleci/Dockerfile index 57832735c..5097163cc 100644 --- a/.circleci/Dockerfile +++ b/.circleci/Dockerfile @@ -26,8 +26,8 @@ RUN apk add --update --no-cache \ RUN pip install docker-compose # get docker client WORKDIR /usr/bin -RUN curl -L https://download.docker.com/linux/static/stable/x86_64/docker-$DOCKER_VERSION.tgz | tar xz --strip-components 1 docker/docker -RUN curl -L https://github.com/goreleaser/goreleaser/releases/download/$GORELEASER_VERSION/goreleaser_Linux_x86_64.tar.gz | tar xz goreleaser +RUN curl -sS -L https://download.docker.com/linux/static/stable/x86_64/docker-$DOCKER_VERSION.tgz | tar xz --strip-components 1 docker/docker +RUN curl -sS -L https://github.com/goreleaser/goreleaser/releases/download/$GORELEASER_VERSION/goreleaser_Linux_x86_64.tar.gz | tar xz goreleaser RUN npm install -g mocha RUN npm install -g mocha-circleci-reporter ENV CI=true diff --git a/CHANGELOG.md b/CHANGELOG.md index c2d4afadd..078ae7298 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # [Hyperledger Burrow](https://github.com/hyperledger/burrow) Changelog -## [Unreleased] +## [0.27.0] - 2019-06-23 +### Added +- [WASM] Support for WASM contracts written in Solidity compiled using solang + +### Fixed +-[RPC/Transact] CallCodeSim and CallTxSim were run against uncommitted checker state rather than committed state were all other reads are routed. They were also passed through Transactor for no particularly good reason. This changes them to run against committed DB state and removes the code path through Transactor. + +### Changed +- [State] TxExecution's Envelope now stored in state so will be reproduced in Vent Tx tables and over RPC, and so matches TxExecutions served from *Sync rpctransact methods ## [0.26.2] - 2019-06-19 @@ -507,7 +515,7 @@ 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.26.2...HEAD +[0.27.0]: https://github.com/hyperledger/burrow/compare/v0.26.2...v0.27.0 [0.26.2]: https://github.com/hyperledger/burrow/compare/v0.26.1...v0.26.2 [0.26.1]: https://github.com/hyperledger/burrow/compare/v0.26.0...v0.26.1 [0.26.0]: https://github.com/hyperledger/burrow/compare/v0.25.1...v0.26.0 diff --git a/Makefile b/Makefile index 0bb947ec0..13a272240 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,8 @@ PROTO_GO_FILES_REAL = $(shell find . -path ./vendor -prune -o -type f -name '*.p # Our own Go files containing the compiled bytecode of solidity files as a constant SOLIDITY_FILES = $(shell find . -path ./vendor -prune -o -path ./tests -prune -o -type f -name '*.sol' -print) SOLIDITY_GO_FILES = $(patsubst %.sol, %.sol.go, $(SOLIDITY_FILES)) +SOLANG_FILES = $(shell find . -path ./vendor -prune -o -path ./tests -prune -o -type f -name '*.solang' -print) +SOLANG_GO_FILES = $(patsubst %.solang, %.solang.go, $(SOLANG_FILES)) CI_IMAGE="hyperledger/burrow:ci" @@ -148,9 +150,16 @@ docker_build: check commit_hash %.sol.go: %.sol @go run ./deploy/compile/solgo/main.go $^ +# Solidity fixtures +%.solang.go: %.solang + @go run ./deploy/compile/solgo/main.go -wasm $^ + .PHONY: solidity solidity: $(SOLIDITY_GO_FILES) +.PHONY: solang +solang: $(SOLANG_GO_FILES) + # Test .PHONY: test @@ -247,3 +256,8 @@ push_ci_image: build_ci_image .PHONY: ready_for_pull_request ready_for_pull_request: docs fix + +.PHONY: staticcheck +staticcheck: + go get honnef.co/go/tools/cmd/staticcheck + staticcheck ./... diff --git a/NOTES.md b/NOTES.md index b4cee2e1e..30d091dc2 100644 --- a/NOTES.md +++ b/NOTES.md @@ -1,3 +1,9 @@ +### Added +- [WASM] Support for WASM contracts written in Solidity compiled using solang + ### Fixed -- [Blockchain] Persist LastBlockTime in Blockchain - before this patch LastBlockTime would only be set correctly after the first block had been received after a node is restarted - this can lead to non-determinism in the EVM via the TIMESTAMP opcode that use the LastBlockTime which is itself sourced from Tendermint's block header (from their implementation of BFT time). Implementing no empty blocks made observing this bug more likely by increasing the amount of time spent in a bad state (LastBlockTime is initially set to GenesisTime). +-[RPC/Transact] CallCodeSim and CallTxSim were run against uncommitted checker state rather than committed state were all other reads are routed. They were also passed through Transactor for no particularly good reason. This changes them to run against committed DB state and removes the code path through Transactor. + +### Changed +- [State] TxExecution's Envelope now stored in state so will be reproduced in Vent Tx tables and over RPC, and so matches TxExecutions served from *Sync rpctransact methods diff --git a/acm/account.go b/acm/account.go index dd968ad0e..1cf3eebe0 100644 --- a/acm/account.go +++ b/acm/account.go @@ -92,7 +92,7 @@ func FromAddressable(addressable crypto.Addressable) *Account { Address: addressable.GetAddress(), PublicKey: addressable.GetPublicKey(), // Since nil slices and maps compare differently to empty ones - Code: Bytecode{}, + EVMCode: Bytecode{}, Permissions: permission.AccountPermissions{ Roles: []string{}, }, @@ -124,13 +124,13 @@ func (acc *Account) Equal(accOther *Account) bool { func (acc Account) String() string { return fmt.Sprintf("Account{Address: %s; Sequence: %v; PublicKey: %v Balance: %v; CodeLength: %v; Permissions: %v}", - acc.Address, acc.Sequence, acc.PublicKey, acc.Balance, len(acc.Code), acc.Permissions) + acc.Address, acc.Sequence, acc.PublicKey, acc.Balance, len(acc.EVMCode), acc.Permissions) } func (acc *Account) Tagged() query.Tagged { return &TaggedAccount{ Account: acc, - Tagged: query.MergeTags(query.MustReflectTags(acc, "Address", "Balance", "Sequence", "Code"), + Tagged: query.MergeTags(query.MustReflectTags(acc, "Address", "Balance", "Sequence", "EVMCode"), query.TagMap{ "Permissions": acc.Permissions.Base.ResultantPerms(), "Roles": acc.Permissions.Roles, diff --git a/acm/account_test.go b/acm/account_test.go index 852f31fff..445d3ef82 100644 --- a/acm/account_test.go +++ b/acm/account_test.go @@ -66,7 +66,7 @@ func TestDecodeConcrete(t *testing.T) { require.NoError(t, err) assert.Equal(t, concreteAcc, concreteAccOut) - concreteAccOut, err = Decode([]byte("flungepliffery munknut tolopops")) + _, err = Decode([]byte("flungepliffery munknut tolopops")) assert.Error(t, err) } @@ -85,7 +85,7 @@ func TestDecode(t *testing.T) { func TestMarshalJSON(t *testing.T) { acc := NewAccountFromSecret("Super Semi Secret") - acc.Code = []byte{60, 23, 45} + acc.EVMCode = []byte{60, 23, 45} acc.Permissions = permission.AccountPermissions{ Base: permission.BasePermissions{ Perms: permission.AllPermFlags, @@ -96,7 +96,7 @@ func TestMarshalJSON(t *testing.T) { bs, err := json.Marshal(acc) expected := fmt.Sprintf(`{"Address":"%s","PublicKey":{"CurveType":"ed25519","PublicKey":"%s"},`+ - `"Sequence":4,"Balance":10,"Code":"3C172D",`+ + `"Sequence":4,"Balance":10,"EVMCode":"3C172D",`+ `"Permissions":{"Base":{"Perms":"root | send | call | createContract | createAccount | bond | name | proposal | input | batch | hasBase | setBase | unsetBase | setGlobal | hasRole | addRole | removeRole","SetBit":""}}}`, acc.Address, acc.PublicKey) assert.Equal(t, expected, string(bs)) @@ -108,16 +108,16 @@ func TestAccountTags(t *testing.T) { perms.Roles = []string{"frogs", "dogs"} acc := &Account{ Permissions: perms, - Code: solidity.Bytecode_StrangeLoop, + EVMCode: solidity.Bytecode_StrangeLoop, } tagged := acc.Tagged() - assert.Equal(t, []string{"Address", "Balance", "Sequence", "Code", "Permissions", "Roles"}, tagged.Keys()) + assert.Equal(t, []string{"Address", "Balance", "Sequence", "EVMCode", "Permissions", "Roles"}, tagged.Keys()) str, _ := tagged.Get("Permissions") assert.Equal(t, "send | call | createContract | createAccount | bond | name | proposal | input | batch | hasBase | hasRole", str) str, _ = tagged.Get("Roles") assert.Equal(t, "frogs;dogs", str) - str, _ = tagged.Get("Code") - qry, err := query.New("Code CONTAINS '0116002556001600360006101000A815'") + tagged.Get("EVMCode") + qry, err := query.New("EVMCode CONTAINS '0116002556001600360006101000A815'") require.NoError(t, err) assert.True(t, qry.Matches(tagged)) } diff --git a/acm/acm.pb.go b/acm/acm.pb.go index 9c508767c..716122b25 100644 --- a/acm/acm.pb.go +++ b/acm/acm.pb.go @@ -33,8 +33,9 @@ type Account struct { PublicKey crypto.PublicKey `protobuf:"bytes,2,opt,name=PublicKey,proto3" json:"PublicKey"` Sequence uint64 `protobuf:"varint,3,opt,name=Sequence,proto3" json:"Sequence,omitempty"` Balance uint64 `protobuf:"varint,4,opt,name=Balance,proto3" json:"Balance,omitempty"` - Code Bytecode `protobuf:"bytes,5,opt,name=Code,proto3,customtype=Bytecode" json:"Code"` + EVMCode Bytecode `protobuf:"bytes,5,opt,name=EVMCode,proto3,customtype=Bytecode" json:"EVMCode"` Permissions permission.AccountPermissions `protobuf:"bytes,6,opt,name=Permissions,proto3" json:"Permissions"` + WASMCode Bytecode `protobuf:"bytes,7,opt,name=WASMCode,proto3,customtype=Bytecode" json:",omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -112,28 +113,30 @@ func init() { proto.RegisterFile("acm.proto", fileDescriptor_49ed775bc0a6adf6) } func init() { golang_proto.RegisterFile("acm.proto", fileDescriptor_49ed775bc0a6adf6) } var fileDescriptor_49ed775bc0a6adf6 = []byte{ - // 323 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x90, 0xbd, 0x4e, 0xfb, 0x30, - 0x14, 0xc5, 0xeb, 0x36, 0xff, 0x7e, 0xb8, 0x1d, 0xfa, 0xf7, 0x64, 0x75, 0x70, 0x0b, 0x62, 0xe8, - 0x00, 0x89, 0xc4, 0x87, 0x90, 0xd8, 0x1a, 0x24, 0x16, 0x24, 0x54, 0x85, 0x8d, 0x2d, 0x71, 0x2e, - 0x69, 0xa4, 0xa6, 0x0e, 0x4e, 0x2c, 0x94, 0x37, 0x61, 0xe4, 0x39, 0x98, 0x18, 0x3b, 0x32, 0x33, - 0x54, 0x28, 0x7d, 0x11, 0x54, 0xe3, 0x86, 0x4c, 0x6c, 0x3e, 0xfe, 0xdd, 0x73, 0xef, 0xd1, 0xc1, - 0x3d, 0x9f, 0x27, 0x76, 0x2a, 0x45, 0x2e, 0x48, 0xcb, 0xe7, 0xc9, 0xe8, 0x24, 0x8a, 0xf3, 0x85, - 0x0a, 0x6c, 0x2e, 0x12, 0x27, 0x12, 0x91, 0x70, 0x34, 0x0b, 0xd4, 0xa3, 0x56, 0x5a, 0xe8, 0xd7, - 0x8f, 0x67, 0x34, 0x4c, 0x41, 0x26, 0x71, 0x96, 0xc5, 0x62, 0x65, 0x7e, 0x06, 0x5c, 0x16, 0x69, - 0x6e, 0xf8, 0xe1, 0x5b, 0x13, 0x77, 0x66, 0x9c, 0x0b, 0xb5, 0xca, 0xc9, 0x1d, 0xee, 0xcc, 0xc2, - 0x50, 0x42, 0x96, 0x51, 0x34, 0x41, 0xd3, 0x81, 0x7b, 0xbe, 0xde, 0x8c, 0x1b, 0x9f, 0x9b, 0xf1, - 0x71, 0xed, 0xe6, 0xa2, 0x48, 0x41, 0x2e, 0x21, 0x8c, 0x40, 0x3a, 0x81, 0x92, 0x52, 0x3c, 0x3b, - 0x66, 0xa1, 0xf1, 0x7a, 0xfb, 0x25, 0xe4, 0x02, 0xf7, 0xe6, 0x2a, 0x58, 0xc6, 0xfc, 0x16, 0x0a, - 0xda, 0x9c, 0xa0, 0x69, 0xff, 0xf4, 0xbf, 0x6d, 0x86, 0x2b, 0xe0, 0x5a, 0xbb, 0x23, 0xde, 0xef, - 0x24, 0x19, 0xe1, 0xee, 0x3d, 0x3c, 0x29, 0x58, 0x71, 0xa0, 0xad, 0x09, 0x9a, 0x5a, 0x5e, 0xa5, - 0x09, 0xc5, 0x1d, 0xd7, 0x5f, 0xfa, 0x3b, 0x64, 0x69, 0xb4, 0x97, 0xe4, 0x08, 0x5b, 0xd7, 0x22, - 0x04, 0xfa, 0x4f, 0x27, 0x1f, 0x9a, 0xe4, 0x5d, 0xb7, 0xc8, 0x81, 0x8b, 0x10, 0x3c, 0x4d, 0xc9, - 0x0d, 0xee, 0xcf, 0xab, 0x42, 0x32, 0xda, 0xd6, 0xa1, 0x98, 0x5d, 0x2b, 0xc9, 0x94, 0x51, 0x9b, - 0x32, 0x09, 0xeb, 0xc6, 0x2b, 0xeb, 0xe5, 0x75, 0xdc, 0x70, 0x2f, 0xd7, 0x25, 0x43, 0x1f, 0x25, - 0x43, 0x5f, 0x25, 0x43, 0xef, 0x5b, 0x86, 0xd6, 0x5b, 0x86, 0x1e, 0x0e, 0xfe, 0x6e, 0xcb, 0xe7, - 0x49, 0xd0, 0xd6, 0xe5, 0x9f, 0x7d, 0x07, 0x00, 0x00, 0xff, 0xff, 0x10, 0xec, 0x45, 0x82, 0xdd, - 0x01, 0x00, 0x00, + // 355 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x51, 0xbf, 0x4f, 0xfa, 0x40, + 0x1c, 0xe5, 0xa0, 0x5f, 0x0a, 0x07, 0x03, 0xdf, 0x9b, 0x1a, 0x86, 0x16, 0x9d, 0x88, 0xc1, 0x36, + 0xf1, 0x47, 0x4c, 0xd8, 0xa8, 0xd1, 0xc5, 0x68, 0x48, 0x49, 0x34, 0x71, 0x6b, 0xaf, 0x67, 0x69, + 0xc2, 0x71, 0xf5, 0x7a, 0x8d, 0xe9, 0x7f, 0xe2, 0xe8, 0x9f, 0xe2, 0xc8, 0xe8, 0xec, 0x40, 0x0c, + 0x6c, 0xfe, 0x0d, 0x0e, 0x86, 0xe3, 0xa8, 0x8d, 0x83, 0x5b, 0x5f, 0xdf, 0x7b, 0x9f, 0xf7, 0xf2, + 0x0e, 0x36, 0x7d, 0x4c, 0xed, 0x84, 0x33, 0xc1, 0x50, 0xcd, 0xc7, 0xb4, 0x7b, 0x18, 0xc5, 0x62, + 0x9a, 0x05, 0x36, 0x66, 0xd4, 0x89, 0x58, 0xc4, 0x1c, 0xc9, 0x05, 0xd9, 0x83, 0x44, 0x12, 0xc8, + 0xaf, 0xad, 0xa7, 0xdb, 0x49, 0x08, 0xa7, 0x71, 0x9a, 0xc6, 0x6c, 0xae, 0xfe, 0xb4, 0x31, 0xcf, + 0x13, 0xa1, 0xf8, 0xfd, 0xaf, 0x2a, 0xd4, 0x47, 0x18, 0xb3, 0x6c, 0x2e, 0xd0, 0x0d, 0xd4, 0x47, + 0x61, 0xc8, 0x49, 0x9a, 0x1a, 0xa0, 0x07, 0xfa, 0x6d, 0xf7, 0x64, 0xb1, 0xb4, 0x2a, 0xef, 0x4b, + 0x6b, 0x50, 0xca, 0x9c, 0xe6, 0x09, 0xe1, 0x33, 0x12, 0x46, 0x84, 0x3b, 0x41, 0xc6, 0x39, 0x7b, + 0x72, 0xd4, 0x41, 0xe5, 0xf5, 0x76, 0x47, 0xd0, 0x29, 0x6c, 0x8e, 0xb3, 0x60, 0x16, 0xe3, 0x2b, + 0x92, 0x1b, 0xd5, 0x1e, 0xe8, 0xb7, 0x8e, 0xfe, 0xdb, 0x4a, 0x5c, 0x10, 0xae, 0xb6, 0x09, 0xf1, + 0x7e, 0x94, 0xa8, 0x0b, 0x1b, 0x13, 0xf2, 0x98, 0x91, 0x39, 0x26, 0x46, 0xad, 0x07, 0xfa, 0x9a, + 0x57, 0x60, 0x64, 0x40, 0xdd, 0xf5, 0x67, 0xfe, 0x86, 0xd2, 0x24, 0xb5, 0x83, 0xe8, 0x00, 0xea, + 0x17, 0xb7, 0xd7, 0xe7, 0x2c, 0x24, 0xc6, 0x3f, 0x59, 0xbe, 0xa3, 0xca, 0x37, 0xdc, 0x5c, 0x10, + 0xcc, 0x42, 0xe2, 0xed, 0x04, 0xe8, 0x12, 0xb6, 0xc6, 0xc5, 0x2c, 0xa9, 0x51, 0x97, 0xd5, 0x4c, + 0xbb, 0x34, 0x95, 0x9a, 0xa4, 0xa4, 0x52, 0x3d, 0xcb, 0x46, 0x34, 0x84, 0x8d, 0xbb, 0xd1, 0x64, + 0x1b, 0xaa, 0xcb, 0x50, 0xf3, 0x77, 0xe8, 0xe7, 0xd2, 0x82, 0x03, 0x46, 0x63, 0x41, 0x68, 0x22, + 0x72, 0xaf, 0xd0, 0x0f, 0xb5, 0xe7, 0x17, 0xab, 0xe2, 0x9e, 0x2d, 0x56, 0x26, 0x78, 0x5b, 0x99, + 0xe0, 0x63, 0x65, 0x82, 0xd7, 0xb5, 0x09, 0x16, 0x6b, 0x13, 0xdc, 0xef, 0xfd, 0xbd, 0xb7, 0x8f, + 0x69, 0x50, 0x97, 0xcf, 0x77, 0xfc, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x65, 0x02, 0xa3, 0x8e, 0x1f, + 0x02, 0x00, 0x00, } func (m *Account) Marshal() (dAtA []byte, err error) { @@ -179,8 +182,8 @@ func (m *Account) MarshalTo(dAtA []byte) (int, error) { } dAtA[i] = 0x2a i++ - i = encodeVarintAcm(dAtA, i, uint64(m.Code.Size())) - n3, err := m.Code.MarshalTo(dAtA[i:]) + i = encodeVarintAcm(dAtA, i, uint64(m.EVMCode.Size())) + n3, err := m.EVMCode.MarshalTo(dAtA[i:]) if err != nil { return 0, err } @@ -193,6 +196,14 @@ func (m *Account) MarshalTo(dAtA []byte) (int, error) { return 0, err } i += n4 + dAtA[i] = 0x3a + i++ + i = encodeVarintAcm(dAtA, i, uint64(m.WASMCode.Size())) + n5, err := m.WASMCode.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n5 if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) } @@ -224,10 +235,12 @@ func (m *Account) Size() (n int) { if m.Balance != 0 { n += 1 + sovAcm(uint64(m.Balance)) } - l = m.Code.Size() + l = m.EVMCode.Size() n += 1 + l + sovAcm(uint64(l)) l = m.Permissions.Size() n += 1 + l + sovAcm(uint64(l)) + l = m.WASMCode.Size() + n += 1 + l + sovAcm(uint64(l)) if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -382,7 +395,7 @@ func (m *Account) Unmarshal(dAtA []byte) error { } case 5: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Code", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field EVMCode", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -409,7 +422,7 @@ func (m *Account) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Code.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.EVMCode.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -446,6 +459,39 @@ func (m *Account) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WASMCode", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAcm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthAcm + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthAcm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.WASMCode.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipAcm(dAtA[iNdEx:]) diff --git a/acm/acmstate/dump_state.go b/acm/acmstate/dump_state.go index 22c73f4bb..185f2290e 100644 --- a/acm/acmstate/dump_state.go +++ b/acm/acmstate/dump_state.go @@ -6,7 +6,6 @@ import ( "encoding/json" "github.com/hyperledger/burrow/acm" - "github.com/hyperledger/burrow/binary" "github.com/hyperledger/burrow/crypto" ) @@ -32,7 +31,7 @@ func (dw *DumpState) RemoveAccount(address crypto.Address) error { return nil } -func (dw *DumpState) SetStorage(address crypto.Address, key, value binary.Word256) error { +func (dw *DumpState) SetStorage(address crypto.Address, key, value []byte) error { dw.WriteString("SetStorage\n") dw.WriteString(address.String()) dw.WriteByte('/') diff --git a/acm/acmstate/memory_state.go b/acm/acmstate/memory_state.go index 6e2395a9b..10bef6c0d 100644 --- a/acm/acmstate/memory_state.go +++ b/acm/acmstate/memory_state.go @@ -10,7 +10,7 @@ import ( type MemoryState struct { Accounts map[crypto.Address]*acm.Account - Storage map[crypto.Address]map[binary.Word256]binary.Word256 + Storage map[crypto.Address]map[binary.Word256][]byte } var _ IterableReaderWriter = &MemoryState{} @@ -19,7 +19,7 @@ var _ IterableReaderWriter = &MemoryState{} func NewMemoryState() *MemoryState { return &MemoryState{ Accounts: make(map[crypto.Address]*acm.Account), - Storage: make(map[crypto.Address]map[binary.Word256]binary.Word256), + Storage: make(map[crypto.Address]map[binary.Word256][]byte), } } @@ -40,22 +40,22 @@ func (ms *MemoryState) RemoveAccount(address crypto.Address) error { return nil } -func (ms *MemoryState) GetStorage(address crypto.Address, key binary.Word256) (binary.Word256, error) { +func (ms *MemoryState) GetStorage(address crypto.Address, key binary.Word256) ([]byte, error) { storage, ok := ms.Storage[address] if !ok { - return binary.Zero256, fmt.Errorf("could not find storage for account %s", address) + return []byte{}, fmt.Errorf("could not find storage for account %s", address) } value, ok := storage[key] if !ok { - return binary.Zero256, fmt.Errorf("could not find key %x for account %s", key, address) + return []byte{}, fmt.Errorf("could not find key %x for account %s", key, address) } return value, nil } -func (ms *MemoryState) SetStorage(address crypto.Address, key, value binary.Word256) error { +func (ms *MemoryState) SetStorage(address crypto.Address, key binary.Word256, value []byte) error { storage, ok := ms.Storage[address] if !ok { - storage = make(map[binary.Word256]binary.Word256) + storage = make(map[binary.Word256][]byte) ms.Storage[address] = storage } storage[key] = value @@ -71,7 +71,7 @@ func (ms *MemoryState) IterateAccounts(consumer func(*acm.Account) error) (err e return nil } -func (ms *MemoryState) IterateStorage(address crypto.Address, consumer func(key, value binary.Word256) error) (err error) { +func (ms *MemoryState) IterateStorage(address crypto.Address, consumer func(key binary.Word256, value []byte) error) (err error) { for key, value := range ms.Storage[address] { if err := consumer(key, value); err != nil { return err diff --git a/acm/acmstate/state.go b/acm/acmstate/state.go index 2c7b968ed..1f72d15de 100644 --- a/acm/acmstate/state.go +++ b/acm/acmstate/state.go @@ -30,19 +30,19 @@ type AccountUpdater interface { type StorageGetter interface { // Retrieve a 32-byte value stored at key for the account at address, return Zero256 if key does not exist but // error if address does not - GetStorage(address crypto.Address, key binary.Word256) (value binary.Word256, err error) + GetStorage(address crypto.Address, key binary.Word256) (value []byte, err error) } type StorageSetter interface { // Store a 32-byte value at key for the account at address, setting to Zero256 removes the key - SetStorage(address crypto.Address, key, value binary.Word256) error + SetStorage(address crypto.Address, key binary.Word256, value []byte) error } type StorageIterable interface { // Iterates through the storage of account ad address calling the passed function once per account, // if the iterator function returns true the iteration breaks and returns true to indicate it iteration // was escaped - IterateStorage(address crypto.Address, consumer func(key, value binary.Word256) error) (err error) + IterateStorage(address crypto.Address, consumer func(key binary.Word256, value []byte) error) (err error) } type AccountStats struct { diff --git a/acm/acmstate/state_cache.go b/acm/acmstate/state_cache.go index 2f2c79ec0..52aeb49b0 100644 --- a/acm/acmstate/state_cache.go +++ b/acm/acmstate/state_cache.go @@ -37,7 +37,7 @@ type Cache struct { type accountInfo struct { sync.RWMutex account *acm.Account - storage map[binary.Word256]binary.Word256 + storage map[binary.Word256][]byte removed bool updated bool } @@ -135,10 +135,10 @@ func (cache *Cache) IterateCachedAccount(consumer func(*acm.Account) (stop bool) return false, nil } -func (cache *Cache) GetStorage(address crypto.Address, key binary.Word256) (binary.Word256, error) { +func (cache *Cache) GetStorage(address crypto.Address, key binary.Word256) ([]byte, error) { accInfo, err := cache.get(address) if err != nil { - return binary.Zero256, err + return []byte{}, err } // Check cache accInfo.RLock() @@ -152,7 +152,7 @@ func (cache *Cache) GetStorage(address crypto.Address, key binary.Word256) (bina // Load from backend value, err = cache.backend.GetStorage(address, key) if err != nil { - return binary.Zero256, err + return []byte{}, err } accInfo.storage[key] = value } @@ -161,7 +161,7 @@ func (cache *Cache) GetStorage(address crypto.Address, key binary.Word256) (bina } // NOTE: Set value to zero to remove. -func (cache *Cache) SetStorage(address crypto.Address, key binary.Word256, value binary.Word256) error { +func (cache *Cache) SetStorage(address crypto.Address, key binary.Word256, value []byte) error { if cache.readonly { return errors.ErrorCodef(errors.ErrorCodeIllegalWrite, "SetStorage called in a read-only context on account %v", address) @@ -186,7 +186,7 @@ func (cache *Cache) SetStorage(address crypto.Address, key binary.Word256, value // Iterates over all cached storage items first in cache and then in backend until consumer returns true for 'stop' func (cache *Cache) IterateCachedStorage(address crypto.Address, - consumer func(key, value binary.Word256) error) error { + consumer func(key binary.Word256, value []byte) error) error { accInfo, err := cache.get(address) if err != nil { return err @@ -294,7 +294,7 @@ func (cache *Cache) get(address crypto.Address) (*accountInfo, error) { } accInfo = &accountInfo{ account: account, - storage: make(map[binary.Word256]binary.Word256), + storage: make(map[binary.Word256][]byte), } cache.accounts[address] = accInfo } diff --git a/acm/acmstate/state_cache_test.go b/acm/acmstate/state_cache_test.go index 8baf046dc..3ac275f53 100644 --- a/acm/acmstate/state_cache_test.go +++ b/acm/acmstate/state_cache_test.go @@ -171,7 +171,7 @@ func TestStateCache_GetStorage(t *testing.T) { cache.UpdateAccount(acc) //Check for correct cache storage value - assert.Equal(t, word("NO YOU ARE A KEY"), accStorage) + assert.Equal(t, "NO YOU ARE A KEY", string(accStorage)) //Sync account to backend err = cache.Sync(writeBackend) @@ -183,7 +183,7 @@ func TestStateCache_GetStorage(t *testing.T) { require.NotNil(t, accStorage) //Check for correct backend storage value - assert.Equal(t, word("NO YOU ARE A KEY"), accStorage) + assert.Equal(t, "NO YOU ARE A KEY", string(accStorage)) } func TestStateCache_SetStorage(t *testing.T) { @@ -195,13 +195,13 @@ func TestStateCache_SetStorage(t *testing.T) { newAcc := acm.NewAccountFromSecret("newAcc") err := cache.UpdateAccount(newAcc) require.NoError(t, err) - err = cache.SetStorage(newAcc.Address, word("What?"), word("Huh?")) + err = cache.SetStorage(newAcc.Address, word("What?"), []byte("Huh?")) require.NoError(t, err) //Check for correct cache storage value newAccStorage, err := cache.GetStorage(newAcc.Address, word("What?")) require.NoError(t, err) - assert.Equal(t, word("Huh?"), newAccStorage) + assert.Equal(t, "Huh?", string(newAccStorage)) //Sync account to backend err = cache.Sync(backend) @@ -210,15 +210,15 @@ func TestStateCache_SetStorage(t *testing.T) { //Check for correct backend storage value newAccStorage, err = backend.GetStorage(newAcc.Address, word("What?")) require.NoError(t, err) - assert.Equal(t, word("Huh?"), newAccStorage) + assert.Equal(t, "Huh?", string(newAccStorage)) noone := acm.NewAccountFromSecret("noone at all") - err = cache.SetStorage(noone.Address, binary.Word256{3, 4, 5}, binary.Word256{102, 103, 104}) + err = cache.SetStorage(noone.Address, binary.Word256{3, 4, 5}, []byte{102, 103, 104}) require.Error(t, err, "should not be able to write to non-existent account") err = cache.UpdateAccount(noone) require.NoError(t, err) - err = cache.SetStorage(noone.Address, binary.Word256{3, 4, 5}, binary.Word256{102, 103, 104}) + err = cache.SetStorage(noone.Address, binary.Word256{3, 4, 5}, []byte{102, 103, 104}) require.NoError(t, err, "should be able to update account after creating it") } @@ -228,16 +228,17 @@ func TestStateCache_Sync(t *testing.T) { cache := NewCache(backend) // Create new account - newAcc := acm.NewAccountFromSecret("newAcc") // Create account + newAcc := acm.NewAccountFromSecret("newAcc") err := cache.UpdateAccount(newAcc) + require.NoError(t, err) // Set balance for account balance := uint64(24) newAcc.Balance = balance // Set storage for account - err = cache.SetStorage(newAcc.Address, word("God save"), word("the queen!")) + err = cache.SetStorage(newAcc.Address, word("God save"), []byte("the queen!")) require.NoError(t, err) //Update cache with account changes @@ -252,7 +253,7 @@ func TestStateCache_Sync(t *testing.T) { //Confirm changes to account storage in cache newAccStorage, err := cache.GetStorage(newAcc.Address, word("God save")) require.NoError(t, err) - assert.Equal(t, word("the queen!"), newAccStorage) + assert.Equal(t, "the queen!", string(newAccStorage)) //Sync account to backend err = cache.Sync(backend) @@ -266,7 +267,7 @@ func TestStateCache_Sync(t *testing.T) { //Confirm changes to account storage synced correctly to backend newAccStorage, err = cache.GetStorage(newAcc.Address, word("God save")) require.NoError(t, err) - assert.Equal(t, word("the queen!"), newAccStorage) + assert.Equal(t, "the queen!", string(newAccStorage)) //Remove account from cache err = cache.RemoveAccount(newAcc.Address) @@ -316,7 +317,7 @@ func testAccounts() *MemoryState { acc2 := acm.NewAccountFromSecret("acc2") acc2.Permissions.Base.Perms = permission.AddRole | permission.Send acc2.Permissions.Base.SetBit = acc1.Permissions.Base.Perms - acc2.Code, _ = acm.NewBytecode(asm.PUSH1, 0x20) + acc2.EVMCode, _ = acm.NewBytecode(asm.PUSH1, 0x20) cache := combine( account(acc1, "I AM A KEY", "NO YOU ARE A KEY"), @@ -333,9 +334,9 @@ func addressOf(secret string) crypto.Address { func account(acc *acm.Account, keyvals ...string) *MemoryState { ts := NewMemoryState() ts.Accounts[acc.Address] = acc - ts.Storage[acc.Address] = make(map[binary.Word256]binary.Word256) + ts.Storage[acc.Address] = make(map[binary.Word256][]byte) for i := 0; i < len(keyvals); i += 2 { - ts.Storage[acc.Address][word(keyvals[i])] = word(keyvals[i+1]) + ts.Storage[acc.Address][word(keyvals[i])] = []byte(keyvals[i+1]) } return ts } diff --git a/acm/bytecode_test.go b/acm/bytecode_test.go index 17ce3a071..7409ffe06 100644 --- a/acm/bytecode_test.go +++ b/acm/bytecode_test.go @@ -24,6 +24,7 @@ func TestBytecode_MarshalJSON(t *testing.T) { bytecodeOut := new(Bytecode) err = json.Unmarshal(bs, bytecodeOut) + require.NoError(t, err) assert.Equal(t, bytecode, *bytecodeOut) } @@ -41,6 +42,7 @@ func TestBytecode_MarshalText(t *testing.T) { bytecodeOut := new(Bytecode) err = bytecodeOut.UnmarshalText(bs) + require.NoError(t, err) assert.Equal(t, bytecode, *bytecodeOut) } @@ -80,6 +82,6 @@ func TestBytecode_Tokens(t *testing.T) { require.NoError(t, err) assert.Equal(t, []string{}, tokens) - tokens, err = Bytecode(bc.MustSplice(asm.PUSH3, 1, 2)).Tokens() + _, err = Bytecode(bc.MustSplice(asm.PUSH3, 1, 2)).Tokens() assert.Error(t, err, "not enough bytes to push") } diff --git a/acm/validator/bucket_test.go b/acm/validator/bucket_test.go index fcd935818..e1ab8b79a 100644 --- a/acm/validator/bucket_test.go +++ b/acm/validator/bucket_test.go @@ -31,10 +31,10 @@ func TestBucket_AlterPower(t *testing.T) { require.NoError(t, err) require.Equal(t, big3.Int64(), flow.Int64()) - flow, err = bucket.AlterPower(pubA, new(big.Int).Add(maxTotalVotingPower, big1)) + _, err = bucket.AlterPower(pubA, new(big.Int).Add(maxTotalVotingPower, big1)) require.Error(t, err, "should fail as we would breach total power") - flow, err = bucket.AlterPower(pubB, big1) + _, err = bucket.AlterPower(pubB, big1) require.Error(t, err, "should fail as we would breach total power") // Drop A and raise B - should now succeed diff --git a/acm/validator/ring_test.go b/acm/validator/ring_test.go index 456e39870..12567d9f8 100644 --- a/acm/validator/ring_test.go +++ b/acm/validator/ring_test.go @@ -29,7 +29,7 @@ func TestValidatorsRing_AlterPower(t *testing.T) { vs = Copy(vsBase) vw = NewRing(vs, 5) powA, powB, powC = 7000, 23, 310 - powerChange, totalFlow, err = alterPowers(t, vw, powA, powB, powC) + _, _, err = alterPowers(t, vw, powA, powB, powC) require.Error(t, err) powA, powB, powC = 7000, 23, 309 diff --git a/bcm/blockchain_test.go b/bcm/blockchain_test.go index a58ef4366..714b6dbf4 100644 --- a/bcm/blockchain_test.go +++ b/bcm/blockchain_test.go @@ -77,6 +77,6 @@ func assertState(t *testing.T, blockchain *Blockchain, height uint64, blockTime } func newGenesisDoc() *genesis.GenesisDoc { - genesisDoc, _, _ := genesis.NewDeterministicGenesis(3450976).GenesisDoc(23, true, 4, 10, true, 4) + genesisDoc, _, _ := genesis.NewDeterministicGenesis(3450976).GenesisDoc(23, 10) return genesisDoc } diff --git a/binary/bytes_test.go b/binary/bytes_test.go index 7e0aeb536..81f9d22e8 100644 --- a/binary/bytes_test.go +++ b/binary/bytes_test.go @@ -15,5 +15,6 @@ func TestHexBytes_MarshalText(t *testing.T) { assert.Equal(t, "\"0102030405\"", string(out)) bs2 := new(HexBytes) err = json.Unmarshal(out, bs2) + require.NoError(t, err) assert.Equal(t, bs, *bs2) } diff --git a/binary/integer.go b/binary/integer.go index cdc4fb7d7..f2d7b65a9 100644 --- a/binary/integer.go +++ b/binary/integer.go @@ -15,7 +15,6 @@ package binary import ( - "encoding/binary" "math" "math/big" ) @@ -26,36 +25,6 @@ var tt256 = new(big.Int).Lsh(big1, 256) var tt256m1 = new(big.Int).Sub(new(big.Int).Lsh(big1, 256), big1) var tt255 = new(big.Int).Lsh(big1, 255) -//-------------------------------------------------------------------------------- - -func PutUint64(dest []byte, i uint64) { - binary.BigEndian.PutUint64(dest, i) -} - -func GetUint64(src []byte) uint64 { - return binary.BigEndian.Uint64(src) -} - -func Uint64Bytes(v uint64) []byte { - bs := make([]byte, 8) - binary.BigEndian.PutUint64(bs, v) - return bs -} - -func PutInt64(dest []byte, i int64) { - binary.BigEndian.PutUint64(dest, uint64(i)) -} - -func GetInt64(src []byte) int64 { - return int64(binary.BigEndian.Uint64(src)) -} - -func Int64Bytes(v int64) []byte { - bs := make([]byte, 8) - binary.BigEndian.PutUint64(bs, uint64(v)) - return bs -} - // Returns whether a + b would be a uint64 overflow func IsUint64SumOverflow(a, b uint64) bool { return math.MaxUint64-a < b diff --git a/binary/integer_test.go b/binary/integer_test.go index b0a72a8c1..c0c1533fe 100644 --- a/binary/integer_test.go +++ b/binary/integer_test.go @@ -97,12 +97,6 @@ func TestS256(t *testing.T) { assertBigIntEqual(t, expected, signed, "Out of twos complement bounds") } -func TestPutUint64BE(t *testing.T) { - bs := make([]byte, 8) - PutUint64(bs, 245343) - assert.Equal(t, "000000000003BE5F", fmt.Sprintf("%X", bs)) -} - func TestSignExtend(t *testing.T) { assertSignExtend(t, 16, 0, "0000 0000 1001 0000", diff --git a/binary/word256.go b/binary/word256.go index ecee9cfb2..c3f38e41c 100644 --- a/binary/word256.go +++ b/binary/word256.go @@ -16,6 +16,7 @@ package binary import ( "bytes" + "encoding/binary" "fmt" "math/big" "sort" @@ -128,12 +129,12 @@ func (w Word256) Size() int { } func Uint64ToWord256(i uint64) (word Word256) { - PutUint64(word[24:], i) + binary.BigEndian.PutUint64(word[24:], i) return } func Int64ToWord256(i int64) (word Word256) { - PutInt64(word[24:], i) + binary.BigEndian.PutUint64(word[24:], uint64(i)) return } @@ -148,11 +149,11 @@ func LeftPadWord256(bz []byte) (word Word256) { } func Uint64FromWord256(word Word256) uint64 { - return GetUint64(word.Postfix(8)) + return binary.BigEndian.Uint64(word.Postfix(8)) } func Int64FromWord256(word Word256) int64 { - return GetInt64(word.Postfix(8)) + return int64(Uint64FromWord256(word)) } //------------------------------------- diff --git a/binary/word256_test.go b/binary/word256_test.go index bc0f038cf..ee0460bfb 100644 --- a/binary/word256_test.go +++ b/binary/word256_test.go @@ -52,6 +52,7 @@ func TestWord256_MarshalText(t *testing.T) { assert.Equal(t, "\"0102030405000000000000000000000000000000000000000000000000000000\"", string(out)) bs2 := new(Word256) err = json.Unmarshal(out, bs2) + require.NoError(t, err) assert.Equal(t, w, *bs2) } diff --git a/cmd/burrow/commands/configure.go b/cmd/burrow/commands/configure.go index b981f64e5..c51edec42 100644 --- a/cmd/burrow/commands/configure.go +++ b/cmd/burrow/commands/configure.go @@ -6,14 +6,13 @@ import ( "io/ioutil" "strings" - "github.com/hyperledger/burrow/dump" - + "github.com/hyperledger/burrow/config/deployment" "github.com/hyperledger/burrow/config/source" + "github.com/hyperledger/burrow/consensus/tendermint" "github.com/hyperledger/burrow/crypto" - "github.com/hyperledger/burrow/deployment" + "github.com/hyperledger/burrow/dump" "github.com/hyperledger/burrow/execution" "github.com/hyperledger/burrow/execution/state" - "github.com/hyperledger/burrow/genesis" "github.com/hyperledger/burrow/genesis/spec" "github.com/hyperledger/burrow/keys" "github.com/hyperledger/burrow/logging" @@ -22,10 +21,8 @@ import ( "github.com/hyperledger/burrow/rpc" cli "github.com/jawher/mow.cli" amino "github.com/tendermint/go-amino" - tmEd25519 "github.com/tendermint/tendermint/crypto/ed25519" cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino" "github.com/tendermint/tendermint/libs/db" - "github.com/tendermint/tendermint/p2p" ) // Configure generates burrow configuration(s) @@ -43,15 +40,11 @@ func Configure(output Output) func(cmd *cli.Cmd) { keysDir := cmd.StringOpt("keys-dir", "", "Directory where keys are stored") - generateNodeKeys := cmd.BoolOpt("generate-node-keys", false, "Generate node keys for validators") - configTemplateIn := cmd.StringsOpt("config-template-in", nil, - fmt.Sprintf("Go text/template template input filename (left delim: %s right delim: %s) to generate config "+ - "file specified with --config-out", deployment.LeftTemplateDelim, deployment.RightTemplateDelim)) + "Go text/template input filename to generate config file specified with --config-out") - configOut := cmd.StringsOpt("config-out", nil, - "Go text/template template output file. Template filename specified with --config-template-in "+ - "file specified with --config-out") + configTemplateOut := cmd.StringsOpt("config-out", nil, + "Go text/template output filename. Template filename specified with --config-template-in") separateGenesisDoc := cmd.StringOpt("w separate-genesis-doc", "", "Emit a separate genesis doc as JSON or TOML") @@ -79,9 +72,8 @@ func Configure(output Output) func(cmd *cli.Cmd) { cmd.Spec = "[--keys-url= | --keys-dir=] " + "[ --config-template-in= --config-out=]... " + "[--genesis-spec=] [--separate-genesis-doc=] " + - "[--chain-name=] [--generate-node-keys] [--restore-dump=] " + - "[--logging=] [--describe-logging] [--empty-blocks=<'always','never',duration>] " + - "[--json] [--debug] [--pool]" + "[--chain-name=] [--restore-dump=] [--json] [--debug] [--pool] " + + "[--logging=] [--describe-logging] [--empty-blocks=<'always','never',duration>]" // no sourcing logs source.LogWriter = ioutil.Discard @@ -109,11 +101,11 @@ func Configure(output Output) func(cmd *cli.Cmd) { conf.Keys.RemoteAddress = *keysURLOpt } - if len(*configTemplateIn) != len(*configOut) { + if len(*configTemplateIn) != len(*configTemplateOut) { output.Fatalf("--config-template-in and --config-out must be specified the same number of times") } - pkg := deployment.Config{} + pkg := deployment.Config{Keys: make(map[crypto.Address]deployment.Key)} // Genesis Spec if *genesisSpecOpt != "" { @@ -130,9 +122,9 @@ func Configure(output Output) func(cmd *cli.Cmd) { keyStore := keys.NewKeyStore(dir, conf.Keys.AllowBadFilePermissions) keyClient := keys.NewLocalKeyClient(keyStore, logging.NewNoopLogger()) - conf.GenesisDoc, err = genesisSpec.GenesisDoc(keyClient, *generateNodeKeys || *pool) + conf.GenesisDoc, err = genesisSpec.GenesisDoc(keyClient) if err != nil { - output.Fatalf("Could not generate GenesisDoc from GenesisSpec using MockKeyClient: %v", err) + output.Fatalf("could not generate GenesisDoc from GenesisSpec using MockKeyClient: %v", err) } allNames, err := keyStore.GetAllNames() @@ -140,66 +132,37 @@ func Configure(output Output) func(cmd *cli.Cmd) { output.Fatalf("could get all keys: %v", err) } - cdc := amino.NewCodec() - cryptoAmino.RegisterAmino(cdc) - - pkg = deployment.Config{Keys: make(map[crypto.Address]deployment.Key)} - for k := range allNames { addr, err := crypto.AddressFromHexString(allNames[k]) if err != nil { - output.Fatalf("Address %s not valid: %v", k, err) + output.Fatalf("address %s not valid: %v", k, err) } key, err := keyStore.GetKey("", addr[:]) if err != nil { - output.Fatalf("Failed to get key: %s: %v", k, err) + output.Fatalf("failed to get key: %s: %v", k, err) } - - // Is this is a validator node key? - nodeKey := false - for _, a := range conf.GenesisDoc.Validators { - if a.NodeAddress != nil && addr == *a.NodeAddress { - nodeKey = true - break - } - } - - if nodeKey { - privKey := tmEd25519.GenPrivKey() - copy(privKey[:], key.PrivateKey.PrivateKey) - nodeKey := &p2p.NodeKey{ - PrivKey: privKey, - } - - json, err := cdc.MarshalJSON(nodeKey) - if err != nil { - output.Fatalf("go-amino failed to json marshall private key: %v", err) - } - pkg.Keys[addr] = deployment.Key{Name: k, Address: addr, KeyJSON: json} - } else { - json, err := json.Marshal(key) - if err != nil { - output.Fatalf("Failed to json marshal key: %s: %v", k, err) - } - pkg.Keys[addr] = deployment.Key{Name: k, Address: addr, KeyJSON: json} + json, err := json.Marshal(key) + if err != nil { + output.Fatalf("failed to json marshal key: %s: %v", k, err) } + pkg.Keys[addr] = deployment.Key{Name: k, Address: addr, KeyJSON: json} } } else { keyClient, err := keys.NewRemoteKeyClient(conf.Keys.RemoteAddress, logging.NewNoopLogger()) if err != nil { - output.Fatalf("Could not create remote key client: %v", err) + output.Fatalf("could not create remote key client: %v", err) + } + conf.GenesisDoc, err = genesisSpec.GenesisDoc(keyClient) + if err != nil { + output.Fatalf("could not realise GenesisSpec: %v", err) } - conf.GenesisDoc, err = genesisSpec.GenesisDoc(keyClient, *generateNodeKeys || *pool) } - if err != nil { - output.Fatalf("could not realise GenesisSpec: %v", err) - } } if *chainNameOpt != "" { if conf.GenesisDoc == nil { - output.Fatalf("Unable to set ChainName since no GenesisDoc/GenesisSpec provided.") + output.Fatalf("unable to set ChainName since no GenesisDoc/GenesisSpec provided.") } conf.GenesisDoc.ChainName = *chainNameOpt } @@ -210,12 +173,12 @@ func Configure(output Output) func(cmd *cli.Cmd) { } if len(conf.GenesisDoc.Validators) == 0 { - output.Fatalf("On restore, validators must be provided in GenesisDoc or GenesisSpec") + output.Fatalf("on restore, validators must be provided in GenesisDoc or GenesisSpec") } reader, err := dump.NewFileReader(*restoreDumpOpt) if err != nil { - output.Fatalf("Failed to read restore dump: %v", err) + output.Fatalf("failed to read restore dump: %v", err) } st, err := state.MakeGenesisState(db.NewMemDB(), conf.GenesisDoc) @@ -231,30 +194,6 @@ func Configure(output Output) func(cmd *cli.Cmd) { conf.GenesisDoc.AppHash = st.Hash() } - if conf.GenesisDoc != nil { - pkg.Config = conf.GenesisDoc - - for _, v := range conf.GenesisDoc.Validators { - tmplV := deployment.Validator{ - Name: v.Name, - Address: v.Address, - } - - if v.NodeAddress != nil { - tmplV.NodeAddress = *v.NodeAddress - } - - pkg.Validators = append(pkg.Validators, tmplV) - } - - for ind := range *configTemplateIn { - err := processTemplate(&pkg, conf.GenesisDoc, (*configTemplateIn)[ind], (*configOut)[ind]) - if err != nil { - output.Fatalf("could not template from %s to %s: %v", (*configTemplateIn)[ind], (*configOut)[ind], err) - } - } - } - // Logging if *loggingOpt != "" { ops := strings.Split(*loggingOpt, ",") @@ -276,15 +215,15 @@ func Configure(output Output) func(cmd *cli.Cmd) { if *separateGenesisDoc != "" { if conf.GenesisDoc == nil { - output.Fatalf("Cannot write separate genesis doc since no GenesisDoc/GenesisSpec provided.") + output.Fatalf("cannot write separate genesis doc since no GenesisDoc/GenesisSpec was provided") } genesisDocJSON, err := conf.GenesisDoc.JSONBytes() if err != nil { - output.Fatalf("Could not form GenesisDoc JSON: %v", err) + output.Fatalf("could not form GenesisDoc JSON: %v", err) } err = ioutil.WriteFile(*separateGenesisDoc, genesisDocJSON, 0644) if err != nil { - output.Fatalf("Could not write GenesisDoc JSON: %v", err) + output.Fatalf("could not write GenesisDoc JSON: %v", err) } conf.GenesisDoc = nil } @@ -293,19 +232,54 @@ func Configure(output Output) func(cmd *cli.Cmd) { conf.Tendermint.CreateEmptyBlocks = *emptyBlocksOpt } + peers := make([]string, 0) + if conf.GenesisDoc != nil { + cdc := amino.NewCodec() + cryptoAmino.RegisterAmino(cdc) + pkg.GenesisDoc = conf.GenesisDoc + + for _, val := range conf.GenesisDoc.Validators { + nodeKey := tendermint.NewNodeKey() + nodeAddress, _ := crypto.AddressFromHexString(string(nodeKey.ID())) + + json, err := cdc.MarshalJSON(nodeKey) + if err != nil { + output.Fatalf("go-amino failed to json marshal private key: %v", err) + } + pkg.Keys[nodeAddress] = deployment.Key{Name: val.Name, Address: nodeAddress, KeyJSON: json} + + pkg.Validators = append(pkg.Validators, deployment.Validator{ + Name: val.Name, + Address: val.Address, + NodeAddress: nodeAddress, + }) + } + + for ind := range *configTemplateIn { + err := processTemplate(&pkg, (*configTemplateIn)[ind], (*configTemplateOut)[ind]) + if err != nil { + output.Fatalf("could not template from %s to %s: %v", (*configTemplateIn)[ind], (*configTemplateOut)[ind], err) + } + } + } + if *pool { - peers := make([]string, 0) - for i, val := range conf.GenesisDoc.Validators { - if val.NodeAddress == nil { - continue + for i, val := range pkg.Validators { + tmConf, err := conf.Tendermint.Config(fmt.Sprintf(".burrow%03d", i), conf.Execution.TimeoutFactor) + if err != nil { + output.Fatalf("could not obtain config for %03d: %v", i, err) } - peers = append(peers, fmt.Sprintf("tcp://%s@127.0.0.1:%d", strings.ToLower(val.NodeAddress.String()), 26656+i)) + nodeKey := pkg.Keys[val.NodeAddress] + err = tendermint.WriteNodeKey(tmConf.NodeKeyFile(), nodeKey.KeyJSON) + if err != nil { + output.Fatalf("failed to create node key for %03d: %v", i, err) + } + peers = append(peers, fmt.Sprintf("tcp://%s@127.0.0.1:%d", nodeKey.Address.String(), 26656+i)) } for i, acc := range conf.GenesisDoc.Accounts { // set stuff conf.Address = &acc.Address conf.Tendermint.PersistentPeers = strings.Join(peers, ",") - conf.BurrowDir = fmt.Sprintf(".burrow%03d", i) conf.Tendermint.ListenHost = rpc.LocalHost conf.Tendermint.ListenPort = fmt.Sprint(26656 + i) @@ -334,7 +308,7 @@ func Configure(output Output) func(cmd *cli.Cmd) { } } -func processTemplate(pkg *deployment.Config, config *genesis.GenesisDoc, templateIn, templateOut string) error { +func processTemplate(pkg *deployment.Config, templateIn, templateOut string) error { data, err := ioutil.ReadFile(templateIn) if err != nil { return err diff --git a/cmd/burrow/commands/deploy.go b/cmd/burrow/commands/deploy.go index a45d67af2..ec78ae590 100644 --- a/cmd/burrow/commands/deploy.go +++ b/cmd/burrow/commands/deploy.go @@ -59,6 +59,8 @@ func Deploy(output Output) func(cmd *cli.Cmd) { verboseOpt := cmd.BoolOpt("v verbose", false, "verbose output") + wasmOpt := cmd.BoolOpt("wasm", false, "Compile to WASM using solang (experimental)") + debugOpt := cmd.BoolOpt("d debug", false, "debug level output") proposalVerify := cmd.BoolOpt("proposal-verify", false, "Verify any proposal, do NOT create new proposal or vote") @@ -72,7 +74,7 @@ func Deploy(output Output) func(cmd *cli.Cmd) { proposalList := cmd.StringOpt("list-proposals state", "", "List proposals, either all, executed, expired, or current") cmd.Spec = "[--chain=] [--keys=] [--mempool-signing] [--dir=] " + - "[--output=] [--set=]... [--bin-path=] [--gas=] " + + "[--output=] [--wasm] [--set=]... [--bin-path=] [--gas=] " + "[--jobs=] [--address=
] [--fee=] [--amount=] " + "[--verbose] [--debug] [--timeout=] [--proposal-create|--proposal-verify|--proposal-create] FILE..." @@ -95,6 +97,7 @@ func Deploy(output Output) func(cmd *cli.Cmd) { args.MempoolSign = *mempoolSigningOpt args.Timeout = *timeoutSecondsOpt args.Path = *pathOpt + args.Wasm = *wasmOpt args.DefaultOutput = *defaultOutputOpt args.DefaultSets = *defaultSetsOpt args.BinPath = *binPathOpt diff --git a/cmd/burrow/commands/examine.go b/cmd/burrow/commands/examine.go index 3824089ec..f2351eb47 100644 --- a/cmd/burrow/commands/examine.go +++ b/cmd/burrow/commands/examine.go @@ -37,6 +37,9 @@ func Examine(output Output) func(cmd *cli.Cmd) { cmd.Action = func() { start, end, err := parseRange(*rangeArg) + if err != nil { + output.Fatalf("could not parse range '%s': %v", *rangeArg, err) + } err = explorer.Blocks(start, end, func(block *bcm.Block) error { @@ -61,6 +64,9 @@ func Examine(output Output) func(cmd *cli.Cmd) { cmd.Action = func() { start, end, err := parseRange(*rangeArg) + if err != nil { + output.Fatalf("could not parse range '%s': %v", *rangeArg, err) + } err = explorer.Blocks(start, end, func(block *bcm.Block) error { diff --git a/cmd/burrow/commands/keys.go b/cmd/burrow/commands/keys.go index 2b6b26443..12d03641b 100644 --- a/cmd/burrow/commands/keys.go +++ b/cmd/burrow/commands/keys.go @@ -12,8 +12,8 @@ import ( "github.com/howeyc/gopass" "github.com/hyperledger/burrow/config" + "github.com/hyperledger/burrow/config/deployment" "github.com/hyperledger/burrow/crypto" - "github.com/hyperledger/burrow/deployment" "github.com/hyperledger/burrow/keys" cli "github.com/jawher/mow.cli" "google.golang.org/grpc" diff --git a/deployment/config.go b/config/deployment/config.go similarity index 70% rename from deployment/config.go rename to config/deployment/config.go index ff935f05d..6e5342bb5 100644 --- a/deployment/config.go +++ b/config/deployment/config.go @@ -33,12 +33,9 @@ type Key struct { type Config struct { Keys map[crypto.Address]Key Validators []Validator - Config *genesis.GenesisDoc + *genesis.GenesisDoc } -const LeftTemplateDelim = "<<" -const RightTemplateDelim = ">>" - var templateFuncs template.FuncMap = map[string]interface{}{ "base64": func(rv reflect.Value) string { return encode(rv, base64.StdEncoding.EncodeToString) @@ -57,20 +54,18 @@ var templateFuncs template.FuncMap = map[string]interface{}{ } const DefaultKeysExportFormat = `{ - "CurveType": "<< .CurveType>>", - "Address": "<< .Address >>", - "PublicKey": "<< hex .PublicKey >>", - "PrivateKey": "<< hex .PrivateKey >>" -} -` + "CurveType": "{{ .CurveType }}", + "Address": "{{ .Address }}", + "PublicKey": "{{ hex .PublicKey }}", + "PrivateKey": "{{ hex .PrivateKey }}" +}` -var DefaultKeyExportTemplate = template.Must(template.New("KeysExport").Funcs(templateFuncs). - Delims(LeftTemplateDelim, RightTemplateDelim). - Parse(DefaultKeysExportFormat)) +var DefaultKeyExportTemplate = template.Must(template.New("KeysExport"). + Funcs(templateFuncs).Parse(DefaultKeysExportFormat)) -func (pkg *Config) Dump(templateName, templateString string) (string, error) { - tmpl, err := template.New(templateName).Delims(LeftTemplateDelim, RightTemplateDelim).Funcs(templateFuncs). - Parse(templateString) +// Dump a configuration to a template +func (pkg *Config) Dump(templateName, templateData string) (string, error) { + tmpl, err := template.New(templateName).Funcs(templateFuncs).Parse(templateData) if err != nil { return "", errors.Wrap(err, "could not dump config to template") } @@ -82,9 +77,9 @@ func (pkg *Config) Dump(templateName, templateString string) (string, error) { return buf.String(), nil } -func (key *Key) Dump(templateString string) (string, error) { - tmpl, err := template.New("ExportKey").Delims(LeftTemplateDelim, RightTemplateDelim).Funcs(templateFuncs). - Parse(templateString) +// Dump a key file to a template +func (key *Key) Dump(templateData string) (string, error) { + tmpl, err := template.New("ExportKey").Funcs(templateFuncs).Parse(templateData) if err != nil { return "", errors.Wrap(err, "could not export key to template") } diff --git a/consensus/abci/app.go b/consensus/abci/app.go index 61f5a5d02..6af202d87 100644 --- a/consensus/abci/app.go +++ b/consensus/abci/app.go @@ -34,8 +34,6 @@ type App struct { // State blockchain *bcm.Blockchain validators Validators - checkTx func(txBytes []byte) types.ResponseCheckTx - deliverTx func(txBytes []byte) types.ResponseCheckTx mempoolLocker sync.Locker authorizedPeersProvider PeersFilterProvider // We need to cache these from BeginBlock for when we need actually need it in Commit @@ -125,6 +123,9 @@ func (app *App) InitChain(chain types.RequestInitChain) (respInitChain types.Res } for _, v := range chain.Validators { pk, err := crypto.PublicKeyFromABCIPubKey(v.GetPubKey()) + if err != nil { + panic(err) + } err = app.checkValidatorMatches(currentSet, types.Validator{Address: pk.GetAddress().Bytes(), Power: v.Power}) if err != nil { panic(err) diff --git a/consensus/tendermint/sign_info.go b/consensus/tendermint/sign_info.go index 7f7c199df..105293bc8 100644 --- a/consensus/tendermint/sign_info.go +++ b/consensus/tendermint/sign_info.go @@ -76,17 +76,17 @@ func (lsi *LastSignedInfo) SignProposal(sign tmCryptoSigner, chainID string, pro // returns error if HRS regression or no SignBytes. returns true if HRS is unchanged func (lsi *LastSignedInfo) checkHRS(height int64, round int, step int8) (bool, error) { if lsi.Height > height { - return false, errors.New("Height regression") + return false, errors.New("height regression") } if lsi.Height == height { if lsi.Round > round { - return false, errors.New("Round regression") + return false, errors.New("round regression") } if lsi.Round == round { if lsi.Step > step { - return false, errors.New("Step regression") + return false, errors.New("step regression") } else if lsi.Step == step { if lsi.SignBytes != nil { if lsi.Signature == nil { @@ -94,7 +94,7 @@ func (lsi *LastSignedInfo) checkHRS(height int64, round int, step int8) (bool, e } return true, nil } - return false, errors.New("No Signature found") + return false, errors.New("no Signature found") } } } @@ -125,7 +125,7 @@ func (lsi *LastSignedInfo) signVote(sign tmCryptoSigner, chainID string, vote *t vote.Timestamp = timestamp vote.Signature = lsi.Signature } else { - err = fmt.Errorf("Conflicting data") + err = fmt.Errorf("conflicting data") } return err } @@ -161,7 +161,7 @@ func (lsi *LastSignedInfo) signProposal(sign tmCryptoSigner, chainID string, pro proposal.Timestamp = timestamp proposal.Signature = lsi.Signature } else { - err = fmt.Errorf("Conflicting data") + err = fmt.Errorf("conflicting data") } return err } diff --git a/consensus/tendermint/tendermint.go b/consensus/tendermint/tendermint.go index c87fceda1..ca53a1e76 100644 --- a/consensus/tendermint/tendermint.go +++ b/consensus/tendermint/tendermint.go @@ -1,6 +1,8 @@ package tendermint import ( + "encoding/json" + "io/ioutil" "os" "path" @@ -45,27 +47,15 @@ func (n *Node) Close() { } func NewNode(conf *config.Config, privValidator tmTypes.PrivValidator, genesisDoc *tmTypes.GenesisDoc, - app *abci.App, metricsProvider node.MetricsProvider, marmotNodeKey *crypto.PrivateKey, logger *logging.Logger) (*Node, error) { + app *abci.App, metricsProvider node.MetricsProvider, logger *logging.Logger) (*Node, error) { var err error // disable Tendermint's RPC conf.RPC.ListenAddress = "" - var nodeKey *p2p.NodeKey - if marmotNodeKey != nil && marmotNodeKey.CurveType == crypto.CurveTypeEd25519 { - var pkey ed25519.PrivKeyEd25519 - copy(pkey[:], marmotNodeKey.PrivateKey) - nodeKey = &p2p.NodeKey{PrivKey: pkey} - } else { - err = os.MkdirAll(path.Dir(conf.NodeKeyFile()), 0777) - if err != nil { - return nil, err - } - - nodeKey, err = p2p.LoadOrGenNodeKey(conf.NodeKeyFile()) - if err != nil { - return nil, err - } + nodeKey, err := EnsureNodeKey(conf.NodeKeyFile()) + if err != nil { + return nil, err } nde := &Node{} @@ -122,3 +112,27 @@ func NewNodeInfo(ni p2p.DefaultNodeInfo) *NodeInfo { TxIndex: ni.Other.TxIndex, } } + +func NewNodeKey() *p2p.NodeKey { + privKey := ed25519.GenPrivKey() + return &p2p.NodeKey{ + PrivKey: privKey, + } +} + +func WriteNodeKey(nodeKeyFile string, key json.RawMessage) error { + err := os.MkdirAll(path.Dir(nodeKeyFile), 0777) + if err != nil { + return err + } + return ioutil.WriteFile(nodeKeyFile, key, 0600) +} + +func EnsureNodeKey(nodeKeyFile string) (*p2p.NodeKey, error) { + err := os.MkdirAll(path.Dir(nodeKeyFile), 0777) + if err != nil { + return nil, err + } + + return p2p.LoadOrGenNodeKey(nodeKeyFile) +} diff --git a/core/config.go b/core/config.go index 2944b8b37..ae38b4b93 100644 --- a/core/config.go +++ b/core/config.go @@ -7,7 +7,6 @@ import ( "github.com/hyperledger/burrow/config" "github.com/hyperledger/burrow/consensus/abci" "github.com/hyperledger/burrow/consensus/tendermint" - "github.com/hyperledger/burrow/crypto" "github.com/hyperledger/burrow/execution" "github.com/hyperledger/burrow/keys" "github.com/hyperledger/burrow/logging/lifecycle" @@ -77,22 +76,6 @@ func (kern *Kernel) LoadTendermintFromConfig(conf *config.BurrowConfig, privVal genesisDoc := kern.Blockchain.GenesisDoc() - // find node key - var nodeKey *crypto.PrivateKey - for _, v := range genesisDoc.Validators { - thisAddress, err := crypto.AddressFromHexString(privVal.GetPubKey().Address().String()) - if err != nil { - break - } - if v.Address == thisAddress && v.NodeAddress != nil { - k, err := kern.keyStore.GetKey("", v.NodeAddress.Bytes()) - if err == nil { - nodeKey = &k.PrivateKey - } - break - } - } - tmGenesisDoc := tendermint.DeriveGenesisDoc(&genesisDoc, kern.Blockchain.AppHashAfterLastBlock()) heightValuer := log.Valuer(func() interface{} { return kern.Blockchain.LastBlockHeight() }) tmLogger := kern.Logger.With(structure.CallerKey, log.Caller(LoggingCallerDepth+1)).With("height", heightValuer) @@ -100,7 +83,7 @@ func (kern *Kernel) LoadTendermintFromConfig(conf *config.BurrowConfig, privVal if err != nil { return fmt.Errorf("could not build Tendermint config: %v", err) } - kern.Node, err = tendermint.NewNode(tmConf, privVal, tmGenesisDoc, app, metricsProvider, nodeKey, tmLogger) + kern.Node, err = tendermint.NewNode(tmConf, privVal, tmGenesisDoc, app, metricsProvider, tmLogger) return err } diff --git a/core/kernel.go b/core/kernel.go index 6c72adfe4..b751678a3 100644 --- a/core/kernel.go +++ b/core/kernel.go @@ -311,7 +311,7 @@ func (kern *Kernel) supervise() { shutdownCh := make(chan os.Signal, 1) reloadCh := make(chan os.Signal, 1) syncCh := make(chan os.Signal, 1) - signal.Notify(shutdownCh, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL) + signal.Notify(shutdownCh, syscall.SIGINT, syscall.SIGTERM) signal.Notify(reloadCh, syscall.SIGHUP) signal.Notify(syncCh, syscall.SIGUSR1) for { diff --git a/core/processes.go b/core/processes.go index 01fd25ef5..e1178d774 100644 --- a/core/processes.go +++ b/core/processes.go @@ -282,7 +282,8 @@ func GRPCLauncher(kern *Kernel, conf *rpc.ServerConfig, keyConfig *keys.KeysConf kern.Blockchain, kern.State, nodeView, kern.Logger)) txCodec := txs.NewAminoCodec() - rpctransact.RegisterTransactServer(grpcServer, rpctransact.NewTransactServer(kern.Transactor, txCodec)) + rpctransact.RegisterTransactServer(grpcServer, + rpctransact.NewTransactServer(kern.State, kern.Blockchain, kern.Transactor, txCodec, kern.Logger)) rpcevents.RegisterExecutionEventsServer(grpcServer, rpcevents.NewExecutionEventsServer(kern.State, kern.Emitter, kern.Blockchain, kern.Logger)) diff --git a/crypto/address.go b/crypto/address.go index 9fd00ea94..3936ca3b2 100644 --- a/crypto/address.go +++ b/crypto/address.go @@ -3,6 +3,7 @@ package crypto import ( "bytes" "crypto/sha256" + bin "encoding/binary" "encoding/json" "fmt" @@ -190,7 +191,7 @@ func Nonce(caller Address, nonce []byte) []byte { // Obtain a nearly unique nonce based on a montonic account sequence number func SequenceNonce(address Address, sequence uint64) []byte { bs := make([]byte, 8) - binary.PutUint64(bs, sequence) + bin.BigEndian.PutUint64(bs, sequence) return Nonce(address, bs) } diff --git a/crypto/address_test.go b/crypto/address_test.go index 55e8a36c2..05c065c6f 100644 --- a/crypto/address_test.go +++ b/crypto/address_test.go @@ -57,6 +57,7 @@ func TestAddress_MarshalJSON(t *testing.T) { addrOut := new(Address) err = json.Unmarshal(bs, addrOut) + require.NoError(t, err) assert.Equal(t, addr, *addrOut) } @@ -74,6 +75,7 @@ func TestAddress_MarshalText(t *testing.T) { addrOut := new(Address) err = addrOut.UnmarshalText(bs) + require.NoError(t, err) assert.Equal(t, addr, *addrOut) } diff --git a/crypto/public_key_test.go b/crypto/public_key_test.go index 6dea35482..b504570a0 100644 --- a/crypto/public_key_test.go +++ b/crypto/public_key_test.go @@ -21,6 +21,7 @@ func TestPublicKeySerialisation(t *testing.T) { require.NoError(t, err) var pubOut PublicKey err = proto.Unmarshal(bs, &pubOut) + require.NoError(t, err) assert.Equal(t, pub, pubOut) bs, err = json.Marshal(pub) diff --git a/deploy/compile/compilers.go b/deploy/compile/compilers.go index 2323c4728..b625c40c7 100644 --- a/deploy/compile/compilers.go +++ b/deploy/compile/compilers.go @@ -8,7 +8,6 @@ import ( "os" "os/exec" "path/filepath" - "regexp" "strings" "github.com/hyperledger/burrow/crypto" @@ -56,6 +55,9 @@ type SolidityContract struct { LinkReferences json.RawMessage } } + EWasm struct { + Wasm string + } Devdoc json.RawMessage Userdoc json.RawMessage Metadata string @@ -147,7 +149,15 @@ func (contract *SolidityContract) Link(libraries map[string]string) error { return nil } -func Compile(file string, optimize bool, workDir string, libraries map[string]string, logger *logging.Logger) (*Response, error) { +func (contract *SolidityContract) Code() (code string) { + code = contract.Evm.Bytecode.Object + if code == "" { + code = contract.EWasm.Wasm + } + return +} + +func EVM(file string, optimize bool, workDir string, libraries map[string]string, logger *logging.Logger) (*Response, error) { input := SolidityInput{Language: "Solidity", Sources: make(map[string]SolidityInputSource)} input.Sources[file] = SolidityInputSource{Urls: []string{file}} @@ -156,10 +166,8 @@ func Compile(file string, optimize bool, workDir string, libraries map[string]st input.Settings.Libraries = make(map[string]map[string]string) input.Settings.Libraries[""] = make(map[string]string) - if libraries != nil { - for l, a := range libraries { - input.Settings.Libraries[""][l] = "0x" + a - } + for l, a := range libraries { + input.Settings.Libraries[""][l] = "0x" + a } command, err := json.Marshal(input) @@ -203,6 +211,63 @@ func Compile(file string, optimize bool, workDir string, libraries map[string]st } } + for _, re := range respItemArray { + logger.TraceMsg("Response formulated", + "name", re.Objectname, + "bin", re.Contract.Code(), + "abi", string(re.Contract.Abi)) + } + + resp := Response{ + Objects: respItemArray, + Warning: warnings, + Error: errors, + } + + return &resp, nil +} + +func WASM(file string, workDir string, logger *logging.Logger) (*Response, error) { + shellCmd := exec.Command("solang", "--standard-json", file) + if workDir != "" { + shellCmd.Dir = workDir + } + output, err := shellCmd.CombinedOutput() + if err != nil { + logger.InfoMsg("solang failed", "output", string(output)) + return nil, err + } + logger.TraceMsg("Command Output", "result", string(output)) + + wasmoutput := SolidityOutput{} + err = json.Unmarshal(output, &wasmoutput) + if err != nil { + return nil, err + } + + respItemArray := make([]ResponseItem, 0) + + for f, s := range wasmoutput.Contracts { + for contract, item := range s { + respItem := ResponseItem{ + Filename: f, + Objectname: objectName(contract), + Contract: item, + } + respItemArray = append(respItemArray, respItem) + } + } + + warnings := "" + errors := "" + for _, msg := range wasmoutput.Errors { + if msg.Type == "Warning" { + warnings += msg.FormattedMessage + } else { + errors += msg.FormattedMessage + } + } + for _, re := range respItemArray { logger.TraceMsg("Response formulated", "name", re.Objectname, @@ -246,23 +311,10 @@ func PrintResponse(resp Response, cli bool, logger *logging.Logger) { for _, r := range resp.Objects { logger.InfoMsg("Response", "name", r.Objectname, - "bin", r.Contract.Evm.Bytecode, + "bin", r.Contract.Code(), "abi", string(r.Contract.Abi[:]), "link", string(r.Contract.Evm.Bytecode.LinkReferences[:]), ) } } } - -func extractObjectNames(script []byte) ([]string, error) { - regExpression, err := regexp.Compile("(contract|library) (.+?) (is)?(.+?)?({)") - if err != nil { - return nil, err - } - objectNamesList := regExpression.FindAllSubmatch(script, -1) - var objects []string - for _, objectNames := range objectNamesList { - objects = append(objects, string(objectNames[2])) - } - return objects, nil -} diff --git a/deploy/compile/compilers_test.go b/deploy/compile/compilers_test.go index d170b204d..33f25d3e2 100644 --- a/deploy/compile/compilers_test.go +++ b/deploy/compile/compilers_test.go @@ -2,12 +2,15 @@ package compile import ( "encoding/json" + "fmt" "os" "os/exec" "path/filepath" "strings" "testing" + "github.com/stretchr/testify/require" + "github.com/hyperledger/burrow/logging" "github.com/stretchr/testify/assert" ) @@ -24,10 +27,6 @@ type SolcResponse struct { Version string `mapstructure:"version" json:"version"` // json encoded } -func BlankSolcItem() *SolcItem { - return &SolcItem{} -} - func BlankSolcResponse() *SolcResponse { return &SolcResponse{ Version: "", @@ -46,6 +45,7 @@ func TestLocalMulti(t *testing.T) { warning, responseJSON := extractWarningJSON(strings.TrimSpace(string(actualOutput))) err = json.Unmarshal([]byte(responseJSON), expectedSolcResponse) + require.NoError(t, err) respItemArray := make([]ResponseItem, 0) @@ -62,7 +62,7 @@ func TestLocalMulti(t *testing.T) { Version: "", Error: "", } - resp, err := Compile("contractImport1.sol", false, "", make(map[string]string), logging.NewNoopLogger()) + resp, err := EVM("contractImport1.sol", false, "", make(map[string]string), logging.NewNoopLogger()) if err != nil { t.Fatal(err) } @@ -90,6 +90,7 @@ func TestLocalSingle(t *testing.T) { warning, responseJSON := extractWarningJSON(strings.TrimSpace(string(actualOutput))) err = json.Unmarshal([]byte(responseJSON), expectedSolcResponse) + require.NoError(t, err) respItemArray := make([]ResponseItem, 0) @@ -109,7 +110,7 @@ func TestLocalSingle(t *testing.T) { Version: "", Error: "", } - resp, err := Compile("simpleContract.sol", false, "", make(map[string]string), logging.NewNoopLogger()) + resp, err := EVM("simpleContract.sol", false, "", make(map[string]string), logging.NewNoopLogger()) if err != nil { t.Fatal(err) } @@ -122,20 +123,18 @@ func TestLocalSingle(t *testing.T) { } func TestFaultyContract(t *testing.T) { - var expectedSolcResponse Response - - actualOutput, err := exec.Command("solc", "--combined-json", "bin,abi", "faultyContract.sol").CombinedOutput() - err = json.Unmarshal(actualOutput, expectedSolcResponse) - t.Log(expectedSolcResponse.Error) - resp, err := Compile("faultyContract.sol", false, "", make(map[string]string), logging.NewNoopLogger()) - t.Log(resp.Error) + const faultyContractFile = "tests/compilers_fixtures/faultyContract.sol" + actualOutput, err := exec.Command("solc", "--combined-json", "bin,abi", faultyContractFile).CombinedOutput() + require.EqualError(t, err, "exit status 1") + resp, err := EVM(faultyContractFile, false, "", make(map[string]string), logging.NewNoopLogger()) + require.NoError(t, err) if err != nil { - if expectedSolcResponse.Error != resp.Error { - t.Errorf("Expected %v got %v", expectedSolcResponse.Error, resp.Error) + if string(actualOutput) != resp.Error { + t.Errorf("Expected %v got %v", string(actualOutput), resp.Error) } } output := strings.TrimSpace(string(actualOutput)) - err = json.Unmarshal([]byte(output), expectedSolcResponse) + fmt.Println(output) } func testContractPath() string { @@ -143,13 +142,6 @@ func testContractPath() string { return filepath.Join(baseDir, "..", "..", "tests", "compilers_fixtures") } -// The solidity 0.4.21 compiler appends something called auxdata to the end of the bin file (this is visible with -// solc --asm). This is a swarm hash of the metadata, and it's always at the end. This includes the path of the -// solidity source file, so it will differ. -func trimAuxdata(bin string) string { - return bin[:len(bin)-86] -} - func extractWarningJSON(output string) (warning string, json string) { jsonBeginsCertainly := strings.Index(output, `{"contracts":`) diff --git a/deploy/compile/solgo/main.go b/deploy/compile/solgo/main.go index 6a86b4edd..ea747c646 100644 --- a/deploy/compile/solgo/main.go +++ b/deploy/compile/solgo/main.go @@ -1,6 +1,7 @@ package main import ( + "flag" "fmt" "os" "path" @@ -10,11 +11,25 @@ import ( ) func main() { - for _, solfile := range os.Args[1:] { - resp, err := compile.Compile(solfile, false, "", nil, logging.NewNoopLogger()) - if err != nil { - fmt.Printf("failed compile solidity: %v\n", err) - os.Exit(1) + wasmPtr := flag.Bool("wasm", false, "Use solang rather than solc") + flag.Parse() + + for _, solfile := range flag.Args() { + var resp *compile.Response + var err error + + if *wasmPtr { + resp, err = compile.WASM(solfile, "", logging.NewNoopLogger()) + if err != nil { + fmt.Printf("failed compile solidity to wasm: %v\n", err) + os.Exit(1) + } + } else { + resp, err = compile.EVM(solfile, false, "", nil, logging.NewNoopLogger()) + if err != nil { + fmt.Printf("failed compile solidity: %v\n", err) + os.Exit(1) + } } if resp.Error != "" { @@ -37,8 +52,12 @@ func main() { f.WriteString("import hex \"github.com/tmthrgd/go-hex\"\n\n") for _, c := range resp.Objects { + code := c.Contract.Evm.Bytecode.Object + if code == "" { + code = c.Contract.EWasm.Wasm + } f.WriteString(fmt.Sprintf("var Bytecode_%s = hex.MustDecodeString(\"%s\")\n", - c.Objectname, c.Contract.Evm.Bytecode.Object)) + c.Objectname, code)) f.WriteString(fmt.Sprintf("var Abi_%s = []byte(`%s`)\n", c.Objectname, c.Contract.Abi)) } diff --git a/deploy/def/client.go b/deploy/def/client.go index 77b966591..1670680fc 100644 --- a/deploy/def/client.go +++ b/deploy/def/client.go @@ -140,10 +140,10 @@ func (c *Client) GetAccount(address crypto.Address) (*acm.Account, error) { return c.queryClient.GetAccount(ctx, &rpcquery.GetAccountParam{Address: address}) } -func (c *Client) GetStorage(address crypto.Address, key binary.Word256) (binary.Word256, error) { +func (c *Client) GetStorage(address crypto.Address, key binary.Word256) ([]byte, error) { val, err := c.queryClient.GetStorage(context.Background(), &rpcquery.GetStorageParam{Address: address, Key: key}) if err != nil { - return binary.Word256{}, err + return []byte{}, err } return val.Value, err } @@ -427,6 +427,7 @@ type CallArg struct { Fee string Gas string Data string + WASM string } func (c *Client) Call(arg *CallArg, logger *logging.Logger) (*payload.CallTx, error) { @@ -435,7 +436,8 @@ func (c *Client) Call(arg *CallArg, logger *logging.Logger) (*payload.CallTx, er "amount", arg.Amount, "sequence", arg.Sequence, "address", arg.Address, - "data", arg.Data) + "data", arg.Data, + "wasm", arg.WASM) input, err := c.TxInput(arg.Input, arg.Amount, arg.Sequence, true, logger) if err != nil { return nil, err @@ -460,10 +462,15 @@ func (c *Client) Call(arg *CallArg, logger *logging.Logger) (*payload.CallTx, er if err != nil { return nil, err } + wasm, err := hex.DecodeString(arg.WASM) + if err != nil { + return nil, err + } tx := &payload.CallTx{ Input: input, Address: contractAddress, Data: code, + WASM: wasm, Fee: fee, GasLimit: gas, } @@ -598,6 +605,9 @@ func (c *Client) TxInput(inputString, amountString, sequenceString string, allow var amount uint64 if amountString != "" { amount, err = c.ParseUint64(amountString) + if err != nil { + return nil, err + } } var sequence uint64 sequence, err = c.getSequence(sequenceString, inputAddress, c.MempoolSigning && allowMempoolSigning, logger) diff --git a/deploy/def/client_test.go b/deploy/def/client_test.go index fe8cb5809..d64ad7742 100644 --- a/deploy/def/client_test.go +++ b/deploy/def/client_test.go @@ -13,5 +13,5 @@ func TestArgMap(t *testing.T) { }) fmt.Println(mp) assert.Equal(t, "fooo", mp["Address"]) - assert.Len(t, mp, 7) + assert.Len(t, mp, 8) } diff --git a/deploy/def/deploy.go b/deploy/def/deploy.go index 18550adfc..7dc1b9fe1 100644 --- a/deploy/def/deploy.go +++ b/deploy/def/deploy.go @@ -11,6 +11,7 @@ type DeployArgs struct { Chain string `mapstructure:"," json:"," yaml:"," toml:","` KeysService string `mapstructure:"," json:"," yaml:"," toml:","` MempoolSign bool `mapstructure:"," json:"," yaml:"," toml:","` + Wasm bool `mapstructure:"," json:"," yaml:"," toml:","` Timeout int `mapstructure:"," json:"," yaml:"," toml:","` Address string `mapstructure:"," json:"," yaml:"," toml:","` BinPath string `mapstructure:"," json:"," yaml:"," toml:","` diff --git a/deploy/jobs/job_manager.go b/deploy/jobs/job_manager.go index c0efe8dd3..10fe303b0 100644 --- a/deploy/jobs/job_manager.go +++ b/deploy/jobs/job_manager.go @@ -24,27 +24,40 @@ type solidityCompilerWork struct { workDir string } -type intermediateJob struct { +type compilerJob struct { work solidityCompilerWork compilerResp *compilers.Response err error done chan struct{} } -func intermediateJobRunner(jobs chan *intermediateJob, logger *logging.Logger) { +func solcRunner(jobs chan *compilerJob, logger *logging.Logger) { for { - intermediate, ok := <-jobs + job, ok := <-jobs if !ok { break } - resp, err := compilers.Compile(intermediate.work.contractName, false, intermediate.work.workDir, nil, logger) - (*intermediate).compilerResp = resp - (*intermediate).err = err - close(intermediate.done) + resp, err := compilers.EVM(job.work.contractName, false, job.work.workDir, nil, logger) + (*job).compilerResp = resp + (*job).err = err + close(job.done) } } -func queueCompilerWork(job *def.Job, playbook *def.Playbook, jobs chan *intermediateJob) error { +func solangRunner(jobs chan *compilerJob, logger *logging.Logger) { + for { + job, ok := <-jobs + if !ok { + return + } + resp, err := compilers.WASM(job.work.contractName, job.work.workDir, logger) + (*job).compilerResp = resp + (*job).err = err + close(job.done) + } +} + +func queueCompilerWork(job *def.Job, playbook *def.Playbook, jobs chan *compilerJob) error { payload, err := job.Payload() if err != nil { return fmt.Errorf("could not get Job payload: %v", payload) @@ -53,7 +66,7 @@ func queueCompilerWork(job *def.Job, playbook *def.Playbook, jobs chan *intermed // Do compilation first switch payload.(type) { case *def.Build: - intermediate := intermediateJob{ + intermediate := compilerJob{ done: make(chan struct{}), work: solidityCompilerWork{ contractName: job.Build.Contract, @@ -64,7 +77,7 @@ func queueCompilerWork(job *def.Job, playbook *def.Playbook, jobs chan *intermed jobs <- &intermediate case *def.Deploy: if filepath.Ext(job.Deploy.Contract) == ".sol" { - intermediate := intermediateJob{ + intermediate := compilerJob{ done: make(chan struct{}), work: solidityCompilerWork{ contractName: job.Deploy.Contract, @@ -94,7 +107,7 @@ func queueCompilerWork(job *def.Job, playbook *def.Playbook, jobs chan *intermed } func getCompilerWork(intermediate interface{}) (*compilers.Response, error) { - if intermediate, ok := intermediate.(*intermediateJob); ok { + if intermediate, ok := intermediate.(*compilerJob); ok { <-intermediate.done return intermediate.compilerResp, intermediate.err @@ -160,6 +173,9 @@ func doJobs(playbook *def.Playbook, args *def.DeployArgs, client *def.Client, lo return err } job.Result, err = SendJob(job.Send, tx, playbook.Account, client, logger) + if err != nil { + return err + } case *def.RegisterName: announce(job.Name, "RegisterName", logger) txs, err := FormulateRegisterNameJob(job.RegisterName, args, playbook, client, logger) @@ -167,6 +183,9 @@ func doJobs(playbook *def.Playbook, args *def.DeployArgs, client *def.Client, lo return err } job.Result, err = RegisterNameJob(job.RegisterName, args, playbook, txs, client, logger) + if err != nil { + return err + } case *def.Permission: announce(job.Name, "Permission", logger) tx, err := FormulatePermissionJob(job.Permission, playbook.Account, client, logger) @@ -174,6 +193,9 @@ func doJobs(playbook *def.Playbook, args *def.DeployArgs, client *def.Client, lo return err } job.Result, err = PermissionJob(job.Permission, playbook.Account, tx, client, logger) + if err != nil { + return err + } // Contracts jobs case *def.Deploy: @@ -262,11 +284,15 @@ func ExecutePlaybook(args *def.DeployArgs, playbook *def.Playbook, client *def.C return fmt.Errorf("error validating Burrow deploy file at %s: %v", playbook.Filename, err) } - jobs := make(chan *intermediateJob, concurrentSolcWorkQueue) + jobs := make(chan *compilerJob, concurrentSolcWorkQueue) defer close(jobs) for i := 0; i < concurrentSolc; i++ { - go intermediateJobRunner(jobs, logger) + if args.Wasm { + go solangRunner(jobs, logger) + } else { + go solcRunner(jobs, logger) + } } for _, job := range playbook.Jobs { diff --git a/deploy/jobs/jobs_contracts.go b/deploy/jobs/jobs_contracts.go index 0a6ca39d9..e8bc54065 100644 --- a/deploy/jobs/jobs_contracts.go +++ b/deploy/jobs/jobs_contracts.go @@ -163,7 +163,7 @@ func FormulateDeployJob(deploy *def.Deploy, do *def.DeployArgs, deployScript *de contractCode = contractCode + callData } - tx, err := deployTx(client, deploy, contractName, string(contractCode), logger) + tx, err := deployTx(client, deploy, contractName, string(contractCode), "", logger) if err != nil { return nil, nil, fmt.Errorf("could not deploy binary contract: %v", err) } @@ -196,7 +196,7 @@ func FormulateDeployJob(deploy *def.Deploy, do *def.DeployArgs, deployScript *de "path", contractPath, "abi", string(response.Contract.Abi), "bin", response.Contract.Evm.Bytecode.Object) - if response.Contract.Evm.Bytecode.Object == "" { + if response.Contract.Evm.Bytecode.Object == "" && response.Contract.EWasm.Wasm == "" { return nil, nil, errCodeMissing } mergeAbiSpecBytes(client, response.Contract.Abi) @@ -214,7 +214,7 @@ func FormulateDeployJob(deploy *def.Deploy, do *def.DeployArgs, deployScript *de var baseContract *compilers.ResponseItem deployedCount := 0 for i, response := range resp.Objects { - if response.Contract.Evm.Bytecode.Object == "" { + if response.Contract.Evm.Bytecode.Object == "" && response.Contract.EWasm.Wasm == "" { continue } mergeAbiSpecBytes(client, response.Contract.Abi) @@ -223,7 +223,7 @@ func FormulateDeployJob(deploy *def.Deploy, do *def.DeployArgs, deployScript *de return nil, nil, err } deployedCount++ - if strings.ToLower(response.Objectname) == strings.ToLower(strings.TrimSuffix(filepath.Base(deploy.Contract), filepath.Ext(filepath.Base(deploy.Contract)))) { + if strings.EqualFold(response.Objectname, strings.TrimSuffix(filepath.Base(deploy.Contract), filepath.Ext(filepath.Base(deploy.Contract)))) { baseObj = tx baseContract = &resp.Objects[i] } else { @@ -248,7 +248,7 @@ func FormulateDeployJob(deploy *def.Deploy, do *def.DeployArgs, deployScript *de continue } if matchInstanceName(response.Objectname, deploy.Instance) { - if response.Contract.Evm.Bytecode.Object == "" { + if response.Contract.Evm.Bytecode.Object == "" && response.Contract.EWasm.Wasm == "" { return nil, nil, errCodeMissing } logger.TraceMsg("Deploy contract", @@ -310,7 +310,7 @@ func matchInstanceName(objectName, deployInstance string) bool { objectNameParts := strings.Split(objectName, ":") deployInstanceParts := strings.Split(deployInstance, "/") - return strings.ToLower(objectNameParts[len(objectNameParts)-1]) == strings.ToLower(deployInstanceParts[len(deployInstanceParts)-1]) + return strings.EqualFold(objectNameParts[len(objectNameParts)-1], deployInstanceParts[len(deployInstanceParts)-1]) } func findContractFile(contract, binPath string, deployPath string) (string, error) { @@ -351,11 +351,17 @@ func deployContract(deploy *def.Deploy, do *def.DeployArgs, script *def.Playbook } } - err = contract.Link(libs) - if err != nil { - return nil, err + wasm := "" + data := "" + if contract.EWasm.Wasm != "" { + wasm = contract.EWasm.Wasm + } else { + err = contract.Link(libs) + if err != nil { + return nil, err + } + data = contract.Evm.Bytecode.Object } - contractCode := contract.Evm.Bytecode.Object if deploy.Data != nil { _, callDataArray, err := util.PreProcessInputData(compilersResponse.Objectname, deploy.Data, do, script, client, true, logger) @@ -367,7 +373,7 @@ func deployContract(deploy *def.Deploy, do *def.DeployArgs, script *def.Playbook return nil, err } callData := hex.EncodeToString(packedBytes) - contractCode = contractCode + callData + data = data + callData } else { // No constructor arguments were provided. Did the constructor want any? spec, err := abi.ReadAbiSpec(compilersResponse.Contract.Abi) @@ -381,15 +387,16 @@ func deployContract(deploy *def.Deploy, do *def.DeployArgs, script *def.Playbook } } - return deployTx(client, deploy, compilersResponse.Objectname, contractCode, logger) + return deployTx(client, deploy, compilersResponse.Objectname, data, wasm, logger) } -func deployTx(client *def.Client, deploy *def.Deploy, contractName, contractCode string, logger *logging.Logger) (*payload.CallTx, error) { +func deployTx(client *def.Client, deploy *def.Deploy, contractName, data, wasm string, logger *logging.Logger) (*payload.CallTx, error) { // Deploy contract logger.TraceMsg("Deploying Contract", "contract", contractName, "source", deploy.Source, - "code", contractCode, + "data", data, + "wasm", wasm, "chain", client.ChainAddress) return client.Call(&def.CallArg{ @@ -397,7 +404,8 @@ func deployTx(client *def.Client, deploy *def.Deploy, contractName, contractCode Amount: deploy.Amount, Fee: deploy.Fee, Gas: deploy.Gas, - Data: contractCode, + Data: data, + WASM: wasm, Sequence: deploy.Sequence, }, logger) } diff --git a/docs/README.md b/docs/README.md index aa93d6779..ce2f74fc0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -5,13 +5,17 @@ Hyperledger Burrow is a permissioned Ethereum smart-contract blockchain node. It ![burrow logo](assets/images/burrow.png) 1. [Installation](INSTALL.md) -1. [Logging](LOGGING.md) -1. [Quickstart](quickstart) +2. [Logging](LOGGING.md) +3. [Quickstart](quickstart) * [Single full node](quickstart/single-full-node.md) - start your first chain * [Send transactions](quickstart/send-transactions.md) - how to communicate with your Burrow chain * [Deploy contracts](quickstart/deploy-contracts.md) - interact with the Ethereum Virtual Machine * [Multiple validators](quickstart/multiple-validators.md) - advanced consensus setup * [Adding validators](quickstart/add-validators.md) - bonding a new party * [Seed nodes](quickstart/seed-nodes.md) - add new node dynamically - * [Kubernetes](https://github.com/helm/charts/tree/master/stable/burrow) - bootstraps a burrow network on a Kubernetes cluster -1. [Dump and restore a chain](dump-restore.md) + * [Dump / restore](design/dump-restore.md) - create a new chain with previous state +4. [Genesis](design/genesis.md) +5. [Permissions](design/permissions.md) +6. [Architecture](arch) + * [State](arch/state.md) +7. [Kubernetes](https://github.com/helm/charts/tree/master/stable/burrow) - bootstraps a burrow network on a Kubernetes cluster diff --git a/docs/architecture/state.md b/docs/architecture/state.md new file mode 100644 index 000000000..2128ce4aa --- /dev/null +++ b/docs/architecture/state.md @@ -0,0 +1,7 @@ +# State + +Burrow wraps its state in a 'mutable forest' which contains one 'commits' tree and an 'immutable forest'. The former implementation contains +commit IDs generated from all sub-trees in the 'immutable forest' thereby providing the state root hash. Each tree in our 'immutable forest' +is lazily loaded by prefix (i.e. initialized if it does not exist), returning a read/write tree. This contains immutable snapshots of its +history for reading, as well as a mutable tree for accumulating state. All trees ultimately wrap [IAVL](https://github.com/tendermint/iavl), +an (immutable) AVL+ library, persisted in [goleveldb](https://github.com/syndtr/goleveldb) - a key/value database. \ No newline at end of file diff --git a/docs/permissions.md b/docs/permissions.md index 12591e735..546c81d26 100644 --- a/docs/permissions.md +++ b/docs/permissions.md @@ -1,8 +1,7 @@ -# Burrow Permissions +# Permissions Burrow supports permissions via permission flags and string tags called 'roles'. - -The flag permissions are +The flag permissions are: | Permission Flag | Capability | Purpose | |-----------------|------------|---------| @@ -43,4 +42,4 @@ An example `genesis.json`: } ``` -See [genesis](genesis.md) for more details on constructing accounts and setting some useful presets +See [genesis](genesis.md) for more details on constructing accounts and setting some useful presets. diff --git a/docs/dump-restore.md b/docs/quickstart/dump-restore.md similarity index 100% rename from docs/dump-restore.md rename to docs/quickstart/dump-restore.md diff --git a/dump/dump.go b/dump/dump.go index 31f96cd61..929593bbd 100644 --- a/dump/dump.go +++ b/dump/dump.go @@ -53,7 +53,7 @@ func NewDumper(state *state.State, blockchain bcm.BlockchainInfo, logger *loggin func (ds *Dumper) Transmit(stream Sender, startHeight, endHeight uint64, options Option) error { height := endHeight - if height <= 0 { + if height == 0 { height = ds.blockchain.LastBlockHeight() } st, err := ds.state.LoadHeight(height) @@ -74,7 +74,7 @@ func (ds *Dumper) Transmit(stream Sender, startHeight, endHeight uint64, options Storage: make([]*Storage, 0), } - err = st.IterateStorage(acc.Address, func(key, value binary.Word256) error { + err = st.IterateStorage(acc.Address, func(key binary.Word256, value []byte) error { storage.Storage = append(storage.Storage, &Storage{Key: key, Value: value}) return nil }) diff --git a/dump/dump.pb.go b/dump/dump.pb.go index 4b3c5f45c..adb99f74b 100644 --- a/dump/dump.pb.go +++ b/dump/dump.pb.go @@ -35,11 +35,11 @@ var _ = time.Kitchen const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package type Storage struct { - Key github_com_hyperledger_burrow_binary.Word256 `protobuf:"bytes,1,opt,name=Key,proto3,customtype=github.com/hyperledger/burrow/binary.Word256" json:"Key"` - Value github_com_hyperledger_burrow_binary.Word256 `protobuf:"bytes,2,opt,name=Value,proto3,customtype=github.com/hyperledger/burrow/binary.Word256" json:"Value"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Key github_com_hyperledger_burrow_binary.Word256 `protobuf:"bytes,1,opt,name=Key,proto3,customtype=github.com/hyperledger/burrow/binary.Word256" json:"Key"` + Value github_com_hyperledger_burrow_binary.HexBytes `protobuf:"bytes,2,opt,name=Value,proto3,customtype=github.com/hyperledger/burrow/binary.HexBytes" json:"Value"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Storage) Reset() { *m = Storage{} } @@ -298,36 +298,37 @@ func init() { proto.RegisterFile("dump.proto", fileDescriptor_58418148159c29a6) func init() { golang_proto.RegisterFile("dump.proto", fileDescriptor_58418148159c29a6) } var fileDescriptor_58418148159c29a6 = []byte{ - // 463 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x52, 0xbb, 0x6e, 0x13, 0x41, - 0x14, 0x65, 0xe2, 0x75, 0x9c, 0x5c, 0x87, 0x14, 0x23, 0x84, 0x56, 0x2e, 0xd6, 0xd6, 0x0a, 0x41, - 0x84, 0x60, 0x2c, 0x99, 0x87, 0x52, 0xd0, 0xc4, 0xc4, 0x88, 0x67, 0x8a, 0x21, 0x0a, 0x12, 0xdd, - 0x3e, 0x86, 0xf1, 0x4a, 0xde, 0x9d, 0xd5, 0xec, 0x2c, 0xb0, 0x3d, 0x0d, 0x1d, 0x3f, 0xc0, 0xbf, - 0x50, 0xba, 0x44, 0x94, 0x14, 0x01, 0x39, 0x3f, 0x82, 0x76, 0x1e, 0x18, 0x52, 0x20, 0xa1, 0x74, - 0xf7, 0xde, 0x33, 0xf7, 0xcc, 0x99, 0x73, 0x06, 0x20, 0xad, 0xf3, 0x92, 0x94, 0x52, 0x28, 0x81, - 0xbd, 0xb6, 0x1e, 0xdc, 0xe6, 0x99, 0x9a, 0xd7, 0x31, 0x49, 0x44, 0x3e, 0xe6, 0x82, 0x8b, 0xb1, - 0x06, 0xe3, 0xfa, 0x8d, 0xee, 0x74, 0xa3, 0x2b, 0xb3, 0x34, 0x18, 0x72, 0x21, 0xf8, 0x82, 0xad, - 0x4f, 0xa9, 0x2c, 0x67, 0x95, 0x8a, 0x1c, 0xeb, 0x60, 0x3b, 0x4a, 0x72, 0x5b, 0x02, 0x7b, 0xcf, - 0x12, 0x5b, 0xf7, 0x8b, 0x28, 0x67, 0x95, 0x69, 0xc2, 0xcf, 0x08, 0x7a, 0x2f, 0x95, 0x90, 0x11, - 0x67, 0xf8, 0x11, 0x74, 0x9e, 0xb1, 0xc6, 0x47, 0x23, 0xb4, 0xb7, 0x33, 0xbd, 0xbb, 0x3c, 0x1d, - 0x5e, 0xfa, 0x7e, 0x3a, 0xbc, 0xf5, 0x87, 0xa8, 0x79, 0x53, 0x32, 0xb9, 0x60, 0x29, 0x67, 0x72, - 0x1c, 0xd7, 0x52, 0x8a, 0x77, 0xe3, 0x38, 0x2b, 0x22, 0xd9, 0x90, 0x57, 0x42, 0xa6, 0x93, 0x7b, - 0xf7, 0x69, 0x4b, 0x80, 0x9f, 0x42, 0xf7, 0x24, 0x5a, 0xd4, 0xcc, 0xdf, 0xb8, 0x00, 0x93, 0xa1, - 0x08, 0x3f, 0x22, 0xd8, 0x3d, 0x48, 0x12, 0x51, 0x17, 0xca, 0xc9, 0x3c, 0x82, 0xde, 0x41, 0x9a, - 0x4a, 0x56, 0x55, 0xff, 0x27, 0x35, 0x91, 0x4d, 0xa9, 0x04, 0xb1, 0xbb, 0xd4, 0x91, 0xe0, 0x1b, - 0xbf, 0x1d, 0xf0, 0x37, 0x46, 0x9d, 0xbd, 0xfe, 0xe4, 0x32, 0xd1, 0xd1, 0xd8, 0x21, 0x75, 0x68, - 0xf8, 0x01, 0xc1, 0xd6, 0xec, 0xe4, 0xc5, 0xec, 0x2d, 0x2b, 0x14, 0xf6, 0xa1, 0xf7, 0x70, 0x1e, - 0x65, 0xc5, 0x93, 0x43, 0xad, 0x62, 0x9b, 0xba, 0x16, 0xef, 0x83, 0x77, 0x9c, 0xe5, 0xe6, 0xf5, - 0xfd, 0xc9, 0x80, 0x98, 0x98, 0x88, 0x8b, 0x89, 0x1c, 0xbb, 0x98, 0xa6, 0x5b, 0xad, 0xf0, 0x4f, - 0x3f, 0x86, 0x88, 0xea, 0x0d, 0x7c, 0x0d, 0xba, 0x9a, 0xdc, 0xef, 0xe8, 0xd5, 0x5d, 0xa2, 0x53, - 0x7b, 0x2e, 0xb8, 0x9e, 0x52, 0x03, 0x86, 0xdf, 0x10, 0x78, 0x87, 0x75, 0x5e, 0xe2, 0xab, 0xb0, - 0xf9, 0x98, 0x65, 0x7c, 0xae, 0xb4, 0x02, 0x8f, 0xda, 0x0e, 0x5f, 0x87, 0x9e, 0xb5, 0xcc, 0x6a, - 0xd8, 0x21, 0xed, 0x4f, 0xb0, 0x33, 0xea, 0x40, 0xfc, 0xe0, 0xbc, 0xb5, 0xf6, 0xde, 0x2b, 0xe6, - 0xfd, 0x7f, 0x63, 0xf4, 0x7c, 0x0c, 0x37, 0xd7, 0x66, 0xf8, 0x9e, 0xd5, 0xab, 0xf7, 0xdc, 0x94, - 0xae, 0xcd, 0x1a, 0x81, 0x77, 0x14, 0xe5, 0xcc, 0xef, 0x5a, 0x39, 0xe6, 0x07, 0xce, 0x0a, 0x25, - 0x1b, 0xaa, 0x91, 0xe9, 0xfe, 0x72, 0x15, 0xa0, 0xaf, 0xab, 0x00, 0xfd, 0x5c, 0x05, 0xe8, 0xcb, - 0x59, 0x80, 0x96, 0x67, 0x01, 0x7a, 0x1d, 0xfe, 0x3b, 0xd1, 0xf6, 0xba, 0x78, 0x53, 0x1b, 0x7b, - 0xe7, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, 0xcf, 0xbc, 0xb3, 0xac, 0x50, 0x03, 0x00, 0x00, + // 475 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x52, 0xbf, 0x6f, 0x13, 0x31, + 0x14, 0xc6, 0xcd, 0xa5, 0x69, 0x9d, 0xd2, 0xc1, 0x42, 0xe8, 0x94, 0xe1, 0x12, 0x9d, 0x10, 0x54, + 0x88, 0x3a, 0x52, 0xa0, 0xa8, 0x03, 0x4b, 0x43, 0x83, 0x8a, 0x0a, 0x1d, 0x4c, 0x55, 0x24, 0xb6, + 0xfb, 0xf1, 0xf0, 0x9d, 0x94, 0x3b, 0x9f, 0x7c, 0x3e, 0xe8, 0xed, 0x2c, 0x6c, 0xfc, 0x05, 0xfc, + 0x2d, 0x8c, 0x19, 0x11, 0x23, 0x43, 0x41, 0xe9, 0x3f, 0x82, 0xce, 0x67, 0x13, 0xe8, 0x80, 0xe8, + 0xf6, 0xde, 0xfb, 0xfc, 0x3e, 0x7f, 0xfe, 0x3e, 0x63, 0x1c, 0x57, 0x59, 0x41, 0x0b, 0x29, 0x94, + 0x20, 0x4e, 0x53, 0x0f, 0x76, 0x79, 0xaa, 0x92, 0x2a, 0xa4, 0x91, 0xc8, 0xc6, 0x5c, 0x70, 0x31, + 0xd6, 0x60, 0x58, 0xbd, 0xd5, 0x9d, 0x6e, 0x74, 0xd5, 0x2e, 0x0d, 0x86, 0x5c, 0x08, 0x3e, 0x87, + 0xd5, 0x29, 0x95, 0x66, 0x50, 0xaa, 0xc0, 0xb2, 0x0e, 0x36, 0x83, 0x28, 0x33, 0x25, 0x86, 0x73, + 0x88, 0x4c, 0xdd, 0xcf, 0x83, 0x0c, 0xca, 0xb6, 0xf1, 0x3f, 0x23, 0xdc, 0x7b, 0xa5, 0x84, 0x0c, + 0x38, 0x90, 0x67, 0xb8, 0x73, 0x0c, 0xb5, 0x8b, 0x46, 0x68, 0x67, 0x6b, 0xfa, 0x68, 0x71, 0x31, + 0xbc, 0xf1, 0xfd, 0x62, 0xf8, 0xe0, 0x0f, 0x51, 0x49, 0x5d, 0x80, 0x9c, 0x43, 0xcc, 0x41, 0x8e, + 0xc3, 0x4a, 0x4a, 0xf1, 0x7e, 0x1c, 0xa6, 0x79, 0x20, 0x6b, 0xfa, 0x5a, 0xc8, 0x78, 0xb2, 0xf7, + 0x98, 0x35, 0x04, 0xe4, 0x18, 0x77, 0xcf, 0x82, 0x79, 0x05, 0xee, 0x9a, 0x66, 0xda, 0x33, 0x4c, + 0xbb, 0xff, 0xc5, 0x74, 0x04, 0xe7, 0xd3, 0x5a, 0x41, 0xc9, 0x5a, 0x0e, 0xff, 0x23, 0xc2, 0xdb, + 0x07, 0x51, 0x24, 0xaa, 0x5c, 0x59, 0x9d, 0x27, 0xb8, 0x77, 0x10, 0xc7, 0x12, 0xca, 0xf2, 0x7a, + 0x5a, 0x23, 0x59, 0x17, 0x4a, 0x50, 0xb3, 0xcb, 0x2c, 0x09, 0xb9, 0xf7, 0xdb, 0x02, 0x77, 0x6d, + 0xd4, 0xd9, 0xe9, 0x4f, 0x6e, 0x52, 0x9d, 0x8d, 0x19, 0x32, 0x8b, 0xfa, 0x1f, 0x10, 0xde, 0x98, + 0x9d, 0xbd, 0x9c, 0xbd, 0x83, 0x5c, 0x11, 0x17, 0xf7, 0x9e, 0x26, 0x41, 0x9a, 0x3f, 0x3f, 0xd4, + 0x2a, 0x36, 0x99, 0x6d, 0xc9, 0x3e, 0x76, 0x4e, 0xd3, 0xac, 0x7d, 0x7e, 0x7f, 0x32, 0xa0, 0x6d, + 0x4e, 0xd4, 0xe6, 0x44, 0x4f, 0x6d, 0x4e, 0xd3, 0x8d, 0x46, 0xf8, 0xa7, 0x1f, 0x43, 0xc4, 0xf4, + 0x06, 0xb9, 0x83, 0xbb, 0x9a, 0xdc, 0xed, 0xe8, 0xd5, 0x6d, 0xaa, 0x63, 0x7b, 0x21, 0xb8, 0x9e, + 0xb2, 0x16, 0xf4, 0xbf, 0x21, 0xec, 0x1c, 0x56, 0x59, 0x41, 0x6e, 0xe3, 0xf5, 0x23, 0x48, 0x79, + 0xa2, 0xb4, 0x02, 0x87, 0x99, 0x8e, 0xdc, 0xc5, 0x3d, 0x63, 0x99, 0xd1, 0xb0, 0x45, 0x9b, 0xaf, + 0x60, 0x66, 0xcc, 0x82, 0xe4, 0xc9, 0x55, 0x6b, 0xcd, 0xbd, 0xb7, 0xda, 0xf7, 0xff, 0x8d, 0xb1, + 0xab, 0x31, 0xdc, 0x5f, 0x99, 0xe1, 0x3a, 0x46, 0xaf, 0xde, 0xb3, 0x53, 0xb6, 0x32, 0x6b, 0x84, + 0x9d, 0x93, 0x20, 0x03, 0xb7, 0x6b, 0xe4, 0xb4, 0x5f, 0x70, 0x96, 0x2b, 0x59, 0x33, 0x8d, 0x4c, + 0xf7, 0x17, 0x4b, 0x0f, 0x7d, 0x5d, 0x7a, 0xe8, 0xe7, 0xd2, 0x43, 0x5f, 0x2e, 0x3d, 0xb4, 0xb8, + 0xf4, 0xd0, 0x1b, 0xff, 0xdf, 0x89, 0x36, 0xd7, 0x85, 0xeb, 0xda, 0xd8, 0x87, 0xbf, 0x02, 0x00, + 0x00, 0xff, 0xff, 0x60, 0x4c, 0x49, 0xe5, 0x51, 0x03, 0x00, 0x00, } func (m *Storage) Marshal() (dAtA []byte, err error) { diff --git a/dump/load.go b/dump/load.go index 938c210e4..cadce858b 100644 --- a/dump/load.go +++ b/dump/load.go @@ -2,6 +2,7 @@ package dump import ( "crypto/sha256" + bin "encoding/binary" "github.com/hyperledger/burrow/acm" "github.com/hyperledger/burrow/binary" @@ -98,6 +99,8 @@ func Load(reader Reader, st *state.State) error { func dumpTxHash(chainID string, lastHeight uint64) binary.HexBytes { hasher := sha256.New() hasher.Write([]byte(chainID)) - hasher.Write(binary.Uint64Bytes(lastHeight)) + bs := make([]byte, 8) + bin.BigEndian.PutUint64(bs, lastHeight) + hasher.Write(bs) return hasher.Sum(nil) } diff --git a/dump/mock_reader_test.go b/dump/mock_reader_test.go index 71350cf7c..8eecb732b 100644 --- a/dump/mock_reader_test.go +++ b/dump/mock_reader_test.go @@ -1,6 +1,7 @@ package dump import ( + bin "encoding/binary" "fmt" "math/rand" @@ -23,7 +24,7 @@ func (m *MockDumpReader) Next() (*Dump, error) { if m.accounts > 0 { var addr crypto.Address - binary.PutUint64(addr.Bytes(), uint64(m.accounts)) + bin.BigEndian.PutUint64(addr.Bytes(), uint64(m.accounts)) row.Account = &acm.Account{ Address: addr, @@ -31,14 +32,14 @@ func (m *MockDumpReader) Next() (*Dump, error) { } if m.accounts%2 > 0 { - row.Account.Code = make([]byte, rand.Int()%10000) + row.Account.EVMCode = make([]byte, rand.Int()%10000) } else { row.Account.PublicKey = crypto.PublicKey{} } m.accounts-- } else if m.storage > 0 { var addr crypto.Address - binary.PutUint64(addr.Bytes(), uint64(m.storage)) + bin.BigEndian.PutUint64(addr.Bytes(), uint64(m.storage)) storagelen := rand.Int() % 25 row.AccountStorage = &AccountStorage{ diff --git a/event/pubsub/pubsub_test.go b/event/pubsub/pubsub_test.go index 76525243d..94da8c07d 100644 --- a/event/pubsub/pubsub_test.go +++ b/event/pubsub/pubsub_test.go @@ -111,11 +111,11 @@ func TestResubscribe(t *testing.T) { defer s.Stop() ctx := context.Background() - ch, err := s.Subscribe(ctx, clientID, query.Empty{}, 1) + _, err := s.Subscribe(ctx, clientID, query.Empty{}, 1) require.NoError(t, err) err = s.Unsubscribe(ctx, clientID, query.Empty{}) require.NoError(t, err) - ch, err = s.Subscribe(ctx, clientID, query.Empty{}, 1) + ch, err := s.Subscribe(ctx, clientID, query.Empty{}, 1) require.NoError(t, err) err = s.Publish(ctx, "Cable") diff --git a/event/query/builder.go b/event/query/builder.go index 249ae1b7d..4e8d3dd3c 100644 --- a/event/query/builder.go +++ b/event/query/builder.go @@ -203,6 +203,8 @@ func StringFromValue(value interface{}) string { switch v := value.(type) { case string: return v + case time.Time: + return timeString + " " + v.Format(time.RFC3339) case encoding.TextMarshaler: bs, _ := v.MarshalText() return string(bs) @@ -229,8 +231,6 @@ func StringFromValue(value interface{}) string { return strconv.FormatFloat(float64(v), 'f', -1, 32) case float64: return strconv.FormatFloat(float64(v), 'f', -1, 64) - case time.Time: - return timeString + " " + v.Format(time.RFC3339) default: if rv.Kind() == reflect.Slice { values := make([]string, rv.Len()) diff --git a/event/query/reflect_tagged_test.go b/event/query/reflect_tagged_test.go index 7aec3fd99..3e2392ec8 100644 --- a/event/query/reflect_tagged_test.go +++ b/event/query/reflect_tagged_test.go @@ -10,12 +10,11 @@ import ( ) type testTaggable struct { - Foo string - Bar string - Baz binary.HexBytes - Address crypto.Address - Indices []int - unexported int + Foo string + Bar string + Baz binary.HexBytes + Address crypto.Address + Indices []int } func TestReflectTagged_Keys(t *testing.T) { diff --git a/event/query/tags.go b/event/query/tags.go index 2cb5d13cd..f1ace8e45 100644 --- a/event/query/tags.go +++ b/event/query/tags.go @@ -52,9 +52,8 @@ func (ts TagMap) Keys() []string { } type CombinedTags struct { - keys []string - ks map[string][]Tagged - concat bool + keys []string + ks map[string][]Tagged } func NewCombinedTags() *CombinedTags { diff --git a/execution/contexts/call_context.go b/execution/contexts/call_context.go index c76475338..75a1f5132 100644 --- a/execution/contexts/call_context.go +++ b/execution/contexts/call_context.go @@ -10,6 +10,7 @@ import ( "github.com/hyperledger/burrow/execution/errors" "github.com/hyperledger/burrow/execution/evm" "github.com/hyperledger/burrow/execution/exec" + "github.com/hyperledger/burrow/execution/wasm" "github.com/hyperledger/burrow/logging" "github.com/hyperledger/burrow/logging/structure" "github.com/hyperledger/burrow/txs/payload" @@ -130,6 +131,7 @@ func (ctx *CallContext) Deliver(inAcc, outAcc *acm.Account, value uint64) error caller crypto.Address = inAcc.Address callee crypto.Address = crypto.ZeroAddress // initialized below code []byte = nil + wcode []byte = nil ret []byte = nil txCache = evm.NewState(ctx.StateWriter, ctx.Blockchain.BlockHash, acmstate.Named("TxCache")) params = evm.Params{ @@ -144,12 +146,13 @@ func (ctx *CallContext) Deliver(inAcc, outAcc *acm.Account, value uint64) error // We already checked for permission callee = crypto.NewContractAddress(caller, ctx.txe.TxHash) code = ctx.tx.Data + wcode = ctx.tx.WASM txCache.CreateAccount(callee) ctx.Logger.TraceMsg("Creating new contract", "contract_address", callee, "init_code", code) } else { - if outAcc == nil || len(outAcc.Code) == 0 { + if outAcc == nil || (len(outAcc.EVMCode) == 0 && len(outAcc.WASMCode) == 0) { // if you call an account that doesn't exist // or an account with no code then we take fees (sorry pal) // NOTE: it's fine to create a contract and call it within one @@ -176,7 +179,8 @@ func (ctx *CallContext) Deliver(inAcc, outAcc *acm.Account, value uint64) error return nil } callee = outAcc.Address - code = txCache.GetCode(callee) + code = txCache.GetEVMCode(callee) + wcode = txCache.GetWASMCode(callee) ctx.Logger.TraceMsg("Calling existing contract", "contract_address", callee, "input", ctx.tx.Data, @@ -186,27 +190,52 @@ func (ctx *CallContext) Deliver(inAcc, outAcc *acm.Account, value uint64) error txHash := ctx.txe.Envelope.Tx.Hash() logger := ctx.Logger.With(structure.TxHashKey, txHash) - vmach := evm.NewVM(params, caller, txHash, logger, ctx.VMOptions...) - ret, exception := vmach.Call(txCache, ctx.txe, caller, callee, code, ctx.tx.Data, value, &gas) - if exception != nil { - // Failure. Charge the gas fee. The 'value' was otherwise not transferred. - ctx.Logger.InfoMsg("Error on execution", - structure.ErrorKey, exception) - - ctx.txe.PushError(errors.ErrorCodef(exception.ErrorCode(), "call error: %s\nEVM call trace: %s", - exception.String(), ctx.txe.CallTrace())) - } else { - ctx.Logger.TraceMsg("Successful execution") + var exception errors.CodedError + if wcode != nil { if createContract { - txCache.InitCode(callee, ret) + txCache.InitWASMCode(callee, wcode) } - err := txCache.Sync() - if err != nil { - return err + ret, exception = wasm.RunWASM(txCache, callee, createContract, wcode, ctx.tx.Data) + if exception != nil { + // Failure. Charge the gas fee. The 'value' was otherwise not transferred. + ctx.Logger.InfoMsg("Error on WASM execution", + structure.ErrorKey, exception) + + ctx.txe.PushError(errors.ErrorCodef(exception.ErrorCode(), "call error: %s\n", + exception.String())) + } else { + ctx.Logger.TraceMsg("Successful execution") + err := txCache.Sync() + if err != nil { + return err + } + } + ctx.txe.Return(ret, ctx.tx.GasLimit-gas) + } else { + // EVM + vmach := evm.NewVM(params, caller, txHash, logger, ctx.VMOptions...) + ret, exception = vmach.Call(txCache, ctx.txe, caller, callee, code, ctx.tx.Data, value, &gas) + if exception != nil { + // Failure. Charge the gas fee. The 'value' was otherwise not transferred. + ctx.Logger.InfoMsg("Error on EVM execution", + structure.ErrorKey, exception) + + ctx.txe.PushError(errors.ErrorCodef(exception.ErrorCode(), "call error: %s\nEVM call trace: %s", + exception.String(), ctx.txe.CallTrace())) + } else { + ctx.Logger.TraceMsg("Successful execution") + if createContract { + txCache.InitCode(callee, ret) + } + err := txCache.Sync() + if err != nil { + return err + } } + ctx.CallEvents(exception) + ctx.txe.Return(ret, ctx.tx.GasLimit-gas) } - ctx.CallEvents(exception) - ctx.txe.Return(ret, ctx.tx.GasLimit-gas) + // Create a receipt from the ret and whether it erred. ctx.Logger.TraceMsg("VM call complete", "caller", caller, diff --git a/execution/contexts/governance_context.go b/execution/contexts/governance_context.go index 62ce355a1..3847edd36 100644 --- a/execution/contexts/governance_context.go +++ b/execution/contexts/governance_context.go @@ -94,10 +94,6 @@ func (ctx *GovernanceContext) UpdateAccount(account *acm.Account, update *spec.T if update.Balances().HasNative() { account.Balance = update.Balances().GetNative(0) } - if update.NodeAddress != nil { - // TODO: can we do something useful if provided with a NodeAddress for an account about to become a validator - // like add it to persistent peers or pre gossip so it gets inbound connections? If so under which circumstances? - } if update.Balances().HasPower() { if update.PublicKey == nil { err = fmt.Errorf("updateAccount should have PublicKey by this point but appears not to for "+ @@ -115,7 +111,7 @@ func (ctx *GovernanceContext) UpdateAccount(account *acm.Account, update *spec.T } } if update.Code != nil { - account.Code = *update.Code + account.EVMCode = *update.Code if err != nil { return ev, err } diff --git a/execution/contexts/name_context.go b/execution/contexts/name_context.go index aeb8896a5..398c9e875 100644 --- a/execution/contexts/name_context.go +++ b/execution/contexts/name_context.go @@ -138,7 +138,7 @@ func (ctx *NameContext) Execute(txe *exec.TxExecution, p payload.Payload) error } } else { if expiresIn < names.MinNameRegistrationPeriod { - return fmt.Errorf("Names must be registered for at least %d blocks", names.MinNameRegistrationPeriod) + return fmt.Errorf("names must be registered for at least %d blocks", names.MinNameRegistrationPeriod) } // entry does not exist, so create it entry = &names.Entry{ diff --git a/execution/contexts/proposal_context.go b/execution/contexts/proposal_context.go index 16f3f0b50..50e30bfd8 100644 --- a/execution/contexts/proposal_context.go +++ b/execution/contexts/proposal_context.go @@ -259,7 +259,7 @@ func validateProposalStrings(proposal *payload.Proposal) error { } func validateStringPrintable(data string) bool { - for _, r := range []rune(data) { + for _, r := range data { if !unicode.IsPrint(r) { return false } diff --git a/execution/errors/errors.go b/execution/errors/errors.go index e6bd8c779..4ee23f821 100644 --- a/execution/errors/errors.go +++ b/execution/errors/errors.go @@ -60,6 +60,7 @@ const ( ErrorCodeInvalidBlockNumber ErrorCodeBlockNumberOutOfRange ErrorCodeAlreadyVoted + ErrorCodeUnresolvedSymbols ) func (c Code) ErrorCode() Code { @@ -152,6 +153,8 @@ func (c Code) String() string { return "block number out of range" case ErrorCodeAlreadyVoted: return "vote already registered for this address" + case ErrorCodeUnresolvedSymbols: + return "code has unresolved symbols" default: return "Unknown error" } diff --git a/execution/evm/abi/abi.go b/execution/evm/abi/abi.go index 9f0a1b24c..c12013312 100644 --- a/execution/evm/abi/abi.go +++ b/execution/evm/abi/abi.go @@ -451,10 +451,6 @@ func (e EVMInt) unpack(data []byte, offset int, v interface{}) (int, error) { return ElementSize, nil } -func (e EVMInt) fixedSize() int { - return ElementSize -} - func (e EVMInt) Dynamic() bool { return false } @@ -597,10 +593,6 @@ func (e EVMBytes) unpack(data []byte, offset int, v interface{}) (int, error) { return ElementSize, nil } -func (e EVMBytes) fixedSize() int { - return ElementSize -} - func (e EVMBytes) Dynamic() bool { return e.M == 0 } @@ -689,10 +681,6 @@ func (e EVMFixed) unpack(data []byte, offset int, v interface{}) (int, error) { return 0, fmt.Errorf("unpacking of %s not implemented, patches welcome", e.GetSignature()) } -func (e EVMFixed) fixedSize() int { - return ElementSize -} - func (e EVMFixed) Dynamic() bool { return false } @@ -763,7 +751,7 @@ func readArgSpec(argsJ []ArgumentJSON) ([]Argument, error) { args[i].Indexed = a.Indexed baseType := a.Type - isArray := regexp.MustCompile("(.*)\\[([0-9]+)\\]") + isArray := regexp.MustCompile(`(.*)\[([0-9]+)\]`) m := isArray.FindStringSubmatch(a.Type) if m != nil { args[i].IsArray = true @@ -818,7 +806,7 @@ func readArgSpec(argsJ []ArgumentJSON) ([]Argument, error) { if M < 8 || M > 256 || (M%8) != 0 { return nil, fmt.Errorf("%s is not valid type", baseType) } - if N <= 0 || N > 80 { + if N == 0 || N > 80 { return nil, fmt.Errorf("%s is not valid type", baseType) } if m[1] == "fixed" { @@ -1366,7 +1354,7 @@ func unpack(argSpec []Argument, data []byte, getArg func(int) interface{}) error return err } offset += l - l, err = a.EVM.unpack(data, int(o), e) + _, err = a.EVM.unpack(data, int(o), e) if err != nil { return err } @@ -1396,7 +1384,7 @@ func unpack(argSpec []Argument, data []byte, getArg func(int) interface{}) error // We have been asked to return the value as a string; make intermediate // array of strings; we will concatenate after intermediate := make([]interface{}, a.ArrayLength) - for i, _ := range intermediate { + for i := range intermediate { intermediate[i] = new(string) } array = &intermediate @@ -1437,11 +1425,11 @@ func unpack(argSpec []Argument, data []byte, getArg func(int) interface{}) error if _, ok := arg.(*string); ok { // We have been asked to return the value as a string; make intermediate // array of strings; we will concatenate after - for i, _ := range intermediate { + for i := range intermediate { intermediate[i] = new(string) } } else { - for i, _ := range intermediate { + for i := range intermediate { intermediate[i] = a.EVM.getGoType() } } diff --git a/execution/evm/abi/core.go b/execution/evm/abi/core.go index 0ebd31f68..eb5dd9e32 100644 --- a/execution/evm/abi/core.go +++ b/execution/evm/abi/core.go @@ -150,7 +150,7 @@ func readAbi(root, contract string, logger *logging.Logger) (string, error) { p = path.Join(root, stripHex(contract)+".bin") if _, err = os.Stat(p); err != nil { logger.TraceMsg("abifile not found", "tried", p) - return "", fmt.Errorf("Abi doesn't exist for =>\t%s", p) + return "", fmt.Errorf("abi doesn't exist for =>\t%s", p) } } logger.TraceMsg("Found ABI file", "path", p) diff --git a/execution/evm/abi/core_test.go b/execution/evm/abi/core_test.go index 307ebf2ae..b88f13e7c 100644 --- a/execution/evm/abi/core_test.go +++ b/execution/evm/abi/core_test.go @@ -335,7 +335,7 @@ func TestUnpacker(t *testing.T) { EVMInt{M: 256}, pad([]byte{42}, 32, true), new(int64), - func() *int64 { var v int64; v = 42; return &v }(), + func() *int64 { var v int64 = 42; return &v }(), }, { EVMInt{M: 256}, @@ -365,7 +365,7 @@ func TestUnpacker(t *testing.T) { EVMInt{M: 256}, pad([]byte{0xfd, 0xca, 0, 0, 0, 0, 0, 0}, 32, true), new(uint64), - func() *uint64 { var v uint64; v = 0xfdca000000000000; return &v }(), + func() *uint64 { var v uint64 = 0xfdca000000000000; return &v }(), }, { EVMInt{M: 256}, @@ -378,7 +378,7 @@ func TestUnpacker(t *testing.T) { EVMInt{M: 256}, hexToBytes(t, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6"), new(int64), - func() *int64 { var v int64; v = -42; return &v }(), + func() *int64 { var v int64 = -42; return &v }(), }, { EVMInt{M: 256}, @@ -402,7 +402,7 @@ func TestUnpacker(t *testing.T) { EVMInt{M: 256}, hexToBytes(t, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF35010124111"), new(int64), - func() *int64 { var v int64; v = -0xcafefedbeef; return &v }(), + func() *int64 { var v int64 = -0xcafefedbeef; return &v }(), }, { EVMInt{M: 256}, @@ -418,37 +418,37 @@ func TestUnpacker(t *testing.T) { EVMUint{M: 256}, pad([]byte{42}, 32, true), new(int64), - func() *int64 { var v int64; v = 42; return &v }(), + func() *int64 { var v int64 = 42; return &v }(), }, { EVMUint{M: 256}, pad([]byte{42}, 32, true), new(int32), - func() *int32 { var v int32; v = 42; return &v }(), + func() *int32 { var v int32 = 42; return &v }(), }, { EVMUint{M: 256}, pad([]byte{0x7f, 0xff}, 32, true), new(int16), - func() *int16 { var v int16; v = 0x7fff; return &v }(), + func() *int16 { var v int16 = 0x7fff; return &v }(), }, { EVMUint{M: 256}, pad([]byte{0xfd, 0xca}, 32, true), new(uint16), - func() *uint16 { var v uint16; v = 0xfdca; return &v }(), + func() *uint16 { var v uint16 = 0xfdca; return &v }(), }, { EVMUint{M: 256}, pad([]byte{0xfd, 0xca}, 32, true), new(uint32), - func() *uint32 { var v uint32; v = 0xfdca; return &v }(), + func() *uint32 { var v uint32 = 0xfdca; return &v }(), }, { EVMUint{M: 256}, pad([]byte{0xfd, 0xca, 0, 0, 0, 0, 0, 0}, 32, true), new(uint64), - func() *uint64 { var v uint64; v = 0xfdca000000000000; return &v }(), + func() *uint64 { var v uint64 = 0xfdca000000000000; return &v }(), }, { EVMUint{M: 256}, diff --git a/execution/evm/event_sink.go b/execution/evm/event_sink.go index 677d637da..04642db24 100644 --- a/execution/evm/event_sink.go +++ b/execution/evm/event_sink.go @@ -27,7 +27,6 @@ func (es *noopEventSink) Log(log *exec.LogEvent) error { type logFreeEventSink struct { EventSink - error error } func NewLogFreeEventSink(eventSink EventSink) *logFreeEventSink { diff --git a/execution/evm/fake_app_state.go b/execution/evm/fake_app_state.go index 1e9e95f32..2e3cbddc9 100644 --- a/execution/evm/fake_app_state.go +++ b/execution/evm/fake_app_state.go @@ -27,7 +27,7 @@ import ( type FakeAppState struct { accounts map[crypto.Address]*acm.Account - storage map[string]Word256 + storage map[string][]byte } var _ acmstate.ReaderWriter = &FakeAppState{} @@ -53,7 +53,7 @@ func (fas *FakeAppState) RemoveAccount(address crypto.Address) error { return nil } -func (fas *FakeAppState) GetStorage(addr crypto.Address, key Word256) (Word256, error) { +func (fas *FakeAppState) GetStorage(addr crypto.Address, key Word256) ([]byte, error) { _, ok := fas.accounts[addr] if !ok { panic(fmt.Sprintf("Invalid account addr: %s", addr)) @@ -63,11 +63,11 @@ func (fas *FakeAppState) GetStorage(addr crypto.Address, key Word256) (Word256, if ok { return value, nil } else { - return Zero256, nil + return []byte{}, nil } } -func (fas *FakeAppState) SetStorage(addr crypto.Address, key Word256, value Word256) error { +func (fas *FakeAppState) SetStorage(addr crypto.Address, key Word256, value []byte) error { _, ok := fas.accounts[addr] if !ok { diff --git a/execution/evm/snative_test.go b/execution/evm/snative_test.go index c6a26c250..a42ffa231 100644 --- a/execution/evm/snative_test.go +++ b/execution/evm/snative_test.go @@ -86,7 +86,7 @@ func TestSNativeContractDescription_Dispatch(t *testing.T) { gas := uint64(1000) // Should fail since we have no permissions - retValue, err := contract.Dispatch(cache, caller.Address, bc.MustSplice(funcID[:], grantee.Address, + _, err = contract.Dispatch(cache, caller.Address, bc.MustSplice(funcID[:], grantee.Address, permFlagToWord256(permission.CreateAccount)), &gas, logger) if !assert.Error(t, err, "Should fail due to lack of permissions") { return @@ -96,7 +96,7 @@ func TestSNativeContractDescription_Dispatch(t *testing.T) { // Grant all permissions and dispatch should success cache.SetPermission(caller.Address, permission.AddRole, true) require.NoError(t, cache.Error()) - retValue, err = contract.Dispatch(cache, caller.Address, bc.MustSplice(funcID[:], + retValue, err := contract.Dispatch(cache, caller.Address, bc.MustSplice(funcID[:], grantee.Address.Word256(), permFlagToWord256(permission.CreateAccount)), &gas, logger) assert.NoError(t, err) assert.Equal(t, retValue, LeftPadBytes([]byte{1}, 32)) @@ -137,16 +137,6 @@ func permFlagToWord256(permFlag permission.PermFlag) Word256 { return Uint64ToWord256(uint64(permFlag)) } -func allAccountPermissions() permission.AccountPermissions { - return permission.AccountPermissions{ - Base: permission.BasePermissions{ - Perms: permission.AllPermFlags, - SetBit: permission.AllPermFlags, - }, - Roles: []string{}, - } -} - // turns the solidity compiler function summary into a map to drive signature // test func idToSignatureMap() map[string]string { diff --git a/execution/evm/stack.go b/execution/evm/stack.go index ace29114e..cbaa5d03a 100644 --- a/execution/evm/stack.go +++ b/execution/evm/stack.go @@ -16,14 +16,11 @@ package evm import ( "fmt" - - "github.com/hyperledger/burrow/crypto" - - "math/big" - "math" + "math/big" . "github.com/hyperledger/burrow/binary" + "github.com/hyperledger/burrow/crypto" "github.com/hyperledger/burrow/execution/errors" ) diff --git a/execution/evm/state.go b/execution/evm/state.go index 67615c286..7fafeed60 100644 --- a/execution/evm/state.go +++ b/execution/evm/state.go @@ -24,10 +24,11 @@ type Interface interface { } type Reader interface { - GetStorage(address crypto.Address, key binary.Word256) binary.Word256 + GetStorage(address crypto.Address, key binary.Word256) []byte GetBalance(address crypto.Address) uint64 GetPermissions(address crypto.Address) permission.AccountPermissions - GetCode(address crypto.Address) acm.Bytecode + GetEVMCode(address crypto.Address) acm.Bytecode + GetWASMCode(address crypto.Address) acm.Bytecode GetSequence(address crypto.Address) uint64 Exists(address crypto.Address) bool // GetBlockHash returns hash of the specific block @@ -37,8 +38,9 @@ type Reader interface { type Writer interface { CreateAccount(address crypto.Address) InitCode(address crypto.Address, code []byte) + InitWASMCode(address crypto.Address, code []byte) RemoveAccount(address crypto.Address) - SetStorage(address crypto.Address, key, value binary.Word256) + SetStorage(address crypto.Address, key binary.Word256, value []byte) AddToBalance(address crypto.Address, amount uint64) SubtractFromBalance(address crypto.Address, amount uint64) SetPermission(address crypto.Address, permFlag permission.PermFlag, value bool) @@ -107,11 +109,11 @@ func (st *State) PushError(err error) { // Reader -func (st *State) GetStorage(address crypto.Address, key binary.Word256) binary.Word256 { +func (st *State) GetStorage(address crypto.Address, key binary.Word256) []byte { value, err := st.cache.GetStorage(address, key) if err != nil { st.PushError(err) - return binary.Zero256 + return []byte{} } return value } @@ -132,12 +134,21 @@ func (st *State) GetPermissions(address crypto.Address) permission.AccountPermis return acc.Permissions } -func (st *State) GetCode(address crypto.Address) acm.Bytecode { +func (st *State) GetEVMCode(address crypto.Address) acm.Bytecode { acc := st.account(address) if acc == nil { return nil } - return acc.Code + return acc.EVMCode +} + +func (st *State) GetWASMCode(address crypto.Address) acm.Bytecode { + acc := st.account(address) + if acc == nil { + return nil + } + + return acc.WASMCode } func (st *State) Exists(address crypto.Address) bool { @@ -178,12 +189,28 @@ func (st *State) InitCode(address crypto.Address, code []byte) { "tried to initialise code for an account that does not exist: %v", address)) return } - if acc.Code != nil { + if acc.EVMCode != nil || acc.WASMCode != nil { + st.PushError(errors.ErrorCodef(errors.ErrorCodeIllegalWrite, + "tried to initialise code for a contract that already exists: %v", address)) + return + } + acc.EVMCode = code + st.updateAccount(acc) +} + +func (st *State) InitWASMCode(address crypto.Address, code []byte) { + acc := st.mustAccount(address) + if acc == nil { + st.PushError(errors.ErrorCodef(errors.ErrorCodeInvalidAddress, + "tried to initialise code for an account that does not exist: %v", address)) + return + } + if acc.EVMCode != nil || acc.WASMCode != nil { st.PushError(errors.ErrorCodef(errors.ErrorCodeIllegalWrite, "tried to initialise code for a contract that already exists: %v", address)) return } - acc.Code = code + acc.WASMCode = code st.updateAccount(acc) } @@ -196,7 +223,7 @@ func (st *State) RemoveAccount(address crypto.Address) { st.removeAccount(address) } -func (st *State) SetStorage(address crypto.Address, key, value binary.Word256) { +func (st *State) SetStorage(address crypto.Address, key binary.Word256, value []byte) { err := st.cache.SetStorage(address, key, value) if err != nil { st.PushError(err) diff --git a/execution/evm/vm.go b/execution/evm/vm.go index f37055bd8..862b968d5 100644 --- a/execution/evm/vm.go +++ b/execution/evm/vm.go @@ -16,6 +16,7 @@ package evm import ( "bytes" + "encoding/binary" "fmt" "io/ioutil" "math/big" @@ -566,7 +567,7 @@ func (vm *VM) execute(callState Interface, eventSink EventSink, caller, callee c address := stack.PopAddress() useGasNegative(gas, GasGetAccount, callState) if callState.Exists(address) { - code := callState.GetCode(address) + code := callState.GetEVMCode(address) l := int64(len(code)) stack.Push64(l) vm.Debugf(" => %d\n", l) @@ -589,7 +590,7 @@ func (vm *VM) execute(callState Interface, eventSink EventSink, caller, callee c callState.PushError(errors.ErrorCodeUnknownAddress) continue } - code := callState.GetCode(address) + code := callState.GetEVMCode(address) memOff := stack.PopBigInt() codeOff := stack.Pop64() length := stack.Pop64() @@ -620,7 +621,7 @@ func (vm *VM) execute(callState Interface, eventSink EventSink, caller, callee c // In case the account does not exist 0 is pushed to the stack. stack.PushU64(0) } else { - code := callState.GetCode(address) + code := callState.GetEVMCode(address) if code == nil { // In case the account does not have code the keccak256 hash of empty data code = acm.Bytecode{} @@ -698,14 +699,14 @@ func (vm *VM) execute(callState Interface, eventSink EventSink, caller, callee c case SLOAD: // 0x54 loc := stack.Pop() - data := callState.GetStorage(callee, loc) + data := LeftPadWord256(callState.GetStorage(callee, loc)) stack.Push(data) vm.Debugf("%s {0x%X = 0x%X}\n", callee, loc, data) case SSTORE: // 0x55 loc, data := stack.Pop(), stack.Pop() useGasNegative(gas, GasStorageUpdate, callState) - callState.SetStorage(callee, loc, data) + callState.SetStorage(callee, loc, data.Bytes()) vm.Debugf("%s {0x%X := 0x%X}\n", callee, loc, data) case JUMP: // 0x56 @@ -788,11 +789,11 @@ func (vm *VM) execute(callState Interface, eventSink EventSink, caller, callee c vm.sequence++ nonce := make([]byte, txs.HashLength+uint64Length) copy(nonce, vm.nonce) - PutUint64(nonce[txs.HashLength:], vm.sequence) + binary.BigEndian.PutUint64(nonce[txs.HashLength:], vm.sequence) newAccount = crypto.NewContractAddress(callee, nonce) } else if op == CREATE2 { salt := stack.Pop() - newAccount = crypto.NewContractAddress2(callee, salt, callState.GetCode(callee)) + newAccount = crypto.NewContractAddress2(callee, salt, callState.GetEVMCode(callee)) } // Check the CreateContract permission for this account @@ -888,23 +889,23 @@ func (vm *VM) execute(callState Interface, eventSink EventSink, caller, callee c switch op { case CALL: childCallState = callState.NewCache() - returnData, callErr = vm.call(childCallState, eventSink, callee, address, callState.GetCode(address), + returnData, callErr = vm.call(childCallState, eventSink, callee, address, callState.GetEVMCode(address), args, value, &gasLimit, exec.CallTypeCall) case CALLCODE: childCallState = callState.NewCache() - returnData, callErr = vm.call(childCallState, eventSink, callee, callee, callState.GetCode(address), + returnData, callErr = vm.call(childCallState, eventSink, callee, callee, callState.GetEVMCode(address), args, value, &gasLimit, exec.CallTypeCode) case DELEGATECALL: childCallState = callState.NewCache() returnData, callErr = vm.delegateCall(childCallState, eventSink, caller, callee, - callState.GetCode(address), args, value, &gasLimit, exec.CallTypeDelegate) + callState.GetEVMCode(address), args, value, &gasLimit, exec.CallTypeDelegate) case STATICCALL: childCallState = callState.NewCache(acmstate.ReadOnly) returnData, callErr = vm.delegateCall(childCallState, NewLogFreeEventSink(eventSink), - callee, address, callState.GetCode(address), args, value, &gasLimit, exec.CallTypeStatic) + callee, address, callState.GetEVMCode(address), args, value, &gasLimit, exec.CallTypeStatic) default: panic(fmt.Errorf("switch statement should be exhaustive so this should not have been reached")) diff --git a/execution/evm/vm_test.go b/execution/evm/vm_test.go index ffcd007ad..8a1af4a41 100644 --- a/execution/evm/vm_test.go +++ b/execution/evm/vm_test.go @@ -15,6 +15,7 @@ package evm import ( + bin "encoding/binary" "strconv" "testing" "time" @@ -61,7 +62,7 @@ func NewTestState(st acmstate.ReaderWriter, blockHashGetter func(uint64) []byte) func newAppState() *FakeAppState { fas := &FakeAppState{ accounts: make(map[crypto.Address]*acm.Account), - storage: make(map[string]Word256), + storage: make(map[string][]byte), } // For default permissions fas.accounts[acm.GlobalPermissionsAddress] = &acm.Account{ @@ -674,7 +675,7 @@ func TestRevert(t *testing.T) { account2 := newAccount(cache, "1, 0, 1") key, value := []byte{0x00}, []byte{0x00} - cache.SetStorage(account1, LeftPadWord256(key), LeftPadWord256(value)) + cache.SetStorage(account1, LeftPadWord256(key), value) var gas uint64 = 100000 @@ -691,7 +692,7 @@ func TestRevert(t *testing.T) { assert.Error(t, cErr, "Expected execution reverted error") storageVal := cache.GetStorage(account1, LeftPadWord256(key)) - assert.Equal(t, LeftPadWord256(value), storageVal) + assert.Equal(t, value, storageVal) t.Logf("Output: %v\n", output) } @@ -763,7 +764,7 @@ func TestStaticCallReadOnly(t *testing.T) { PUSH1, value, PUSH20, callee, PUSH2, gas1, gas2, STATICCALL, PUSH1, retSize, PUSH1, retOff, RETURN)) - txe := runVM(cache, ourVm, caller, callee, cache.GetCode(caller), 1000) + txe := runVM(cache, ourVm, caller, callee, cache.GetEVMCode(caller), 1000) // the topmost caller can never *illegally* modify state require.Error(t, txe.Exception) assertErrorCode(t, errors.ErrorCodeIllegalWrite, txe.Exception, @@ -791,7 +792,7 @@ func TestStaticCallWithValue(t *testing.T) { PUSH1, retOff, RETURN)) cache.AddToBalance(callee, 100000) - txe := runVM(cache, ourVm, caller, callee, cache.GetCode(caller), 1000) + txe := runVM(cache, ourVm, caller, callee, cache.GetEVMCode(caller), 1000) require.NotNil(t, txe.Exception) assertErrorCode(t, errors.ErrorCodeIllegalWrite, txe.Exception, "expected static call violation because of call with value") } @@ -816,7 +817,7 @@ func TestStaticCallNoValue(t *testing.T) { PUSH1, retOff, RETURN)) cache.AddToBalance(callee, 100000) - txe := runVM(cache, ourVm, caller, callee, cache.GetCode(caller), 1000) + txe := runVM(cache, ourVm, caller, callee, cache.GetEVMCode(caller), 1000) // no exceptions expected because value never set in children require.NoError(t, txe.Exception.AsError()) exCalls := txe.ExceptionalCalls() @@ -833,12 +834,12 @@ func TestCreate(t *testing.T) { // ensure pre-generated address has same sequence number nonce := make([]byte, txs.HashLength+uint64Length) copy(nonce, ourVm.nonce) - PutUint64(nonce[txs.HashLength:], ourVm.sequence+1) + bin.BigEndian.PutUint64(nonce[txs.HashLength:], ourVm.sequence+1) addr := crypto.NewContractAddress(callee, nonce) var gas uint64 = 100000 caller := newAccount(cache, "1, 2, 3") - output, err := ourVm.Call(cache, NewNoopEventSink(), caller, callee, cache.GetCode(callee), []byte{}, 0, &gas) + output, err := ourVm.Call(cache, NewNoopEventSink(), caller, callee, cache.GetEVMCode(callee), []byte{}, 0, &gas) assert.NoError(t, err, "Should return new address without error") assert.Equal(t, addr.Bytes(), output, "Addresses should be equal") } @@ -852,11 +853,11 @@ func TestCreate2(t *testing.T) { // salt of 0s var salt [32]byte callee := makeAccountWithCode(cache, "callee", MustSplice(PUSH1, 0x0, PUSH1, 0x0, PUSH1, 0x0, PUSH32, salt[:], CREATE2, PUSH1, 0, MSTORE, PUSH1, 20, PUSH1, 12, RETURN)) - addr := crypto.NewContractAddress2(callee, salt, cache.GetCode(callee)) + addr := crypto.NewContractAddress2(callee, salt, cache.GetEVMCode(callee)) var gas uint64 = 100000 caller := newAccount(cache, "1, 2, 3") - output, err := ourVm.Call(cache, NewNoopEventSink(), caller, callee, cache.GetCode(callee), []byte{}, 0, &gas) + output, err := ourVm.Call(cache, NewNoopEventSink(), caller, callee, cache.GetEVMCode(callee), []byte{}, 0, &gas) assert.NoError(t, err, "Should return new address without error") assert.Equal(t, addr.Bytes(), output, "Returned value not equal to create2 address") } @@ -906,7 +907,7 @@ func TestDelegateCallGas(t *testing.T) { delegateCallCost, callerCodeSuffix)) // Should pass - txe := runVM(cache, ourVm, caller, callee, cache.GetCode(caller), 100) + txe := runVM(cache, ourVm, caller, callee, cache.GetEVMCode(caller), 100) assert.Nil(t, txe.Exception, "Should have sufficient funds for call") assert.Equal(t, Int64ToWord256(calleeReturnValue).Bytes(), txe.Result.Return) @@ -915,7 +916,7 @@ func TestDelegateCallGas(t *testing.T) { delegateCallCost-1, callerCodeSuffix)) // Should fail - txe = runVM(cache, ourVm, caller2, callee, cache.GetCode(caller2), 100) + txe = runVM(cache, ourVm, caller2, callee, cache.GetEVMCode(caller2), 100) assert.NotNil(t, txe.Exception, "Should have insufficient gas for call") } @@ -960,7 +961,7 @@ func TestMemoryBounds(t *testing.T) { code = MustSplice(code, storeAtEnd(), MLOAD) } require.NoError(t, cache.Error()) - output, err = ourVm.Call(cache, NewNoopEventSink(), caller, callee, MustSplice(code, storeAtEnd(), returnAfterStore()), + _, err = ourVm.Call(cache, NewNoopEventSink(), caller, callee, MustSplice(code, storeAtEnd(), returnAfterStore()), nil, 0, &gas) assert.Error(t, err, "Should hit memory out of bounds") } @@ -1380,6 +1381,7 @@ func TestDataStackOverflow(t *testing.T) { // Input is the function hash of `get()` input, err := hex.DecodeString("6d4ce63c") + require.NoError(t, err) _, err = ourVm.Call(cache, eventSink, account1, account2, contractCode, input, 0, &gas) assertErrorCode(t, errors.ErrorCodeDataStackOverflow, err, "Should be stack overflow") diff --git a/execution/exec/exec.pb.go b/execution/exec/exec.pb.go index eeab4d2a5..bee8cee9c 100644 --- a/execution/exec/exec.pb.go +++ b/execution/exec/exec.pb.go @@ -500,8 +500,8 @@ func (*BlockExecution) XXX_MessageName() string { type TxExecutionKey struct { // The block height Height uint64 `protobuf:"varint,1,opt,name=Height,proto3" json:"Height,omitempty"` - // The offset of the TxExecution - Offset uint64 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"` + // The offset of the TxExecution in bytes + Offset uint64 `protobuf:"varint,2,opt,name=Offset,proto3" json:"Offset,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1358,83 +1358,83 @@ func init() { golang_proto.RegisterFile("exec.proto", fileDescriptor_4d737c7315c var fileDescriptor_4d737c7315c25422 = []byte{ // 1252 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0x4f, 0x6f, 0x1b, 0x45, - 0x14, 0xef, 0xda, 0xeb, 0x7f, 0x63, 0xa7, 0x94, 0x51, 0xa9, 0xac, 0x1c, 0xec, 0xb0, 0x85, 0x52, - 0x42, 0xbb, 0xae, 0x02, 0x01, 0x14, 0x24, 0x44, 0xdc, 0x44, 0x49, 0x68, 0x68, 0x61, 0xea, 0x16, + 0x14, 0xef, 0xda, 0xeb, 0x7f, 0x63, 0xa7, 0x94, 0x51, 0xa9, 0xac, 0x1e, 0xec, 0xb0, 0x85, 0x52, + 0x42, 0xbb, 0xae, 0x02, 0x01, 0x14, 0x24, 0x44, 0xdc, 0x44, 0x49, 0x68, 0x68, 0x60, 0xea, 0x16, 0x81, 0xe0, 0xb0, 0xde, 0x9d, 0xac, 0x57, 0xb5, 0x77, 0x57, 0xbb, 0xe3, 0xb0, 0xfe, 0x02, 0x1c, 0x10, 0x07, 0xb8, 0x95, 0x0b, 0xea, 0xf7, 0xe0, 0xc2, 0x31, 0x37, 0x7a, 0xee, 0xc1, 0xa0, 0xf4, 0x13, 0x20, 0x4e, 0xe4, 0x84, 0x66, 0xe6, 0xcd, 0x7a, 0x97, 0xa6, 0x49, 0x85, 0x73, 0xe0, 0x62, 0xcd, 0x7b, 0xef, 0x37, 0xcf, 0x6f, 0xde, 0xfb, 0xbd, 0xf7, 0x16, 0x21, 0x9a, 0x50, 0xdb, 0x0c, - 0xa3, 0x80, 0x05, 0x58, 0xe7, 0xe7, 0xc5, 0xeb, 0xae, 0xc7, 0x06, 0xe3, 0xbe, 0x69, 0x07, 0xa3, - 0x8e, 0x1b, 0xb8, 0x41, 0x47, 0x18, 0xfb, 0xe3, 0x3d, 0x21, 0x09, 0x41, 0x9c, 0xe4, 0xa5, 0xc5, - 0xf7, 0x32, 0x70, 0x46, 0x7d, 0x87, 0x46, 0x23, 0xcf, 0x67, 0xd9, 0xa3, 0xd5, 0xb7, 0xbd, 0x0e, - 0x9b, 0x84, 0x34, 0x96, 0xbf, 0x70, 0xb1, 0xed, 0x06, 0x81, 0x3b, 0xa4, 0x33, 0xf7, 0xcc, 0x1b, - 0xd1, 0x98, 0x59, 0xa3, 0x10, 0x00, 0x0d, 0x1a, 0x45, 0x41, 0xa4, 0xe0, 0x75, 0xdf, 0x1a, 0xa5, - 0x77, 0x6b, 0x2c, 0x51, 0xc7, 0x0b, 0x21, 0xff, 0x9b, 0x38, 0xf6, 0x02, 0x1f, 0x34, 0x28, 0x0e, - 0xd5, 0x93, 0x8c, 0x5f, 0x0a, 0xa8, 0x7e, 0x97, 0x45, 0xd4, 0x1a, 0x6d, 0xee, 0x53, 0x9f, 0xe1, - 0x1b, 0x08, 0x75, 0xa9, 0xeb, 0xf9, 0xdd, 0x61, 0x60, 0x3f, 0x68, 0x6a, 0x4b, 0xda, 0xd5, 0xfa, - 0xca, 0x05, 0x53, 0xe4, 0x60, 0xa6, 0x27, 0x19, 0x0c, 0x7e, 0x03, 0x55, 0x84, 0xd4, 0x4b, 0x9a, - 0x05, 0x01, 0x5f, 0xc8, 0xc0, 0x7b, 0x09, 0x51, 0x56, 0xfc, 0x05, 0xaa, 0x6e, 0xfa, 0xfb, 0x74, - 0x18, 0x84, 0xb4, 0x59, 0x04, 0x24, 0x0f, 0x53, 0x29, 0xbb, 0xe6, 0x93, 0x69, 0x7b, 0x39, 0x93, - 0xad, 0xc1, 0x24, 0xa4, 0xd1, 0x90, 0x3a, 0x2e, 0x8d, 0x3a, 0xfd, 0x71, 0x14, 0x05, 0xdf, 0x74, - 0xb2, 0x78, 0x92, 0xba, 0xc3, 0xaf, 0xa2, 0x92, 0x08, 0xbf, 0xa9, 0x0b, 0xbf, 0x75, 0x19, 0x81, - 0x50, 0x11, 0x69, 0x11, 0x10, 0xdf, 0xe9, 0x25, 0xcd, 0x52, 0x0e, 0xc2, 0x55, 0x44, 0x5a, 0xf0, - 0x32, 0x0f, 0xd0, 0x91, 0x2f, 0x2f, 0x0b, 0xd4, 0xf9, 0x14, 0x25, 0xdf, 0x9d, 0xda, 0xd7, 0xf4, - 0x83, 0x47, 0x6d, 0xcd, 0xb8, 0x95, 0xcd, 0x16, 0xbe, 0x84, 0xca, 0xdb, 0xd4, 0x73, 0x07, 0x4c, - 0xe4, 0x4d, 0x27, 0x20, 0xe1, 0xd7, 0xb9, 0xde, 0x72, 0x68, 0x94, 0x26, 0x48, 0x96, 0x59, 0x2a, - 0x09, 0x18, 0x0d, 0x63, 0xf6, 0xf7, 0xcf, 0x73, 0x65, 0x7c, 0xaf, 0xa5, 0xd9, 0xe6, 0xe1, 0xf6, - 0x12, 0x70, 0xac, 0x65, 0xc3, 0x55, 0x5a, 0x92, 0xda, 0xf1, 0x6b, 0xa8, 0x4c, 0x68, 0x3c, 0x1e, - 0x32, 0x08, 0xa1, 0x21, 0x91, 0x52, 0x47, 0xc0, 0x86, 0x3b, 0xa8, 0xb6, 0x99, 0xd8, 0x34, 0x64, - 0x5e, 0xe0, 0x43, 0x2a, 0x5f, 0x36, 0x81, 0x64, 0xa9, 0x81, 0xcc, 0x30, 0xc6, 0x7d, 0x48, 0x2a, - 0xfe, 0x04, 0x95, 0x7b, 0xc9, 0xb6, 0x15, 0x0f, 0x44, 0x65, 0x1b, 0xdd, 0xd5, 0x83, 0x69, 0xfb, - 0xdc, 0x93, 0x69, 0xfb, 0xfa, 0xc9, 0xe5, 0xec, 0x7b, 0xbe, 0x15, 0x4d, 0xcc, 0x6d, 0x9a, 0x74, - 0x27, 0x8c, 0xc6, 0x04, 0x9c, 0x18, 0x7f, 0x6b, 0xb3, 0xb7, 0xe1, 0x8f, 0xb9, 0xef, 0xde, 0x24, - 0xa4, 0xe2, 0x95, 0x0b, 0xdd, 0x95, 0xa3, 0x69, 0xdb, 0x3c, 0x95, 0x26, 0x9d, 0xd0, 0x9a, 0x0c, - 0x03, 0xcb, 0x31, 0xf9, 0x4d, 0x02, 0x1e, 0x32, 0x71, 0x16, 0xce, 0x20, 0xce, 0x4c, 0x99, 0x8a, - 0xb9, 0x8a, 0x5f, 0x44, 0xa5, 0x1d, 0xdf, 0xa1, 0x89, 0x48, 0xa2, 0x4e, 0xa4, 0xc0, 0x8b, 0x70, - 0x27, 0xf2, 0x5c, 0xcf, 0x07, 0x0e, 0x42, 0x11, 0xa4, 0x8e, 0x80, 0xcd, 0xf8, 0x56, 0x43, 0xe7, - 0x05, 0x09, 0x36, 0x13, 0x6a, 0x8f, 0x79, 0x9a, 0xe7, 0x24, 0x16, 0x5e, 0x45, 0x8d, 0x5e, 0x92, - 0x7a, 0x8b, 0x9b, 0xc5, 0xa5, 0xa2, 0xac, 0xac, 0x24, 0x4b, 0x6a, 0x21, 0x39, 0x98, 0xf1, 0x11, - 0x3a, 0x9f, 0x91, 0x6f, 0xd1, 0xc9, 0x73, 0xe3, 0xb8, 0x84, 0xca, 0xc1, 0xde, 0x5e, 0x4c, 0x25, - 0xbb, 0x74, 0x02, 0x92, 0xf1, 0x67, 0x01, 0xd5, 0x33, 0x2e, 0xf0, 0xb5, 0x34, 0xde, 0x63, 0xf9, - 0xda, 0xd5, 0x1f, 0x4f, 0xdb, 0x5a, 0x1a, 0x76, 0x76, 0x5e, 0x94, 0xcf, 0x76, 0x5e, 0x5c, 0x46, - 0x65, 0x31, 0x15, 0xe2, 0x66, 0x45, 0xe4, 0x22, 0x37, 0x30, 0xc0, 0x94, 0xe9, 0x99, 0xea, 0x09, - 0x3d, 0x73, 0x05, 0x55, 0x08, 0xb5, 0xa9, 0x17, 0xb2, 0x66, 0x0d, 0x60, 0xfc, 0x4f, 0x41, 0x47, - 0x94, 0x31, 0xdf, 0x5b, 0xe8, 0xf4, 0xde, 0x7a, 0xa6, 0x6a, 0xf5, 0x17, 0xab, 0xda, 0x77, 0x9a, - 0x62, 0x19, 0x6e, 0xa2, 0xca, 0xcd, 0x81, 0xe5, 0xf9, 0x3b, 0x1b, 0x22, 0xdf, 0x35, 0xa2, 0xc4, - 0x4c, 0x21, 0x0b, 0xc7, 0xf3, 0xb6, 0x98, 0xe5, 0xed, 0xfb, 0x48, 0xef, 0x79, 0x23, 0x0a, 0x13, - 0x61, 0xd1, 0x94, 0x7b, 0xc9, 0x54, 0x7b, 0xc9, 0xec, 0xa9, 0xbd, 0xd4, 0xad, 0xf2, 0x76, 0xfa, - 0xe1, 0xf7, 0xb6, 0x46, 0xc4, 0x0d, 0xe3, 0xb7, 0x82, 0xaa, 0xf8, 0xff, 0xb9, 0x8b, 0xdf, 0x42, - 0x35, 0x51, 0x72, 0x11, 0x5d, 0x51, 0x44, 0xb7, 0x70, 0x34, 0x6d, 0xcf, 0x94, 0x64, 0x76, 0xe4, - 0x49, 0x15, 0xc2, 0xce, 0x86, 0xc8, 0x47, 0x8d, 0x28, 0x31, 0x93, 0xd4, 0xd2, 0xf1, 0x49, 0x2d, - 0x67, 0x93, 0x9a, 0xe3, 0x43, 0xe5, 0x74, 0x3e, 0xac, 0xe9, 0x0f, 0x1f, 0xb5, 0xcf, 0x19, 0x3f, - 0x16, 0x60, 0xd5, 0x71, 0x7a, 0xe6, 0x9a, 0x09, 0xe8, 0xf9, 0xaf, 0xde, 0xbf, 0xc2, 0xff, 0x3c, - 0x1c, 0xab, 0xb9, 0x0f, 0xab, 0x5c, 0xa8, 0x60, 0x3d, 0x8a, 0x33, 0x7e, 0x13, 0x95, 0xef, 0x8c, - 0x19, 0x07, 0x16, 0x55, 0x2c, 0x62, 0x36, 0x09, 0x1d, 0xf4, 0x85, 0x14, 0xf0, 0x65, 0xa4, 0xdf, - 0xb4, 0x86, 0x43, 0xa0, 0xc3, 0x4b, 0x12, 0xc8, 0x35, 0x12, 0x26, 0x8c, 0x78, 0x09, 0x15, 0x77, - 0x03, 0x17, 0x06, 0x1d, 0xf4, 0xf9, 0x6e, 0xe0, 0x4a, 0x08, 0x37, 0xe1, 0x0f, 0xd1, 0xc2, 0x56, - 0xb0, 0x4f, 0x23, 0x7f, 0xdd, 0xb6, 0x83, 0xb1, 0xcf, 0xa0, 0xc7, 0x9b, 0x12, 0x9b, 0x33, 0xc9, - 0x5b, 0x79, 0xf8, 0x5a, 0x95, 0xe7, 0x43, 0x6c, 0xe1, 0x87, 0x9a, 0xea, 0x54, 0x5e, 0x03, 0x42, - 0xd9, 0x38, 0xf2, 0x45, 0x52, 0x1a, 0x04, 0x24, 0x5e, 0xb5, 0x2d, 0x2b, 0xbe, 0x17, 0x53, 0x07, - 0x18, 0xaf, 0x44, 0xbc, 0x8c, 0x6a, 0xb7, 0xad, 0x11, 0xdd, 0xf4, 0x59, 0x34, 0x81, 0xb7, 0x37, - 0x4c, 0xf9, 0x29, 0x25, 0x74, 0x64, 0x66, 0xc6, 0x37, 0x50, 0xf5, 0x53, 0x1a, 0x8d, 0xd6, 0x23, - 0x37, 0x86, 0xd7, 0x5f, 0x34, 0x33, 0x5f, 0x57, 0xca, 0x46, 0x52, 0x94, 0xf1, 0x97, 0x86, 0xaa, - 0xea, 0xd9, 0xf8, 0x36, 0xaa, 0xac, 0x3b, 0x4e, 0x44, 0xe3, 0x58, 0x46, 0xd7, 0x7d, 0x07, 0x78, - 0x7b, 0xed, 0x64, 0xde, 0xda, 0xd1, 0x24, 0x64, 0x81, 0x09, 0x77, 0x89, 0x72, 0x82, 0x77, 0x90, - 0xbe, 0x61, 0x31, 0x6b, 0xbe, 0x26, 0x10, 0x2e, 0xf0, 0x2e, 0x2a, 0xf7, 0x82, 0xd0, 0xb3, 0xe5, - 0x72, 0x78, 0xe1, 0xc8, 0xc0, 0xd9, 0xe7, 0x41, 0xe4, 0xac, 0xac, 0xbe, 0x4b, 0xc0, 0x87, 0xf1, - 0x73, 0x01, 0xd5, 0x52, 0x42, 0xe0, 0xab, 0xa8, 0xca, 0x05, 0xd1, 0x5d, 0x25, 0xd1, 0x5d, 0x8d, - 0xa3, 0x69, 0x3b, 0xd5, 0x91, 0xf4, 0xc4, 0xbf, 0x68, 0xf8, 0x59, 0x3c, 0x2a, 0xb7, 0x21, 0x94, - 0x96, 0xa4, 0x76, 0x1e, 0x31, 0x2c, 0xd3, 0xc2, 0x1c, 0xb9, 0x54, 0xa3, 0xb2, 0x85, 0xd0, 0x5d, - 0x66, 0xd9, 0x0f, 0x36, 0x68, 0xc8, 0x06, 0x30, 0xfd, 0x32, 0x1a, 0x3e, 0x71, 0x80, 0x57, 0xfa, - 0x5c, 0x13, 0x47, 0x3a, 0x31, 0x3e, 0x43, 0xf8, 0x59, 0x82, 0xe3, 0x0f, 0xd0, 0x02, 0xc8, 0xf7, - 0x42, 0xc7, 0x62, 0x14, 0x72, 0xf0, 0x8a, 0x29, 0xbe, 0xd7, 0x7b, 0x74, 0x14, 0x0e, 0x2d, 0x46, - 0x01, 0x42, 0xf2, 0x58, 0xe3, 0x2b, 0x84, 0x66, 0x5d, 0x7d, 0xd6, 0x54, 0x33, 0xbe, 0x46, 0xf5, - 0xcc, 0x28, 0x38, 0x73, 0xf7, 0x3f, 0x15, 0x50, 0xae, 0xb2, 0xfc, 0x0c, 0x83, 0xed, 0x3f, 0x57, - 0x56, 0xfa, 0x48, 0xbd, 0xd1, 0xf9, 0x78, 0x22, 0x7d, 0xa4, 0x2d, 0x57, 0x9c, 0xbf, 0xe5, 0x2e, - 0xa2, 0xd2, 0x7d, 0x6b, 0x38, 0xa6, 0xea, 0x1b, 0x51, 0x08, 0xf8, 0x02, 0x2a, 0x6e, 0x59, 0x31, - 0x6c, 0x10, 0x7e, 0xec, 0x76, 0x0f, 0x0e, 0x5b, 0xda, 0xe3, 0xc3, 0x96, 0xf6, 0xc7, 0x61, 0x4b, - 0xfb, 0xf5, 0x69, 0x4b, 0x3b, 0x78, 0xda, 0xd2, 0xbe, 0x3c, 0x25, 0x7c, 0xaa, 0x3e, 0x08, 0xc4, - 0xa9, 0x5f, 0x16, 0xbb, 0xfa, 0xed, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x93, 0x44, 0x7b, 0xc9, + 0xa3, 0x80, 0x05, 0x58, 0xe7, 0xe7, 0xcb, 0x37, 0x5c, 0x8f, 0x0d, 0xc6, 0x7d, 0xd3, 0x0e, 0x46, + 0x1d, 0x37, 0x70, 0x83, 0x8e, 0x30, 0xf6, 0xc7, 0x7b, 0x42, 0x12, 0x82, 0x38, 0xc9, 0x4b, 0x97, + 0xdf, 0xcb, 0xc0, 0x19, 0xf5, 0x1d, 0x1a, 0x8d, 0x3c, 0x9f, 0x65, 0x8f, 0x56, 0xdf, 0xf6, 0x3a, + 0x6c, 0x12, 0xd2, 0x58, 0xfe, 0xc2, 0xc5, 0xb6, 0x1b, 0x04, 0xee, 0x90, 0xce, 0xdc, 0x33, 0x6f, + 0x44, 0x63, 0x66, 0x8d, 0x42, 0x00, 0x34, 0x68, 0x14, 0x05, 0x91, 0x82, 0xd7, 0x7d, 0x6b, 0x94, + 0xde, 0xad, 0xb1, 0x44, 0x1d, 0x2f, 0x84, 0xfc, 0x6f, 0xe2, 0xd8, 0x0b, 0x7c, 0xd0, 0xa0, 0x38, + 0x54, 0x4f, 0x32, 0x7e, 0x29, 0xa0, 0xfa, 0x5d, 0x16, 0x51, 0x6b, 0xb4, 0xb1, 0x4f, 0x7d, 0x86, + 0x6f, 0x22, 0xd4, 0xa5, 0xae, 0xe7, 0x77, 0x87, 0x81, 0xfd, 0xa0, 0xa9, 0x2d, 0x6a, 0xd7, 0xea, + 0xcb, 0x17, 0x4c, 0x91, 0x83, 0x99, 0x9e, 0x64, 0x30, 0xf8, 0x0d, 0x54, 0x11, 0x52, 0x2f, 0x69, + 0x16, 0x04, 0x7c, 0x21, 0x03, 0xef, 0x25, 0x44, 0x59, 0xf1, 0x17, 0xa8, 0xba, 0xe1, 0xef, 0xd3, + 0x61, 0x10, 0xd2, 0x66, 0x11, 0x90, 0x3c, 0x4c, 0xa5, 0xec, 0x9a, 0x4f, 0xa6, 0xed, 0xa5, 0x4c, + 0xb6, 0x06, 0x93, 0x90, 0x46, 0x43, 0xea, 0xb8, 0x34, 0xea, 0xf4, 0xc7, 0x51, 0x14, 0x7c, 0xd3, + 0xc9, 0xe2, 0x49, 0xea, 0x0e, 0xbf, 0x8a, 0x4a, 0x22, 0xfc, 0xa6, 0x2e, 0xfc, 0xd6, 0x65, 0x04, + 0x42, 0x45, 0xa4, 0x45, 0x40, 0x7c, 0xa7, 0x97, 0x34, 0x4b, 0x39, 0x08, 0x57, 0x11, 0x69, 0xc1, + 0x4b, 0x3c, 0x40, 0x47, 0xbe, 0xbc, 0x2c, 0x50, 0xe7, 0x53, 0x94, 0x7c, 0x77, 0x6a, 0x5f, 0xd5, + 0x0f, 0x1e, 0xb5, 0x35, 0xe3, 0x76, 0x36, 0x5b, 0xf8, 0x12, 0x2a, 0x6f, 0x51, 0xcf, 0x1d, 0x30, + 0x91, 0x37, 0x9d, 0x80, 0x84, 0x5f, 0xe7, 0x7a, 0xcb, 0xa1, 0x51, 0x9a, 0x20, 0x59, 0x66, 0xa9, + 0x24, 0x60, 0x34, 0x8c, 0xd9, 0xdf, 0x3f, 0xcf, 0x95, 0xf1, 0xbd, 0x96, 0x66, 0x9b, 0x87, 0xdb, + 0x4b, 0xc0, 0xb1, 0x96, 0x0d, 0x57, 0x69, 0x49, 0x6a, 0xc7, 0xaf, 0xa1, 0x32, 0xa1, 0xf1, 0x78, + 0xc8, 0x20, 0x84, 0x86, 0x44, 0x4a, 0x1d, 0x01, 0x1b, 0xee, 0xa0, 0xda, 0x46, 0x62, 0xd3, 0x90, + 0x79, 0x81, 0x0f, 0xa9, 0x7c, 0xd9, 0x04, 0x92, 0xa5, 0x06, 0x32, 0xc3, 0x18, 0xf7, 0x21, 0xa9, + 0xf8, 0x13, 0x54, 0xee, 0x25, 0x5b, 0x56, 0x3c, 0x10, 0x95, 0x6d, 0x74, 0x57, 0x0e, 0xa6, 0xed, + 0x73, 0x4f, 0xa6, 0xed, 0x1b, 0x27, 0x97, 0xb3, 0xef, 0xf9, 0x56, 0x34, 0x31, 0xb7, 0x68, 0xd2, + 0x9d, 0x30, 0x1a, 0x13, 0x70, 0x62, 0xfc, 0xad, 0xcd, 0xde, 0x86, 0x3f, 0xe6, 0xbe, 0x7b, 0x93, + 0x90, 0x8a, 0x57, 0x2e, 0x74, 0x97, 0x8f, 0xa6, 0x6d, 0xf3, 0x54, 0x9a, 0x74, 0x42, 0x6b, 0x32, + 0x0c, 0x2c, 0xc7, 0xe4, 0x37, 0x09, 0x78, 0xc8, 0xc4, 0x59, 0x38, 0x83, 0x38, 0x33, 0x65, 0x2a, + 0xe6, 0x2a, 0x7e, 0x11, 0x95, 0xb6, 0x7d, 0x87, 0x26, 0x22, 0x89, 0x3a, 0x91, 0x02, 0x2f, 0xc2, + 0x6e, 0xe4, 0xb9, 0x9e, 0x0f, 0x1c, 0x84, 0x22, 0x48, 0x1d, 0x01, 0x9b, 0xf1, 0xad, 0x86, 0xce, + 0x0b, 0x12, 0x6c, 0x24, 0xd4, 0x1e, 0xf3, 0x34, 0xcf, 0x49, 0x2c, 0xbc, 0x82, 0x1a, 0xbd, 0x24, + 0xf5, 0x16, 0x37, 0x8b, 0x8b, 0x45, 0x59, 0x59, 0x49, 0x96, 0xd4, 0x42, 0x72, 0x30, 0xe3, 0x23, + 0x74, 0x3e, 0x23, 0xdf, 0xa6, 0x93, 0xe7, 0xc6, 0x71, 0x09, 0x95, 0x77, 0xf7, 0xf6, 0x62, 0x2a, + 0xd9, 0xa5, 0x13, 0x90, 0x8c, 0x3f, 0x0b, 0xa8, 0x9e, 0x71, 0x81, 0xaf, 0xa7, 0xf1, 0x1e, 0xcb, + 0xd7, 0xae, 0xfe, 0x78, 0xda, 0xd6, 0xd2, 0xb0, 0xb3, 0xf3, 0xa2, 0x7c, 0xb6, 0xf3, 0xe2, 0x0a, + 0x2a, 0x8b, 0xa9, 0x10, 0x37, 0x2b, 0x22, 0x17, 0xb9, 0x81, 0x01, 0xa6, 0x4c, 0xcf, 0x54, 0x4f, + 0xe8, 0x99, 0xab, 0xa8, 0x42, 0xa8, 0x4d, 0xbd, 0x90, 0x35, 0x6b, 0x00, 0xe3, 0x7f, 0x0a, 0x3a, + 0xa2, 0x8c, 0xf9, 0xde, 0x42, 0xa7, 0xf7, 0xd6, 0x33, 0x55, 0xab, 0xbf, 0x58, 0xd5, 0xbe, 0xd3, + 0x14, 0xcb, 0x70, 0x13, 0x55, 0x6e, 0x0d, 0x2c, 0xcf, 0xdf, 0x5e, 0x17, 0xf9, 0xae, 0x11, 0x25, + 0x66, 0x0a, 0x59, 0x38, 0x9e, 0xb7, 0xc5, 0x2c, 0x6f, 0xdf, 0x47, 0x7a, 0xcf, 0x1b, 0x51, 0x98, + 0x08, 0x97, 0x4d, 0xb9, 0x97, 0x4c, 0xb5, 0x97, 0xcc, 0x9e, 0xda, 0x4b, 0xdd, 0x2a, 0x6f, 0xa7, + 0x1f, 0x7e, 0x6f, 0x6b, 0x44, 0xdc, 0x30, 0x7e, 0x2b, 0xa8, 0x8a, 0xff, 0x9f, 0xbb, 0xf8, 0x2d, + 0x54, 0x13, 0x25, 0x17, 0xd1, 0x15, 0x45, 0x74, 0x0b, 0x47, 0xd3, 0xf6, 0x4c, 0x49, 0x66, 0x47, + 0x9e, 0x54, 0x21, 0x6c, 0xaf, 0x8b, 0x7c, 0xd4, 0x88, 0x12, 0x33, 0x49, 0x2d, 0x1d, 0x9f, 0xd4, + 0x72, 0x36, 0xa9, 0x39, 0x3e, 0x54, 0x4e, 0xe7, 0xc3, 0xaa, 0xfe, 0xf0, 0x51, 0xfb, 0x9c, 0xf1, + 0x63, 0x01, 0x56, 0x1d, 0xa7, 0x67, 0xae, 0x99, 0x80, 0x9e, 0xff, 0xea, 0xfd, 0xab, 0xfc, 0xcf, + 0xc3, 0xb1, 0x9a, 0xfb, 0xb0, 0xca, 0x85, 0x0a, 0xd6, 0xa3, 0x38, 0xe3, 0x37, 0x51, 0x79, 0x77, + 0xcc, 0x38, 0xb0, 0xa8, 0x62, 0x11, 0xb3, 0x49, 0xe8, 0xa0, 0x2f, 0xa4, 0x80, 0xaf, 0x20, 0xfd, + 0x96, 0x35, 0x1c, 0x02, 0x1d, 0x5e, 0x92, 0x40, 0xae, 0x91, 0x30, 0x61, 0xc4, 0x8b, 0xa8, 0xb8, + 0x13, 0xb8, 0x30, 0xe8, 0xa0, 0xcf, 0x77, 0x02, 0x57, 0x42, 0xb8, 0x09, 0x7f, 0x88, 0x16, 0x36, + 0x83, 0x7d, 0x1a, 0xf9, 0x6b, 0xb6, 0x1d, 0x8c, 0x7d, 0x06, 0x3d, 0xde, 0x94, 0xd8, 0x9c, 0x49, + 0xde, 0xca, 0xc3, 0x57, 0xab, 0x3c, 0x1f, 0x62, 0x0b, 0x3f, 0xd4, 0x54, 0xa7, 0xf2, 0x1a, 0x10, + 0xca, 0xc6, 0x91, 0x2f, 0x92, 0xd2, 0x20, 0x20, 0xf1, 0xaa, 0x6d, 0x5a, 0xf1, 0xbd, 0x98, 0x3a, + 0xc0, 0x78, 0x25, 0xe2, 0x25, 0x54, 0xbb, 0x63, 0x8d, 0xe8, 0x86, 0xcf, 0xa2, 0x09, 0xbc, 0xbd, + 0x61, 0xca, 0x4f, 0x29, 0xa1, 0x23, 0x33, 0x33, 0xbe, 0x89, 0xaa, 0x9f, 0xd2, 0x68, 0xb4, 0x16, + 0xb9, 0x31, 0xbc, 0xfe, 0xa2, 0x99, 0xf9, 0xba, 0x52, 0x36, 0x92, 0xa2, 0x8c, 0xbf, 0x34, 0x54, + 0x55, 0xcf, 0xc6, 0x77, 0x50, 0x65, 0xcd, 0x71, 0x22, 0x1a, 0xc7, 0x32, 0xba, 0xee, 0x3b, 0xc0, + 0xdb, 0xeb, 0x27, 0xf3, 0xd6, 0x8e, 0x26, 0x21, 0x0b, 0x4c, 0xb8, 0x4b, 0x94, 0x13, 0xbc, 0x8d, + 0xf4, 0x75, 0x8b, 0x59, 0xf3, 0x35, 0x81, 0x70, 0x81, 0x77, 0x50, 0xb9, 0x17, 0x84, 0x9e, 0x2d, + 0x97, 0xc3, 0x0b, 0x47, 0x06, 0xce, 0x3e, 0x0f, 0x22, 0x67, 0x79, 0xe5, 0x5d, 0x02, 0x3e, 0x8c, + 0x9f, 0x0b, 0xa8, 0x96, 0x12, 0x02, 0x5f, 0x43, 0x55, 0x2e, 0x88, 0xee, 0x2a, 0x89, 0xee, 0x6a, + 0x1c, 0x4d, 0xdb, 0xa9, 0x8e, 0xa4, 0x27, 0xfe, 0x45, 0xc3, 0xcf, 0xe2, 0x51, 0xb9, 0x0d, 0xa1, + 0xb4, 0x24, 0xb5, 0xf3, 0x88, 0x61, 0x99, 0x16, 0xe6, 0xc8, 0xa5, 0x1a, 0x95, 0x2d, 0x84, 0xee, + 0x32, 0xcb, 0x7e, 0xb0, 0x4e, 0x43, 0x36, 0x80, 0xe9, 0x97, 0xd1, 0xf0, 0x89, 0x03, 0xbc, 0xd2, + 0xe7, 0x9a, 0x38, 0xd2, 0x89, 0xf1, 0x19, 0xc2, 0xcf, 0x12, 0x1c, 0x7f, 0x80, 0x16, 0x40, 0xbe, + 0x17, 0x3a, 0x16, 0xa3, 0x90, 0x83, 0x57, 0x4c, 0xf1, 0xbd, 0xde, 0xa3, 0xa3, 0x70, 0x68, 0x31, + 0x0a, 0x10, 0x92, 0xc7, 0x1a, 0x5f, 0x21, 0x34, 0xeb, 0xea, 0xb3, 0xa6, 0x9a, 0xf1, 0x35, 0xaa, + 0x67, 0x46, 0xc1, 0x99, 0xbb, 0xff, 0xa9, 0x80, 0x72, 0x95, 0xe5, 0x67, 0x18, 0x6c, 0xff, 0xb9, + 0xb2, 0xd2, 0x47, 0xea, 0x8d, 0xce, 0xc7, 0x13, 0xe9, 0x23, 0x6d, 0xb9, 0xe2, 0xfc, 0x2d, 0x77, + 0x11, 0x95, 0xee, 0x5b, 0xc3, 0x31, 0x55, 0xdf, 0x88, 0x42, 0xc0, 0x17, 0x50, 0x71, 0xd3, 0x8a, + 0x61, 0x83, 0xf0, 0x63, 0xb7, 0x7b, 0x70, 0xd8, 0xd2, 0x1e, 0x1f, 0xb6, 0xb4, 0x3f, 0x0e, 0x5b, + 0xda, 0xaf, 0x4f, 0x5b, 0xda, 0xc1, 0xd3, 0x96, 0xf6, 0xe5, 0x29, 0xe1, 0x53, 0xf5, 0x41, 0x20, + 0x4e, 0xfd, 0xb2, 0xd8, 0xd5, 0x6f, 0xff, 0x13, 0x00, 0x00, 0xff, 0xff, 0xba, 0x03, 0xcc, 0x65, 0xcd, 0x0e, 0x00, 0x00, } diff --git a/execution/exec/stream_event_test.go b/execution/exec/stream_event_test.go new file mode 100644 index 000000000..1a935c9ac --- /dev/null +++ b/execution/exec/stream_event_test.go @@ -0,0 +1,68 @@ +package exec + +import ( + "testing" + "time" + + "github.com/hyperledger/burrow/crypto/sha3" + "github.com/hyperledger/burrow/genesis" + "github.com/hyperledger/burrow/txs" + "github.com/hyperledger/burrow/txs/payload" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/abci/types" +) + +var genesisDoc, accounts, _ = genesis.NewDeterministicGenesis(345234523).GenesisDoc(10, 0) + +func TestTxExecution(t *testing.T) { + txe := NewTxExecution(txs.Enclose(genesisDoc.ChainID(), newCallTx(0, 1))) + + stack := new(TxStack) + var txeOut *TxExecution + + for _, ev := range txe.StreamEvents() { + txeOut = stack.Consume(ev) + if txeOut != nil { + require.Equal(t, txe, txeOut) + } + } + + assert.NotNil(t, txeOut, "should have consumed input TxExecution") +} + +func TestConsumeBlockExecution(t *testing.T) { + height := int64(234242) + be := &BlockExecution{ + Header: &types.Header{ + ChainID: genesisDoc.ChainID(), + AppHash: sha3.Sha3([]byte("hashily")), + NumTxs: 1, + Time: time.Now(), + Height: height, + }, + Height: uint64(height), + TxExecutions: []*TxExecution{ + NewTxExecution(txs.Enclose(genesisDoc.ChainID(), newCallTx(0, 3))), + NewTxExecution(txs.Enclose(genesisDoc.ChainID(), newCallTx(0, 2))), + NewTxExecution(txs.Enclose(genesisDoc.ChainID(), newCallTx(2, 1))), + }, + } + + stack := new(BlockAccumulator) + var beOut *BlockExecution + + for _, ev := range be.StreamEvents() { + beOut = stack.Consume(ev) + if beOut != nil { + require.Equal(t, be, beOut) + } + } + assert.NotNil(t, beOut, "should have consumed input BlockExecution") +} + +func newCallTx(fromIndex, toIndex int) *payload.CallTx { + from := accounts[fromIndex] + to := accounts[toIndex].GetAddress() + return payload.NewCallTxWithSequence(from.GetPublicKey(), &to, []byte{1, 2, 3}, 324, 34534534, 23, 1) +} diff --git a/execution/exec/tx_execution.go b/execution/exec/tx_execution.go index 111071e79..949db96a9 100644 --- a/execution/exec/tx_execution.go +++ b/execution/exec/tx_execution.go @@ -70,6 +70,9 @@ func (txe *TxExecution) StreamEvents() StreamEvents { Result: txe.Result, }, }, + &StreamEvent{ + Envelope: txe.Envelope, + }, ) for _, ev := range txe.Events { ses = append(ses, &StreamEvent{ diff --git a/execution/execution.go b/execution/execution.go index 4913343d7..d741e253f 100644 --- a/execution/execution.go +++ b/execution/execution.go @@ -375,7 +375,7 @@ func (exe *executor) GetAccount(address crypto.Address) (*acm.Account, error) { } // Storage -func (exe *executor) GetStorage(address crypto.Address, key binary.Word256) (binary.Word256, error) { +func (exe *executor) GetStorage(address crypto.Address, key binary.Word256) ([]byte, error) { exe.RLock() defer exe.RUnlock() return exe.stateCache.GetStorage(address, key) diff --git a/execution/execution_test.go b/execution/execution_test.go index 9e3b2f357..9b80710c4 100644 --- a/execution/execution_test.go +++ b/execution/execution_test.go @@ -127,7 +127,7 @@ var users = makeUsers(10) var logger = logging.NewNoopLogger() var deterministicGenesis = genesis.NewDeterministicGenesis(34059836243380576) var testGenesisDoc, testPrivAccounts, _ = deterministicGenesis. - GenesisDoc(3, true, 1000, 1, true, 1000) + GenesisDoc(3, 1) var testChainID = testGenesisDoc.ChainID() func TestSendFails(t *testing.T) { @@ -331,7 +331,7 @@ func TestCallPermission(t *testing.T) { simpleAcc := &acm.Account{ Address: simpleContractAddr, Balance: 0, - Code: []byte{0x60}, + EVMCode: []byte{0x60}, Sequence: 0, Permissions: permission.ZeroAccountPermissions, } @@ -352,7 +352,7 @@ func TestCallPermission(t *testing.T) { caller1Acc := &acm.Account{ Address: caller1ContractAddr, Balance: 10000, - Code: contractCode, + EVMCode: contractCode, Sequence: 0, Permissions: permission.ZeroAccountPermissions, } @@ -393,7 +393,7 @@ func TestCallPermission(t *testing.T) { caller2Acc := &acm.Account{ Address: caller2ContractAddr, Balance: 1000, - Code: contractCode2, + EVMCode: contractCode2, Sequence: 0, Permissions: permission.ZeroAccountPermissions, } @@ -459,8 +459,8 @@ func TestCreatePermission(t *testing.T) { if contractAcc == nil { t.Fatalf("failed to create contract %s", contractAddr) } - if !bytes.Equal(contractAcc.Code, contractCode) { - t.Fatalf("contract does not have correct code. Got %X, expected %X", contractAcc.Code, contractCode) + if !bytes.Equal(contractAcc.EVMCode, contractCode) { + t.Fatalf("contract does not have correct code. Got %X, expected %X", contractAcc.EVMCode, contractCode) } //------------------------------ @@ -483,8 +483,8 @@ func TestCreatePermission(t *testing.T) { if contractAcc == nil { t.Fatalf("failed to create contract %s", contractAddr) } - if !bytes.Equal(contractAcc.Code, factoryCode) { - t.Fatalf("contract does not have correct code. Got %X, expected %X", contractAcc.Code, factoryCode) + if !bytes.Equal(contractAcc.EVMCode, factoryCode) { + t.Fatalf("contract does not have correct code. Got %X, expected %X", contractAcc.EVMCode, factoryCode) } //------------------------------ @@ -522,7 +522,7 @@ func TestCreatePermission(t *testing.T) { contractAcc = &acm.Account{ Address: contractAddr, Balance: 1000, - Code: code, + EVMCode: code, Sequence: 0, Permissions: permission.ZeroAccountPermissions, } @@ -538,7 +538,7 @@ func TestCreatePermission(t *testing.T) { _, err = execTxWaitAccountCall(t, exe, txEnv, crypto.Address{}) // require.NoError(t, err) zeroAcc := getAccount(exe.stateCache, crypto.Address{}) - if len(zeroAcc.Code) != 0 { + if len(zeroAcc.EVMCode) != 0 { t.Fatal("the zero account was given code from a CALL!") } } @@ -608,6 +608,7 @@ func TestCreateAccountPermission(t *testing.T) { } tx.AddOutput(users[7].GetAddress(), 10) err = exe.signExecuteCommit(tx, users[:2]...) + require.NoError(t, err) // Two inputs, both with send, both with create, two outputs (one known, one unknown) should pass tx = payload.NewSendTx() @@ -637,7 +638,7 @@ func TestCreateAccountPermission(t *testing.T) { caller1Acc := &acm.Account{ Address: caller1ContractAddr, Balance: 0, - Code: contractCode, + EVMCode: contractCode, Sequence: 0, Permissions: permission.ZeroAccountPermissions, } @@ -702,7 +703,7 @@ func TestSNativeCALL(t *testing.T) { doug := &acm.Account{ Address: DougAddress, Balance: 0, - Code: nil, + EVMCode: nil, Sequence: 0, Permissions: permission.ZeroAccountPermissions, } @@ -1140,9 +1141,9 @@ func TestCreates(t *testing.T) { exe := makeExecutor(st) newAcc1 := getAccount(st, acc1.Address) - newAcc1.Code = preFactoryCode + newAcc1.EVMCode = preFactoryCode newAcc2 := getAccount(st, acc2.Address) - newAcc2.Code = factoryCode + newAcc2.EVMCode = factoryCode exe.updateAccounts(t, newAcc1, newAcc2) @@ -1188,7 +1189,7 @@ func TestCreates(t *testing.T) { require.NoError(t, err) require.NotEqual(t, Zero256, secondCreatedAddress, "should not be zero address") - if firstCreatedAddress == secondCreatedAddress { + if bytes.Equal(firstCreatedAddress, secondCreatedAddress) { t.Errorf("Multiple contracts created with the same address!") } } @@ -1210,7 +1211,7 @@ func TestContractSend(t *testing.T) { acc2 := getAccount(st, privAccounts[2].GetAddress()) newAcc1 := getAccount(st, acc1.Address) - newAcc1.Code = callerCode + newAcc1.EVMCode = callerCode _, _, err := st.Update(func(up state.Updatable) error { return up.UpdateAccount(newAcc1) }) @@ -1292,7 +1293,7 @@ func TestMerklePanic(t *testing.T) { { stateCallTx := makeExecutor(copyState(t, st)) newAcc1 := getAccount(stateCallTx, acc1.Address) - newAcc1.Code = []byte{0x60} + newAcc1.EVMCode = []byte{0x60} err := stateCallTx.stateCache.UpdateAccount(newAcc1) require.NoError(t, err) tx := &payload.CallTx{ @@ -1355,7 +1356,7 @@ func TestTxs(t *testing.T) { { stateCallTx := copyState(t, st) newAcc1 := getAccount(stateCallTx, acc1.Address) - newAcc1.Code = []byte{0x60} + newAcc1.EVMCode = []byte{0x60} _, _, err := stateCallTx.Update(func(up state.Updatable) error { return up.UpdateAccount(newAcc1) }) @@ -1458,7 +1459,7 @@ func TestSelfDestruct(t *testing.T) { contractCode := []byte{0x60, 0x01, 0x60, 0x01, 0x55, 0x73} contractCode = append(contractCode, acc2.Address.Bytes()...) contractCode = append(contractCode, 0xff) - newAcc1.Code = contractCode + newAcc1.EVMCode = contractCode _, _, err := st.Update(func(up state.Updatable) error { return up.UpdateAccount(newAcc1) }) @@ -1546,8 +1547,7 @@ func newBaseGenDoc(globalPerm, accountPerm permission.AccountPermissions) genesi func makeGenesisState(numAccounts int, randBalance bool, minBalance uint64, numValidators int, randBonded bool, minBonded int64) (*state.State, []*acm.PrivateAccount) { - testGenesisDoc, privAccounts, _ := deterministicGenesis.GenesisDoc(numAccounts, randBalance, minBalance, - numValidators, randBonded, minBonded) + testGenesisDoc, privAccounts, _ := deterministicGenesis.GenesisDoc(numAccounts, numValidators) s0, err := state.MakeGenesisState(dbm.NewMemDB(), testGenesisDoc) if err != nil { panic(fmt.Errorf("could not make genesis state: %v", err)) @@ -1575,8 +1575,6 @@ func addressPtr(account *acm.Account) *crypto.Address { return &accountAddresss } -var ExceptionTimeOut = errors.NewException(errors.ErrorCodeGeneric, "timed out waiting for event") - type testExecutor struct { *executor *bcm.Blockchain @@ -1697,7 +1695,7 @@ func testSNativeCALL(t *testing.T, expectPass bool, exe *testExecutor, doug *acm doug.Permissions.Base.Set(snativePerm, true) } - doug.Code = callContractCode(snativeAddress) + doug.EVMCode = callContractCode(snativeAddress) dougAddress := doug.Address exe.updateAccounts(t, doug) diff --git a/execution/simulated_call.go b/execution/simulated_call.go index bff6d5138..ac7e877a5 100644 --- a/execution/simulated_call.go +++ b/execution/simulated_call.go @@ -14,18 +14,18 @@ import ( // Run a contract's code on an isolated and unpersisted state // Cannot be used to create new contracts -func CallSim(reader acmstate.Reader, tip bcm.BlockchainInfo, fromAddress, address crypto.Address, data []byte, +func CallSim(reader acmstate.Reader, blockchain bcm.BlockchainInfo, fromAddress, address crypto.Address, data []byte, logger *logging.Logger) (*exec.TxExecution, error) { cache := acmstate.NewCache(reader) exe := contexts.CallContext{ RunCall: true, StateWriter: cache, - Blockchain: tip, + Blockchain: blockchain, Logger: logger, } - txe := exec.NewTxExecution(txs.Enclose(tip.ChainID(), &payload.CallTx{ + txe := exec.NewTxExecution(txs.Enclose(blockchain.ChainID(), &payload.CallTx{ Input: &payload.TxInput{ Address: fromAddress, }, @@ -42,18 +42,18 @@ func CallSim(reader acmstate.Reader, tip bcm.BlockchainInfo, fromAddress, addres // Run the given code on an isolated and unpersisted state // Cannot be used to create new contracts. -func CallCodeSim(reader acmstate.Reader, tip bcm.BlockchainInfo, fromAddress, address crypto.Address, code, data []byte, +func CallCodeSim(reader acmstate.Reader, blockchain bcm.BlockchainInfo, fromAddress, address crypto.Address, code, data []byte, logger *logging.Logger) (*exec.TxExecution, error) { // Attach code to target account (overwriting target) cache := acmstate.NewCache(reader) err := cache.UpdateAccount(&acm.Account{ Address: address, - Code: code, + EVMCode: code, }) if err != nil { return nil, err } - return CallSim(cache, tip, fromAddress, address, data, logger) + return CallSim(cache, blockchain, fromAddress, address, data, logger) } diff --git a/execution/state/accounts.go b/execution/state/accounts.go index 957a70c6f..28b1352c1 100644 --- a/execution/state/accounts.go +++ b/execution/state/accounts.go @@ -24,7 +24,7 @@ func (s *ReadState) GetAccount(address crypto.Address) (*acm.Account, error) { func (ws *writeState) statsAddAccount(acc *acm.Account) { if acc != nil { - if len(acc.Code) > 0 { + if len(acc.EVMCode) > 0 || len(acc.WASMCode) > 0 { ws.accountStats.AccountsWithCode++ } else { ws.accountStats.AccountsWithoutCode++ @@ -34,7 +34,7 @@ func (ws *writeState) statsAddAccount(acc *acm.Account) { func (ws *writeState) statsRemoveAccount(acc *acm.Account) { if acc != nil { - if len(acc.Code) > 0 { + if len(acc.EVMCode) > 0 || len(acc.WASMCode) > 0 { ws.accountStats.AccountsWithCode-- } else { ws.accountStats.AccountsWithoutCode-- @@ -102,30 +102,37 @@ func (s *State) GetAccountStats() acmstate.AccountStats { // Storage -func (s *ReadState) GetStorage(address crypto.Address, key binary.Word256) (binary.Word256, error) { +func (s *ReadState) GetStorage(address crypto.Address, key binary.Word256) ([]byte, error) { keyFormat := keys.Storage.Fix(address) tree, err := s.Forest.Reader(keyFormat.Prefix()) if err != nil { - return binary.Zero256, err + return []byte{}, err } - return binary.LeftPadWord256(tree.Get(keyFormat.KeyNoPrefix(key))), nil + return tree.Get(keyFormat.KeyNoPrefix(key)), nil } -func (ws *writeState) SetStorage(address crypto.Address, key, value binary.Word256) error { +func (ws *writeState) SetStorage(address crypto.Address, key binary.Word256, value []byte) error { keyFormat := keys.Storage.Fix(address) tree, err := ws.forest.Writer(keyFormat.Prefix()) if err != nil { return err } - if value == binary.Zero256 { + zero := true + for _, b := range value { + if b != 0 { + zero = false + break + } + } + if zero { tree.Delete(keyFormat.KeyNoPrefix(key)) } else { - tree.Set(keyFormat.KeyNoPrefix(key), value.Bytes()) + tree.Set(keyFormat.KeyNoPrefix(key), value) } return nil } -func (s *ReadState) IterateStorage(address crypto.Address, consumer func(key, value binary.Word256) error) error { +func (s *ReadState) IterateStorage(address crypto.Address, consumer func(key binary.Word256, value []byte) error) error { keyFormat := keys.Storage.Fix(address) tree, err := s.Forest.Reader(keyFormat.Prefix()) if err != nil { @@ -142,6 +149,6 @@ func (s *ReadState) IterateStorage(address crypto.Address, consumer func(key, va return fmt.Errorf("value '%X' stored for account %s is not a %v-byte word", key, address, binary.Word256Length) } - return consumer(binary.LeftPadWord256(key), binary.LeftPadWord256(value)) + return consumer(binary.LeftPadWord256(key), value) }) } diff --git a/execution/state/events.go b/execution/state/events.go index 2e4339556..06d912870 100644 --- a/execution/state/events.go +++ b/execution/state/events.go @@ -5,12 +5,12 @@ import ( "fmt" "io" - "github.com/tendermint/go-amino" + "github.com/hyperledger/burrow/txs" "github.com/hyperledger/burrow/execution/exec" ) -var cdc = amino.NewCodec() +var cdc = txs.NewAminoCodec() func (ws *writeState) AddBlock(be *exec.BlockExecution) error { // If there are no transactions, do not store anything. This reduces the amount of data we store and diff --git a/execution/state/events_test.go b/execution/state/events_test.go index a18fbc66a..b15fb7c3e 100644 --- a/execution/state/events_test.go +++ b/execution/state/events_test.go @@ -1,6 +1,7 @@ package state import ( + bin "encoding/binary" "fmt" "testing" @@ -147,9 +148,9 @@ func mkBlock(height, numTxs, events uint64) *exec.BlockExecution { func mkTx(height, txIndex, events uint64) *exec.TxExecution { hash := make([]byte, 32) - binary.PutUint64(hash[:8], height) - binary.PutUint64(hash[8:16], txIndex) - binary.PutUint64(hash[16:24], events) + bin.BigEndian.PutUint64(hash[:8], height) + bin.BigEndian.PutUint64(hash[8:16], txIndex) + bin.BigEndian.PutUint64(hash[16:24], events) txe := &exec.TxExecution{ TxHeader: &exec.TxHeader{ TxHash: hash, diff --git a/execution/state/state.go b/execution/state/state.go index 25302c8c3..3b125c567 100644 --- a/execution/state/state.go +++ b/execution/state/state.go @@ -200,7 +200,7 @@ func LoadState(db dbm.DB, version int64) (*State, error) { } // Populate stats. If this starts taking too long, store the value rather than the full scan at startup err = s.IterateAccounts(func(acc *acm.Account) error { - if len(acc.Code) > 0 { + if len(acc.EVMCode) > 0 || len(acc.WASMCode) > 0 { s.writeState.accountStats.AccountsWithCode++ } else { s.writeState.accountStats.AccountsWithoutCode++ diff --git a/execution/state/validators.go b/execution/state/validators.go index 96e0b5f66..d43dc1385 100644 --- a/execution/state/validators.go +++ b/execution/state/validators.go @@ -35,6 +35,9 @@ func LoadValidatorRing(version int64, ringSize int, ring := validator.NewRing(nil, ringSize) // Load the IAVL state rs.Forest, err = getImmutable(startVersion) + if err != nil { + return nil, err + } // Write the validator state at startVersion from IAVL tree into the ring's current bucket delta err = validator.Write(ring, rs) if err != nil { diff --git a/execution/transactor.go b/execution/transactor.go index 30660c2f2..944588447 100644 --- a/execution/transactor.go +++ b/execution/transactor.go @@ -23,7 +23,6 @@ import ( "github.com/hyperledger/burrow/acm" "github.com/hyperledger/burrow/bcm" "github.com/hyperledger/burrow/consensus/tendermint/codes" - "github.com/hyperledger/burrow/crypto" "github.com/hyperledger/burrow/event" "github.com/hyperledger/burrow/execution/errors" "github.com/hyperledger/burrow/execution/exec" @@ -197,6 +196,9 @@ func (trans *Transactor) SignTx(txEnv *txs.Envelope) (*txs.Envelope, error) { signers := make([]acm.AddressableSigner, len(inputs)) for i, input := range inputs { signers[i], err = trans.MempoolAccounts.SigningAccount(input.Address) + if err != nil { + return nil, err + } } err = txEnv.Sign(signers...) if err != nil { @@ -252,11 +254,3 @@ func (trans *Transactor) CheckTxAsync(txEnv *txs.Envelope, callback func(res *ab } return trans.CheckTxAsyncRaw(txBytes, callback) } - -func (trans *Transactor) CallCodeSim(fromAddress crypto.Address, code, data []byte) (*exec.TxExecution, error) { - return CallCodeSim(trans.MempoolAccounts, trans.BlockchainInfo, fromAddress, fromAddress, code, data, trans.logger) -} - -func (trans *Transactor) CallSim(fromAddress, address crypto.Address, data []byte) (*exec.TxExecution, error) { - return CallSim(trans.MempoolAccounts, trans.BlockchainInfo, fromAddress, address, data, trans.logger) -} diff --git a/execution/wasm/storage_test.solang b/execution/wasm/storage_test.solang new file mode 100644 index 000000000..5ad6e43ff --- /dev/null +++ b/execution/wasm/storage_test.solang @@ -0,0 +1,17 @@ + + +contract storage_test { + uint64 foo; + + constructor() public { + foo = 102; + } + + function getFooPlus2() public view returns (uint64) { + return foo + 2; + } + + function incFoo() public { + foo += 1; + } +} diff --git a/execution/wasm/storage_test.solang.go b/execution/wasm/storage_test.solang.go new file mode 100644 index 000000000..f3635e11b --- /dev/null +++ b/execution/wasm/storage_test.solang.go @@ -0,0 +1,6 @@ +package wasm + +import hex "github.com/tmthrgd/go-hex" + +var Bytecode_storage_test = hex.MustDecodeString("0061736D0100000001220760037F7F7F0060027F7F0060000060017F0060017F017F60027F7F017F6000017E02380303656E760D7365745F73746F726167653332000003656E760D6765745F73746F726167653332000003656E76066D656D6F727902010202030F0E00010102030405000002060203040608017F01418080040B07BB010E095F5F6D656D637079380002085F5F627A65726F380003075F5F627365743800040B5F5F696E69745F686561700005065F5F667265650006085F5F6D616C6C6F630007095F5F7265616C6C6F6300080B5F5F62653332746F6C654E00090B5F5F6C654E746F62653332000A12736F6C3A3A5F5F636F6E7374727563746F72000B10736F6C3A3A676574466F6F506C757332000C0B736F6C3A3A696E63466F6F000D0B636F6E7374727563746F72000E0866756E6374696F6E000F0AF8080E2600034020002001290300370300200041086A2100200141086A21012002417F6A22020D000B0B1C00034020004200370300200041086A21002001417F6A22010D000B0B1C0003402000427F370300200041086A21002001417F6A22010D000B0B2B00410041003602808004410041003602848004410041003A008C800441003F0041F0FF7B6A36028880040BB90101037F02402000450D00410021012000417C6A41003A0000024002400240200041706A22022802002203450D0020032D000C450D01200321010B200041746A2802002203450D020C010B20022003280200220136020002402001450D00200120023602040B200041786A2202200328020820022802006A41106A360200200041746A2802002203450D010B20032D000C0D0020012003360204200320013602002003200041786A28020020032802086A41106A3602080F0B0BA90101047F41808004210102400340024020012D000C0D002001280208220220004F0D020B200128020022010D000B41002101410028020821020B02402002200041076A41787122036B22024118490D00200120036A41106A22002001280200220436020002402004450D00200420003602040B2000200241706A360208200041003A000C2000200136020420012000360200200141086A20033602000B200141013A000C200141106A0BF50101057F024002400240200041706A22022802002203450D0020032D000C0D00200041786A220428020020032802086A41106A220520014F0D010B41002103410020014103766B21022001100721010340200120036A200020036A290300370300200341086A2103200241016A22020D000B20001006200121000C010B20042005360200200328020022032002360204200220033602002005200141076A41787122066B22054118490D00200020066A2201200336020002402003450D00200341046A20013602000B2001200541706A360208200141003A000C20012002360204200220013602002004200636020020000F0B20000B2D002000411F6A21000340200120002D00003A0000200141016A21012000417F6A21002002417F6A22020D000B0B2D002001411F6A21010340200120002D00003A00002001417F6A2101200041016A21002002417F6A22020D000B0B2701017F230041106B22002400200042E6003703084100200041086A41081000200041106A24000B2D02017F017E230041106B220024004100200041086A4108100120002903082101200041106A2400200142027C0B3701017F230041106B220024004100200041086A410810012000200029030842017C3703084100200041086A41081000200041106A24000B12001005024020002802000D00100B0F0B000B8E0103037F017E017F23002201210202402000280200220341034D0D002003417C6A21030240200041046A28020041DE9AB88F79470D0020030D01100D41041007220041003602002002240020000F0B20030D00100C21044124100722004120360200200041046A220541041003200141706A2203240020032004370300200320054108100A2002240020000F0B000B") +var Abi_storage_test = []byte(`[{"name":"","type":"constructor","inputs":[],"outputs":[],"constant":false,"payable":false,"stateMutability":"nonpayable"},{"name":"getFooPlus2","type":"function","inputs":[],"outputs":[{"name":"","type":"uint64"}],"constant":true,"payable":false,"stateMutability":"view"},{"name":"incFoo","type":"function","inputs":[],"outputs":[],"constant":false,"payable":false,"stateMutability":"nonpayable"}]`) diff --git a/execution/wasm/wasm.go b/execution/wasm/wasm.go new file mode 100644 index 000000000..1e3f24218 --- /dev/null +++ b/execution/wasm/wasm.go @@ -0,0 +1,150 @@ +package wasm + +import ( + "encoding/binary" + "fmt" + + burrow_binary "github.com/hyperledger/burrow/binary" + "github.com/hyperledger/burrow/crypto" + "github.com/hyperledger/burrow/execution/errors" + "github.com/hyperledger/burrow/execution/evm" + "github.com/perlin-network/life/exec" +) + +type execContext struct { + address crypto.Address + state evm.Interface +} + +// In EVM, the code for an account is created by the EVM code itself; the code in the EVM deploy transaction is run, +// and the EVM code returns (via the RETURN) opcode) the code for the contract. In addition, when a new contract is +// created using the "new C()" construct is soldity, the EVM itself passes the code for the new contract. + +// The compiler must embed any contract code for smart contracts it wants to create. +// - This does not allow for circular references: contract A creates contract B, contract B creates contract A. +// - This makes it very hard to support other languages; e.g. go or rust have no such bizarre concepts, and would +// require tricking into supporting this +// - This makes it possible for tricksy contracts that create different contracts at different times. Very hard to +// support static analysis on these contracts +// - This makes it hard to know ahead-of-time what the code for a contract will be + +// Our WASM implementation does not allow for this. The code passed to the deploy transaction, is the contract. Any child contracts must be passed +// during the initial deployment (not implemented yet) + +// ABIs +// Our WASM ABI is entirely compatible with Solidity. This means that solidity EVM can call WASM contracts and vice +// versa. However, in the EVM ABI model the difference between constructor calls and function calls are implicit: the +// constructor code path is different from the function call code path, and there is nothing visible in the binary ABI +// encoded arguments telling you that it is a function call or a constructor. Note function calls do have a 4 byte +// prefix but this is not required; without it the fallback function should be called. + +// So in our WASM model the smart contract has two entry points: constructor and function. + +// ABIs memory space +// In the EVM model, ABIs are passed via the calldata opcodes. This means that the ABI encoded data is not directly +// accessible and has to be copied to smart contract memory. Solidity exposes this via the calldata and memory +// modifiers on variables. + +// In our WASM model, the function and constructor WASM fuctions have one argument and return value. The argument is +// where in WASM memory the ABI encoded arguments are and the return value is the offset where the return data can be +// found. At this offset we first find a 32 bit little endian encoded length (since WASM is little endian and we are +// using 32 bit memory model) followed by the bytes themselves. + +// Contract Storage +// In the EVM model, contract storage is addressed via 256 bit key and the contents is a 256 bit value. For WASM, +// we've changed the contents to a arbitary byte string. This makes it much easier to store/retrieve smaller values +// (e.g. int64) and dynamic length fields (e.g. strings/arrays). + +// Access to contract storage is via WASM externals. +// - set_storage32(uint32 key, uint8* data, uint32 len) // set contract storage +// - get_storage32(uint32 key, uint8* data, uint32 len) // get contract storage (right pad with zeros) + +// RunWASM creates a WASM VM, and executes the given WASM contract code +func RunWASM(state evm.Interface, address crypto.Address, createContract bool, wasm, input []byte) (output []byte, cerr errors.CodedError) { + defer func() { + if r := recover(); r != nil { + cerr = errors.ErrorCodeExecutionAborted + } + }() + // WASM + config := exec.VMConfig{ + DisableFloatingPoint: true, + MaxMemoryPages: 2, + DefaultMemoryPages: 2, + } + + execContext := execContext{address, state} + + vm, err := exec.NewVirtualMachine(wasm, config, &execContext, nil) + + if err != nil { + return []byte{}, errors.ErrorCodeInvalidContract + } + + // FIXME: Check length + if len(input) > 0 { + binary.LittleEndian.PutUint32(vm.Memory[:], uint32(len(input))) + copy(vm.Memory[4:], input) + } + + wasmFunc := "function" + if createContract { + wasmFunc = "constructor" + } + entryID, ok := vm.GetFunctionExport(wasmFunc) + if !ok { + return []byte{}, errors.ErrorCodeUnresolvedSymbols + } + + // The 0 argument is the offset where our calldata is stored (if any) + offset, err := vm.Run(entryID, 0) + if err != nil { + return []byte{}, errors.ErrorCodeExecutionAborted + } + + if offset > 0 { + // FIXME: Check length + length := binary.LittleEndian.Uint32(vm.Memory[offset : offset+4]) + output = vm.Memory[offset+4 : offset+4+int64(length)] + } + + return +} + +func (e *execContext) ResolveFunc(module, field string) exec.FunctionImport { + if module != "env" { + panic(fmt.Sprintf("unknown module %s", module)) + } + + switch field { + case "set_storage32": + return func(vm *exec.VirtualMachine) int64 { + key := int(uint32(vm.GetCurrentFrame().Locals[0])) + ptr := int(uint32(vm.GetCurrentFrame().Locals[1])) + len := int(uint32(vm.GetCurrentFrame().Locals[2])) + // FIXME: Check length + e.state.SetStorage(e.address, burrow_binary.Int64ToWord256(int64(key)), vm.Memory[ptr:ptr+len]) + return 0 + } + + case "get_storage32": + return func(vm *exec.VirtualMachine) int64 { + key := int(uint32(vm.GetCurrentFrame().Locals[0])) + ptr := int(uint32(vm.GetCurrentFrame().Locals[1])) + length := int(uint32(vm.GetCurrentFrame().Locals[2])) + val := e.state.GetStorage(e.address, burrow_binary.Int64ToWord256(int64(key))) + if len(val) < length { + val = append(val, make([]byte, length-len(val))...) + } + // FIXME: Check length + copy(vm.Memory[ptr:ptr+length], val) + return 0 + } + default: + panic(fmt.Sprintf("unknown function %s", field)) + } +} + +func (e *execContext) ResolveGlobal(module, field string) int64 { + panic(fmt.Sprintf("global %s module %s not found", field, module)) +} diff --git a/execution/wasm/wasm_test.go b/execution/wasm/wasm_test.go new file mode 100644 index 000000000..7e9a29293 --- /dev/null +++ b/execution/wasm/wasm_test.go @@ -0,0 +1,66 @@ +package wasm + +import ( + "fmt" + "testing" + + "github.com/hyperledger/burrow/binary" + "github.com/hyperledger/burrow/execution/evm" + + "github.com/hyperledger/burrow/acm/acmstate" + "github.com/hyperledger/burrow/execution/evm/abi" + + "github.com/hyperledger/burrow/crypto" + "github.com/stretchr/testify/require" +) + +func TestStaticCallWithValue(t *testing.T) { + cache := evm.NewState(acmstate.NewMemoryState(), blockHashGetter) + + cache.CreateAccount(crypto.ZeroAddress) + // run constructor + _, cerr := RunWASM(cache, crypto.ZeroAddress, true, Bytecode_storage_test, []byte{}) + require.NoError(t, cerr) + + // run getFooPlus2 + spec, err := abi.ReadAbiSpec(Abi_storage_test) + require.NoError(t, err) + calldata, _, err := spec.Pack("getFooPlus2") + + returndata, cerr := RunWASM(cache, crypto.ZeroAddress, false, Bytecode_storage_test, calldata) + require.NoError(t, cerr) + + data := abi.GetPackingTypes(spec.Functions["getFooPlus2"].Outputs) + + err = spec.Unpack(returndata, "getFooPlus2", data...) + require.NoError(t, err) + returnValue := *data[0].(*uint64) + var expected uint64 + expected = 104 + require.Equal(t, expected, returnValue) + + // call incFoo + calldata, _, err = spec.Pack("incFoo") + + returndata, cerr = RunWASM(cache, crypto.ZeroAddress, false, Bytecode_storage_test, calldata) + require.NoError(t, cerr) + + require.Equal(t, returndata, []byte{}) + + // run getFooPlus2 + calldata, _, err = spec.Pack("getFooPlus2") + require.NoError(t, err) + + returndata, cerr = RunWASM(cache, crypto.ZeroAddress, false, Bytecode_storage_test, calldata) + require.NoError(t, cerr) + + spec.Unpack(returndata, "getFooPlus2", data...) + expected = 105 + returnValue = *data[0].(*uint64) + + require.Equal(t, expected, returnValue) +} + +func blockHashGetter(height uint64) []byte { + return binary.LeftPadWord256([]byte(fmt.Sprintf("block_hash_%d", height))).Bytes() +} diff --git a/storage/cache_db.go b/forensics/cache_db.go similarity index 84% rename from storage/cache_db.go rename to forensics/cache_db.go index af5607c8e..293f0ed2e 100644 --- a/storage/cache_db.go +++ b/forensics/cache_db.go @@ -1,15 +1,16 @@ -package storage +package forensics import ( + "github.com/hyperledger/burrow/storage" dbm "github.com/tendermint/tendermint/libs/db" ) type CacheDB struct { cache *KVCache - backend KVIterableReader + backend storage.KVIterableReader } -func NewCacheDB(backend KVIterableReader) *CacheDB { +func NewCacheDB(backend storage.KVIterableReader) *CacheDB { return &CacheDB{ cache: NewKVCache(), backend: backend, @@ -33,13 +34,13 @@ func (cdb *CacheDB) Has(key []byte) bool { return !deleted && (value != nil || cdb.backend.Has(key)) } -func (cdb *CacheDB) Iterator(low, high []byte) KVIterator { +func (cdb *CacheDB) Iterator(low, high []byte) storage.KVIterator { // Keys from cache will sort first because of order in MultiIterator and Uniq will take the first KVs so KVs // appearing in cache will override values from backend. return Uniq(NewMultiIterator(false, cdb.cache.Iterator(low, high), cdb.backend.Iterator(low, high))) } -func (cdb *CacheDB) ReverseIterator(low, high []byte) KVIterator { +func (cdb *CacheDB) ReverseIterator(low, high []byte) storage.KVIterator { return Uniq(NewMultiIterator(true, cdb.cache.ReverseIterator(low, high), cdb.backend.ReverseIterator(low, high))) } @@ -69,7 +70,7 @@ func (cdb *CacheDB) NewBatch() dbm.Batch { } } -func (cdb *CacheDB) Commit(writer KVWriter) { +func (cdb *CacheDB) Commit(writer storage.KVWriter) { cdb.cache.WriteTo(writer) cdb.cache.Reset() } diff --git a/storage/cache_db_test.go b/forensics/cache_db_test.go similarity index 86% rename from storage/cache_db_test.go rename to forensics/cache_db_test.go index 67ce7a5c3..08b93ef3b 100644 --- a/storage/cache_db_test.go +++ b/forensics/cache_db_test.go @@ -1,4 +1,4 @@ -package storage +package forensics import ( "fmt" @@ -11,10 +11,10 @@ import ( func TestBatchCommit(t *testing.T) { db := dbm.NewMemDB() cdb := NewCacheDB(db) - foo := bz("foo") - bam := bz("bam") - bosh := bz("bosh") - boom := bz("boom") + foo := []byte("foo") + bam := []byte("bam") + bosh := []byte("bosh") + boom := []byte("boom") db.Set(foo, bam) assert.Equal(t, bam, cdb.Get(foo), "underlying writes should be seen") cdb.Set(foo, bosh) @@ -39,10 +39,10 @@ func TestBatchCommit(t *testing.T) { func TestCacheDB_Iterator(t *testing.T) { db := dbm.NewMemDB() cdb := NewCacheDB(db) - foo := bz("foo") - bam := bz("bam") - bosh := bz("bosh") - boom := bz("boom") + foo := []byte("foo") + bam := []byte("bam") + bosh := []byte("bosh") + boom := []byte("boom") db.Set(append(foo, foo...), foo) db.Set(append(foo, bam...), bam) diff --git a/storage/channel_iterator.go b/forensics/channel_iterator.go similarity index 99% rename from storage/channel_iterator.go rename to forensics/channel_iterator.go index a59eb737e..897e86b4f 100644 --- a/storage/channel_iterator.go +++ b/forensics/channel_iterator.go @@ -1,4 +1,4 @@ -package storage +package forensics import ( "bytes" diff --git a/forensics/channel_iterator_test.go b/forensics/channel_iterator_test.go new file mode 100644 index 000000000..998d2bcb9 --- /dev/null +++ b/forensics/channel_iterator_test.go @@ -0,0 +1,52 @@ +package forensics + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + dbm "github.com/tendermint/tendermint/libs/db" +) + +func TestNewChannelIterator(t *testing.T) { + ch := make(chan KVPair) + go sendKVPair(ch, kvPairs("a", "hello", "b", "channel", "c", "this is nice")) + ci := NewChannelIterator(ch, []byte("a"), []byte("c")) + checkItem(t, ci, []byte("a"), []byte("hello")) + checkNext(t, ci, true) + checkItem(t, ci, []byte("b"), []byte("channel")) + checkNext(t, ci, true) + checkItem(t, ci, []byte("c"), []byte("this is nice")) + checkNext(t, ci, false) + checkInvalid(t, ci) +} + +func checkInvalid(t *testing.T, itr dbm.Iterator) { + checkValid(t, itr, false) + checkKeyPanics(t, itr) + checkValuePanics(t, itr) + checkNextPanics(t, itr) +} + +func checkValid(t *testing.T, itr dbm.Iterator, expected bool) { + valid := itr.Valid() + require.Equal(t, expected, valid) +} + +func checkNext(t *testing.T, itr dbm.Iterator, expected bool) { + itr.Next() + valid := itr.Valid() + require.Equal(t, expected, valid) +} + +func checkNextPanics(t *testing.T, itr dbm.Iterator) { + assert.Panics(t, func() { itr.Next() }, "checkNextPanics expected panic but didn't") +} +func checkKeyPanics(t *testing.T, itr dbm.Iterator) { + assert.Panics(t, func() { itr.Key() }, "checkKeyPanics expected panic but didn't") +} + +func checkValuePanics(t *testing.T, itr dbm.Iterator) { + assert.Panics(t, func() { itr.Key() }, "checkValuePanics expected panic but didn't") +} diff --git a/storage/kvcache.go b/forensics/kvcache.go similarity index 86% rename from storage/kvcache.go rename to forensics/kvcache.go index c17004c65..16cafb532 100644 --- a/storage/kvcache.go +++ b/forensics/kvcache.go @@ -1,9 +1,11 @@ -package storage +package forensics import ( "bytes" "sort" "sync" + + "github.com/hyperledger/burrow/storage" ) type KVCache struct { @@ -91,22 +93,22 @@ func (kvc *KVCache) Delete(key []byte) { kvc.cache[skey] = vi } -func (kvc *KVCache) Iterator(low, high []byte) KVIterator { +func (kvc *KVCache) Iterator(low, high []byte) storage.KVIterator { kvc.RLock() defer kvc.RUnlock() - low, high = NormaliseDomain(low, high) + low, high = storage.NormaliseDomain(low, high) return kvc.newIterator(low, high, false) } -func (kvc *KVCache) ReverseIterator(low, high []byte) KVIterator { +func (kvc *KVCache) ReverseIterator(low, high []byte) storage.KVIterator { kvc.RLock() defer kvc.RUnlock() - low, high = NormaliseDomain(low, high) + low, high = storage.NormaliseDomain(low, high) return kvc.newIterator(low, high, true) } // Writes contents of cache to backend without flushing the cache -func (kvc *KVCache) WriteTo(writer KVWriter) { +func (kvc *KVCache) WriteTo(writer storage.KVWriter) { kvc.Lock() defer kvc.Unlock() for k, vi := range kvc.cache { @@ -133,7 +135,7 @@ func (kvc *KVCache) sortedKeysInDomain(low, high []byte) [][]byte { startIndex := len(kvc.keys) for i, key := range sortedKeys { // !(key < start) => key >= start then include (inclusive start) - if CompareKeys(key, low) != -1 { + if storage.CompareKeys(key, low) != -1 { startIndex = i break } @@ -142,7 +144,7 @@ func (kvc *KVCache) sortedKeysInDomain(low, high []byte) [][]byte { sortedKeys = sortedKeys[startIndex:] for i, key := range sortedKeys { // !(key < end) => key >= end then exclude (exclusive end) - if CompareKeys(key, high) != -1 { + if storage.CompareKeys(key, high) != -1 { sortedKeys = sortedKeys[:i] break } @@ -209,15 +211,3 @@ func (kvi *KVCacheIterator) sliceIndex() int { } return kvi.keyIndex } - -func insertKey(sortedKeys [][]byte, key []byte) [][]byte { - i := sort.Search(len(sortedKeys), func(i int) bool { - // Smallest sortedKey such that key - return bytes.Compare(sortedKeys[i], key) > -1 - }) - // ensure space - sortedKeys = append(sortedKeys, nil) - copy(sortedKeys[i+1:], sortedKeys[i:]) - sortedKeys[i] = key - return sortedKeys -} diff --git a/storage/kvcache_test.go b/forensics/kvcache_test.go similarity index 54% rename from storage/kvcache_test.go rename to forensics/kvcache_test.go index 9d39db097..6c33d80a3 100644 --- a/storage/kvcache_test.go +++ b/forensics/kvcache_test.go @@ -1,10 +1,11 @@ -package storage +package forensics import ( + bin "encoding/binary" "math/rand" "testing" - "github.com/hyperledger/burrow/binary" + "github.com/hyperledger/burrow/storage" "github.com/stretchr/testify/assert" ) @@ -30,20 +31,20 @@ func TestKVCache_Iterator(t *testing.T) { } func TestKVCache_Iterator2(t *testing.T) { - assert.Equal(t, []string{"b"}, testIterate(bz("b"), bz("c"), false, "a", "b", "c", "d")) - assert.Equal(t, []string{"b", "c"}, testIterate(bz("b"), bz("cc"), false, "a", "b", "c", "d")) - assert.Equal(t, []string{"a", "b", "c", "d"}, testIterate(bz(""), nil, false, "a", "b", "c", "d")) - assert.Equal(t, []string{"d", "c", "b", "a"}, testIterate(bz(""), nil, true, "a", "b", "c", "d")) + assert.Equal(t, []string{"b"}, testIterate([]byte("b"), []byte("c"), false, "a", "b", "c", "d")) + assert.Equal(t, []string{"b", "c"}, testIterate([]byte("b"), []byte("cc"), false, "a", "b", "c", "d")) + assert.Equal(t, []string{"a", "b", "c", "d"}, testIterate([]byte(""), nil, false, "a", "b", "c", "d")) + assert.Equal(t, []string{"d", "c", "b", "a"}, testIterate([]byte(""), nil, true, "a", "b", "c", "d")) assert.Equal(t, []string{"a", "b", "c", "d"}, testIterate(nil, nil, false, "a", "b", "c", "d")) - assert.Equal(t, []string{}, testIterate(bz(""), bz(""), false, "a", "b", "c", "d")) - assert.Equal(t, []string{}, testIterate(bz("ab"), bz("ab"), false, "a", "b", "c", "d")) - assert.Equal(t, []string{"a"}, testIterate(bz("0"), bz("ab"), true, "a", "b", "c", "d")) - assert.Equal(t, []string{"c", "b", "a"}, testIterate(bz("a"), bz("c1"), true, "a", "b", "c", "d")) - assert.Equal(t, []string{"b", "a"}, testIterate(bz("a"), bz("c"), true, "a", "b", "c", "d")) - assert.Equal(t, []string{"b", "a"}, testIterate(bz("a"), bz("c"), true, "a", "b", "c", "d")) - assert.Equal(t, []string{}, testIterate(bz("c"), bz("e"), true, "a", "b")) - assert.Equal(t, []string{}, testIterate(bz("c"), bz("e"), true, "z", "f")) + assert.Equal(t, []string{}, testIterate([]byte(""), []byte(""), false, "a", "b", "c", "d")) + assert.Equal(t, []string{}, testIterate([]byte("ab"), []byte("ab"), false, "a", "b", "c", "d")) + assert.Equal(t, []string{"a"}, testIterate([]byte("0"), []byte("ab"), true, "a", "b", "c", "d")) + assert.Equal(t, []string{"c", "b", "a"}, testIterate([]byte("a"), []byte("c1"), true, "a", "b", "c", "d")) + assert.Equal(t, []string{"b", "a"}, testIterate([]byte("a"), []byte("c"), true, "a", "b", "c", "d")) + assert.Equal(t, []string{"b", "a"}, testIterate([]byte("a"), []byte("c"), true, "a", "b", "c", "d")) + assert.Equal(t, []string{}, testIterate([]byte("c"), []byte("e"), true, "a", "b")) + assert.Equal(t, []string{}, testIterate([]byte("c"), []byte("e"), true, "z", "f")) } func BenchmarkKVCache_Iterator_1E6_Inserts(b *testing.B) { @@ -61,7 +62,7 @@ func benchmarkKVCache_Iterator(b *testing.B, inserts int) { keyvals := make([][]byte, inserts) for i := 0; i < inserts; i++ { bs := make([]byte, 8) - binary.PutInt64(bs, rnd.Int63()) + bin.BigEndian.PutUint64(bs, uint64(rnd.Int63())) keyvals[i] = bs } for i := 0; i < inserts; i++ { @@ -82,7 +83,7 @@ func testIterate(low, high []byte, reverse bool, keys ...string) []string { bs := []byte(k) kvc.Set(bs, bs) } - var it KVIterator + var it storage.KVIterator if reverse { it = kvc.ReverseIterator(low, high) } else { diff --git a/storage/multi_iterator.go b/forensics/multi_iterator.go similarity index 79% rename from storage/multi_iterator.go rename to forensics/multi_iterator.go index 8152e5cca..a74cec68d 100644 --- a/storage/multi_iterator.go +++ b/forensics/multi_iterator.go @@ -1,21 +1,23 @@ -package storage +package forensics import ( "bytes" "container/heap" + + "github.com/hyperledger/burrow/storage" ) type MultiIterator struct { start []byte end []byte // Acts as priority queue based on sort order of current key in each iterator - iterators []KVIterator - iteratorOrder map[KVIterator]int + iterators []storage.KVIterator + iteratorOrder map[storage.KVIterator]int lessComp int } // MultiIterator iterates in order over a series o -func NewMultiIterator(reverse bool, iterators ...KVIterator) *MultiIterator { +func NewMultiIterator(reverse bool, iterators ...storage.KVIterator) *MultiIterator { // reuse backing array lessComp := -1 if reverse { @@ -23,7 +25,7 @@ func NewMultiIterator(reverse bool, iterators ...KVIterator) *MultiIterator { } mi := &MultiIterator{ iterators: iterators, - iteratorOrder: make(map[KVIterator]int), + iteratorOrder: make(map[storage.KVIterator]int), lessComp: lessComp, } mi.init() @@ -37,10 +39,10 @@ func (mi *MultiIterator) init() { if it.Valid() { validIterators = append(validIterators, it) start, end := it.Domain() - if i == 0 || CompareKeys(start, mi.start) == mi.lessComp { + if i == 0 || storage.CompareKeys(start, mi.start) == mi.lessComp { mi.start = start } - if i == 0 || CompareKeys(mi.end, end) == mi.lessComp { + if i == 0 || storage.CompareKeys(mi.end, end) == mi.lessComp { mi.end = end } } else { @@ -68,7 +70,7 @@ func (mi *MultiIterator) Swap(i, j int) { } func (mi *MultiIterator) Push(x interface{}) { - mi.iterators = append(mi.iterators, x.(KVIterator)) + mi.iterators = append(mi.iterators, x.(storage.KVIterator)) } func (mi *MultiIterator) Pop() interface{} { @@ -88,7 +90,7 @@ func (mi *MultiIterator) Valid() bool { func (mi *MultiIterator) Next() { // Always advance the lowest iterator - the same one we serve the KV pair from - it := heap.Pop(mi).(KVIterator) + it := heap.Pop(mi).(storage.KVIterator) it.Next() if it.Valid() { heap.Push(mi, it) @@ -103,7 +105,7 @@ func (mi *MultiIterator) Value() []byte { return mi.Peek().Value() } -func (mi *MultiIterator) Peek() KVIterator { +func (mi *MultiIterator) Peek() storage.KVIterator { return mi.iterators[0] } diff --git a/storage/multi_iterator_test.go b/forensics/multi_iterator_test.go similarity index 78% rename from storage/multi_iterator_test.go rename to forensics/multi_iterator_test.go index f054044a0..57f1f6a19 100644 --- a/storage/multi_iterator_test.go +++ b/forensics/multi_iterator_test.go @@ -1,6 +1,7 @@ -package storage +package forensics import ( + "sort" "testing" "github.com/stretchr/testify/assert" @@ -47,3 +48,19 @@ func TestDuplicateKeys(t *testing.T) { assert.Equal(t, []string{"dogs", "frogs", "bar", "zfoo"}, as, "duplicate keys should appear in iterator order") } + +func iteratorOver(kvp []KVPair, reverse ...bool) *ChannelIterator { + var sortable sort.Interface = KVPairs(kvp) + if len(reverse) > 0 && reverse[0] { + sortable = sort.Reverse(sortable) + } + sort.Stable(sortable) + ch := make(chan KVPair) + var start, end []byte + if len(kvp) > 0 { + start, end = kvp[0].Key, kvp[len(kvp)-1].Key + } + go sendKVPair(ch, kvp) + ci := NewChannelIterator(ch, start, end) + return ci +} diff --git a/forensics/replay.go b/forensics/replay.go index c9995c21e..b5de6bd83 100644 --- a/forensics/replay.go +++ b/forensics/replay.go @@ -16,7 +16,6 @@ import ( "github.com/hyperledger/burrow/execution/state" "github.com/hyperledger/burrow/genesis" "github.com/hyperledger/burrow/logging" - "github.com/hyperledger/burrow/storage" "github.com/hyperledger/burrow/txs" "github.com/pkg/errors" dbm "github.com/tendermint/tendermint/libs/db" @@ -45,17 +44,17 @@ func (recap *ReplayCapture) String() string { } func NewReplay(dbDir string, genesisDoc *genesis.GenesisDoc, logger *logging.Logger) *Replay { - //burrowDB := core.NewBurrowDB(dbDir) + // burrowDB := core.NewBurrowDB(dbDir) // Avoid writing through to underlying DB db := dbm.NewDB(core.BurrowDBName, dbm.GoLevelDBBackend, dbDir) - cacheDB := storage.NewCacheDB(db) + cacheDB := NewCacheDB(db) return &Replay{ - Explorer: bcm.NewBlockExplorer(dbm.LevelDBBackend, path.Join(dbDir, "data")), - db: db, - cacheDB: cacheDB, - blockchain: bcm.NewBlockchain(cacheDB, genesisDoc), - genesisDoc: genesisDoc, - logger: logger, + Explorer: bcm.NewBlockExplorer(dbm.LevelDBBackend, path.Join(dbDir, "data")), + db: db, + cacheDB: cacheDB, + blockchain: bcm.NewBlockchain(cacheDB, genesisDoc), + genesisDoc: genesisDoc, + logger: logger, } } diff --git a/forensics/replay_test.go b/forensics/replay_test.go index 9bf6341e4..c12d9aba4 100644 --- a/forensics/replay_test.go +++ b/forensics/replay_test.go @@ -35,8 +35,9 @@ import ( //const criticalBlock uint64 = 6 // const goodDir = "/home/silas/burrows/production-t9/dealspace/002" -const badDir = "/home/silas/burrows/production-t9/dealspace/001" +const badDir = "/home/silas/burrows/production-t9/dealspace/001" const criticalBlock uint64 = 38 + //const criticalBlock uint64 = 52 func TestState(t *testing.T) { diff --git a/storage/unique_iterator.go b/forensics/unique_iterator.go similarity index 80% rename from storage/unique_iterator.go rename to forensics/unique_iterator.go index b1449914f..281ebdbc9 100644 --- a/storage/unique_iterator.go +++ b/forensics/unique_iterator.go @@ -1,13 +1,17 @@ -package storage +package forensics -import "bytes" +import ( + "bytes" + + "github.com/hyperledger/burrow/storage" +) type uniqueIterator struct { - source KVIterator + source storage.KVIterator prevKey []byte } -func Uniq(source KVIterator) *uniqueIterator { +func Uniq(source storage.KVIterator) *uniqueIterator { return &uniqueIterator{ source: source, } diff --git a/storage/unique_iterator_test.go b/forensics/unique_iterator_test.go similarity index 94% rename from storage/unique_iterator_test.go rename to forensics/unique_iterator_test.go index bf82bccab..3db8300fa 100644 --- a/storage/unique_iterator_test.go +++ b/forensics/unique_iterator_test.go @@ -1,4 +1,4 @@ -package storage +package forensics import ( "testing" diff --git a/storage/util_test.go b/forensics/util_test.go similarity index 58% rename from storage/util_test.go rename to forensics/util_test.go index fba4ad3d1..ecb56b37a 100644 --- a/storage/util_test.go +++ b/forensics/util_test.go @@ -1,11 +1,12 @@ -package storage +package forensics import ( - "sort" "strings" "testing" + "github.com/hyperledger/burrow/storage" "github.com/stretchr/testify/assert" + dbm "github.com/tendermint/tendermint/libs/db" ) func sendKVPair(ch chan<- KVPair, kvs []KVPair) { @@ -15,7 +16,7 @@ func sendKVPair(ch chan<- KVPair, kvs []KVPair) { close(ch) } -func collectIterator(it KVIterator) KVPairs { +func collectIterator(it storage.KVIterator) KVPairs { var kvp []KVPair for it.Valid() { kvp = append(kvp, KVPair{it.Key(), it.Value()}) @@ -33,7 +34,7 @@ func kvPairs(kvs ...string) KVPairs { return kvp } -func assertIteratorSorted(t *testing.T, it KVIterator, reverse bool) { +func assertIteratorSorted(t *testing.T, it storage.KVIterator, reverse bool) { prev := "" for it.Valid() { strKey := string(it.Key()) @@ -52,22 +53,8 @@ func assertIteratorSorted(t *testing.T, it KVIterator, reverse bool) { } } -func iteratorOver(kvp []KVPair, reverse ...bool) *ChannelIterator { - var sortable sort.Interface = KVPairs(kvp) - if len(reverse) > 0 && reverse[0] { - sortable = sort.Reverse(sortable) - } - sort.Stable(sortable) - ch := make(chan KVPair) - var start, end []byte - if len(kvp) > 0 { - start, end = kvp[0].Key, kvp[len(kvp)-1].Key - } - go sendKVPair(ch, kvp) - ci := NewChannelIterator(ch, start, end) - return ci -} - -func bz(s string) []byte { - return []byte(s) +func checkItem(t *testing.T, itr dbm.Iterator, key []byte, value []byte) { + k, v := itr.Key(), itr.Value() + assert.Exactly(t, key, k) + assert.Exactly(t, value, v) } diff --git a/genesis/deterministic_genesis.go b/genesis/deterministic_genesis.go index 38b9137c2..cc231bead 100644 --- a/genesis/deterministic_genesis.go +++ b/genesis/deterministic_genesis.go @@ -21,14 +21,13 @@ func NewDeterministicGenesis(seed int64) *deterministicGenesis { } } -func (dg *deterministicGenesis) GenesisDoc(numAccounts int, randBalance bool, minBalance uint64, numValidators int, - randBonded bool, minBonded int64) (*GenesisDoc, []*acm.PrivateAccount, []*acm.PrivateAccount) { +func (dg *deterministicGenesis) GenesisDoc(numAccounts int, numValidators int) (*GenesisDoc, []*acm.PrivateAccount, []*acm.PrivateAccount) { accounts := make([]Account, numAccounts) privAccounts := make([]*acm.PrivateAccount, numAccounts) defaultPerms := permission.DefaultAccountPermissions for i := 0; i < numAccounts; i++ { - account, privAccount := dg.Account(randBalance, minBalance) + account, privAccount := dg.Account(9999999) acc := Account{ BasicAccount: BasicAccount{ Address: account.GetAddress(), @@ -69,7 +68,7 @@ func (dg *deterministicGenesis) GenesisDoc(numAccounts int, randBalance bool, mi } -func (dg *deterministicGenesis) Account(randBalance bool, minBalance uint64) (*acm.Account, *acm.PrivateAccount) { +func (dg *deterministicGenesis) Account(minBalance uint64) (*acm.Account, *acm.PrivateAccount) { privateKey, err := crypto.GeneratePrivateKey(dg.random, crypto.CurveTypeEd25519) if err != nil { panic(fmt.Errorf("could not generate private key deterministically")) @@ -87,8 +86,6 @@ func (dg *deterministicGenesis) Account(randBalance bool, minBalance uint64) (*a Balance: minBalance, Permissions: perms, } - if randBalance { - acc.Balance += uint64(dg.random.Int()) - } + acc.Balance += uint64(dg.random.Int()) return acc, privAccount.PrivateAccount() } diff --git a/genesis/genesis.go b/genesis/genesis.go index 6a15055a6..170b1248f 100644 --- a/genesis/genesis.go +++ b/genesis/genesis.go @@ -52,9 +52,8 @@ type Account struct { type Validator struct { BasicAccount - NodeAddress *crypto.Address `json:",omitempty" toml:",omitempty" yaml:",omitempty"` - Name string - UnbondTo []BasicAccount + Name string + UnbondTo []BasicAccount } //------------------------------------------------------------ @@ -76,7 +75,8 @@ type GenesisDoc struct { Accounts []Account Validators []Validator // memo - hash []byte + hash []byte + chainID string } func (genesisDoc *GenesisDoc) JSONString() string { @@ -113,7 +113,10 @@ func (genesisDoc *GenesisDoc) ShortHash() []byte { } func (genesisDoc *GenesisDoc) ChainID() string { - return fmt.Sprintf("%s-%X", genesisDoc.ChainName, genesisDoc.ShortHash()) + if genesisDoc.chainID == "" { + genesisDoc.chainID = fmt.Sprintf("%s-%X", genesisDoc.ChainName, genesisDoc.ShortHash()) + } + return genesisDoc.chainID } //------------------------------------------------------------ @@ -193,9 +196,8 @@ func (gv *Validator) Clone() Validator { PublicKey: gv.PublicKey, Amount: gv.Amount, }, - Name: gv.Name, - UnbondTo: unbondToClone, - NodeAddress: gv.NodeAddress, + Name: gv.Name, + UnbondTo: unbondToClone, } } diff --git a/genesis/spec/genesis_spec.go b/genesis/spec/genesis_spec.go index a925b1e36..db13d1928 100644 --- a/genesis/spec/genesis_spec.go +++ b/genesis/spec/genesis_spec.go @@ -47,7 +47,7 @@ func (gs *GenesisSpec) RealiseKeys(keyClient keys.KeyClient) error { } // Produce a fully realised GenesisDoc from a template GenesisDoc that may omit values -func (gs *GenesisSpec) GenesisDoc(keyClient keys.KeyClient, generateNodeKeys bool) (*genesis.GenesisDoc, error) { +func (gs *GenesisSpec) GenesisDoc(keyClient keys.KeyClient) (*genesis.GenesisDoc, error) { genesisDoc := new(genesis.GenesisDoc) if gs.GenesisTime == nil { genesisDoc.GenesisTime = time.Now() @@ -94,7 +94,7 @@ func (gs *GenesisSpec) GenesisDoc(keyClient keys.KeyClient, generateNodeKeys boo if templateAccount.Balances().HasPower() { // Note this does not modify the input template templateAccount.Address = &account.Address - validator, err := templateAccount.Validator(keyClient, i, generateNodeKeys) + validator, err := templateAccount.Validator(keyClient, i) if err != nil { return nil, fmt.Errorf("could not create Validator from template: %v", err) } diff --git a/genesis/spec/genesis_spec_test.go b/genesis/spec/genesis_spec_test.go index 1d52df39a..f40d93b53 100644 --- a/genesis/spec/genesis_spec_test.go +++ b/genesis/spec/genesis_spec_test.go @@ -22,7 +22,7 @@ func TestGenesisSpec_GenesisDoc(t *testing.T) { }}, } - genesisDoc, err := genesisSpec.GenesisDoc(keyClient, false) + genesisDoc, err := genesisSpec.GenesisDoc(keyClient) require.NoError(t, err) require.Len(t, genesisDoc.Accounts, 1) // Should create validator @@ -52,7 +52,7 @@ func TestGenesisSpec_GenesisDoc(t *testing.T) { }}, } - genesisDoc, err = genesisSpec.GenesisDoc(keyClient, false) + genesisDoc, err = genesisSpec.GenesisDoc(keyClient) require.NoError(t, err) require.Len(t, genesisDoc.Accounts, 2) @@ -67,7 +67,7 @@ func TestGenesisSpec_GenesisDoc(t *testing.T) { // Try an empty spec genesisSpec = GenesisSpec{} - genesisDoc, err = genesisSpec.GenesisDoc(keyClient, false) + genesisDoc, err = genesisSpec.GenesisDoc(keyClient) require.NoError(t, err) // Similar assersions to first case - should generate our default single identity chain diff --git a/genesis/spec/presets.go b/genesis/spec/presets.go index 39d9b0ca5..16774d030 100644 --- a/genesis/spec/presets.go +++ b/genesis/spec/presets.go @@ -167,17 +167,3 @@ func mergeStrings(as, bs []string) []string { sort.Strings(strs) return strs } - -func addUint64Pointers(a, b *uint64) *uint64 { - if a == nil && b == nil { - return nil - } - amt := uint64(0) - if a != nil { - amt += *a - } - if b != nil { - amt += *b - } - return &amt -} diff --git a/genesis/spec/presets_test.go b/genesis/spec/presets_test.go index 1c11015f9..155fb706b 100644 --- a/genesis/spec/presets_test.go +++ b/genesis/spec/presets_test.go @@ -13,7 +13,7 @@ import ( func TestMergeGenesisSpecAccounts(t *testing.T) { keyClient := mock.NewKeyClient() gs := MergeGenesisSpecs(FullAccount("0"), ParticipantAccount("1"), ParticipantAccount("2")) - gd, err := gs.GenesisDoc(keyClient, false) + gd, err := gs.GenesisDoc(keyClient) require.NoError(t, err) assert.Len(t, gd.Validators, 1) assert.Len(t, gd.Accounts, 3) diff --git a/genesis/spec/spec.pb.go b/genesis/spec/spec.pb.go index 378b441ca..e5dc717d4 100644 --- a/genesis/spec/spec.pb.go +++ b/genesis/spec/spec.pb.go @@ -32,12 +32,11 @@ const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package type TemplateAccount struct { Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"` Address *github_com_hyperledger_burrow_crypto.Address `protobuf:"bytes,2,opt,name=Address,proto3,customtype=github.com/hyperledger/burrow/crypto.Address" json:",omitempty" toml:",omitempty"` - NodeAddress *github_com_hyperledger_burrow_crypto.Address `protobuf:"bytes,3,opt,name=NodeAddress,proto3,customtype=github.com/hyperledger/burrow/crypto.Address" json:",omitempty" toml:",omitempty"` - PublicKey *crypto.PublicKey `protobuf:"bytes,4,opt,name=PublicKey,proto3" json:",omitempty" toml:",omitempty"` - Amounts []balance.Balance `protobuf:"bytes,5,rep,name=Amounts,proto3" json:",omitempty" toml:",omitempty"` - Permissions []string `protobuf:"bytes,6,rep,name=Permissions,proto3" json:",omitempty" toml:",omitempty"` - Roles []string `protobuf:"bytes,7,rep,name=Roles,proto3" json:",omitempty" toml:",omitempty"` - Code *github_com_hyperledger_burrow_acm.Bytecode `protobuf:"bytes,8,opt,name=Code,proto3,customtype=github.com/hyperledger/burrow/acm.Bytecode" json:"Code,omitempty"` + PublicKey *crypto.PublicKey `protobuf:"bytes,3,opt,name=PublicKey,proto3" json:",omitempty" toml:",omitempty"` + Amounts []balance.Balance `protobuf:"bytes,4,rep,name=Amounts,proto3" json:",omitempty" toml:",omitempty"` + Permissions []string `protobuf:"bytes,5,rep,name=Permissions,proto3" json:",omitempty" toml:",omitempty"` + Roles []string `protobuf:"bytes,6,rep,name=Roles,proto3" json:",omitempty" toml:",omitempty"` + Code *github_com_hyperledger_burrow_acm.Bytecode `protobuf:"bytes,7,opt,name=Code,proto3,customtype=github.com/hyperledger/burrow/acm.Bytecode" json:"Code,omitempty"` XXX_unrecognized []byte `json:"-"` } @@ -121,33 +120,32 @@ func init() { proto.RegisterFile("spec.proto", fileDescriptor_423806180556987f) func init() { golang_proto.RegisterFile("spec.proto", fileDescriptor_423806180556987f) } var fileDescriptor_423806180556987f = []byte{ - // 411 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x53, 0x31, 0x6f, 0xd4, 0x30, - 0x14, 0x3e, 0x73, 0x77, 0xbd, 0x9e, 0xaf, 0x08, 0xea, 0x29, 0xea, 0x10, 0x47, 0xc7, 0x40, 0x84, - 0x4a, 0x22, 0x1d, 0x13, 0x9d, 0xb8, 0x20, 0x58, 0x90, 0xaa, 0x2a, 0xed, 0xc4, 0x96, 0x38, 0x8f, - 0x34, 0x52, 0x1c, 0x47, 0xb6, 0x23, 0x94, 0xbf, 0xc0, 0xc4, 0xc8, 0xdc, 0x5f, 0xc2, 0x98, 0x91, - 0xb9, 0x43, 0x84, 0xae, 0x1b, 0x23, 0xbf, 0x00, 0x9d, 0x73, 0xa1, 0x37, 0x41, 0x96, 0x4e, 0x7e, - 0x9f, 0x9f, 0xbe, 0xef, 0x7b, 0x7a, 0x9f, 0x8d, 0xb1, 0x2a, 0x81, 0x79, 0xa5, 0x14, 0x5a, 0x90, - 0xc9, 0xb6, 0x3e, 0x79, 0x99, 0x66, 0xfa, 0xba, 0x8a, 0x3d, 0x26, 0xb8, 0x9f, 0x8a, 0x54, 0xf8, - 0xa6, 0x19, 0x57, 0x9f, 0x0c, 0x32, 0xc0, 0x54, 0x1d, 0xe9, 0xe4, 0x88, 0xc9, 0xba, 0xd4, 0x3d, - 0x7a, 0x1c, 0x47, 0x79, 0x54, 0x30, 0xe8, 0xe0, 0xf2, 0xcb, 0x14, 0x3f, 0xb9, 0x02, 0x5e, 0xe6, - 0x91, 0x86, 0x35, 0x63, 0xa2, 0x2a, 0x34, 0x21, 0x78, 0x72, 0x1e, 0x71, 0xb0, 0x90, 0x83, 0xdc, - 0x79, 0x68, 0x6a, 0xc2, 0xf1, 0x6c, 0x9d, 0x24, 0x12, 0x94, 0xb2, 0x1e, 0x39, 0xc8, 0x3d, 0x0a, - 0x2e, 0x6f, 0x5b, 0x7a, 0xba, 0x37, 0xc8, 0x75, 0x5d, 0x82, 0xcc, 0x21, 0x49, 0x41, 0xfa, 0x71, - 0x25, 0xa5, 0xf8, 0xec, 0xef, 0x7c, 0x77, 0xbc, 0x5f, 0x2d, 0xc5, 0xa7, 0x82, 0x67, 0x1a, 0x78, - 0xa9, 0xeb, 0xdf, 0x2d, 0x3d, 0xd6, 0x82, 0xe7, 0x67, 0xcb, 0xfb, 0xbb, 0x65, 0xd8, 0x7b, 0x90, - 0x0a, 0x2f, 0xce, 0x45, 0x02, 0xbd, 0xe5, 0xf8, 0xe1, 0x2c, 0xf7, 0x7d, 0xc8, 0x15, 0x9e, 0x5f, - 0x54, 0x71, 0x9e, 0xb1, 0x0f, 0x50, 0x5b, 0x13, 0x07, 0xb9, 0x8b, 0xd5, 0xb1, 0xb7, 0xd3, 0xfc, - 0xdb, 0x08, 0x9e, 0x0d, 0xd1, 0xbd, 0x17, 0x22, 0x97, 0x78, 0xb6, 0xe6, 0xdb, 0xcd, 0x2a, 0x6b, - 0xea, 0x8c, 0xdd, 0xc5, 0xea, 0xa9, 0xd7, 0x87, 0x10, 0x74, 0x67, 0xf0, 0xbc, 0x69, 0xe9, 0x68, - 0xd8, 0x86, 0x3a, 0x25, 0xf2, 0x0e, 0x2f, 0x2e, 0x40, 0xf2, 0x4c, 0xa9, 0x4c, 0x14, 0xca, 0x3a, - 0x70, 0xc6, 0xee, 0x7c, 0xd8, 0x64, 0xfb, 0x3c, 0xf2, 0x1a, 0x4f, 0x43, 0x91, 0x83, 0xb2, 0x66, - 0xc3, 0x05, 0x3a, 0x06, 0x79, 0x8f, 0x27, 0x6f, 0x45, 0x02, 0xd6, 0xa1, 0x09, 0x67, 0xd5, 0xb4, - 0x14, 0xdd, 0xb6, 0xf4, 0xc5, 0xbf, 0x03, 0x8a, 0x18, 0xf7, 0x82, 0x5a, 0x03, 0x13, 0x09, 0x84, - 0x86, 0x7f, 0x76, 0xf8, 0xf5, 0x86, 0x8e, 0xbe, 0xdd, 0xd0, 0x51, 0xf0, 0xa6, 0xd9, 0xd8, 0xe8, - 0xc7, 0xc6, 0x46, 0x3f, 0x37, 0x36, 0xfa, 0x7e, 0x67, 0xa3, 0xe6, 0xce, 0x46, 0x1f, 0xff, 0xa3, - 0x98, 0x42, 0x01, 0x2a, 0x53, 0xfe, 0xf6, 0x6b, 0xc4, 0x07, 0xe6, 0x55, 0xbf, 0xfa, 0x13, 0x00, - 0x00, 0xff, 0xff, 0xcf, 0x67, 0x15, 0x5d, 0x35, 0x03, 0x00, 0x00, + // 396 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0x31, 0x8f, 0xd3, 0x30, + 0x14, 0xc7, 0x6b, 0x9a, 0xbb, 0x52, 0xf7, 0x10, 0x9c, 0xa7, 0xe8, 0x86, 0x38, 0x2a, 0x03, 0x11, + 0x3a, 0x12, 0xa9, 0x4c, 0xdc, 0x44, 0x83, 0x60, 0x41, 0x42, 0xa7, 0xdc, 0x4d, 0x6c, 0x89, 0xf3, + 0xc8, 0x45, 0x8a, 0xe3, 0xc8, 0x76, 0x84, 0xf2, 0x2d, 0x90, 0x58, 0x98, 0xef, 0x93, 0x30, 0x66, + 0x64, 0xee, 0x10, 0xa1, 0x76, 0x63, 0xe4, 0x13, 0xa0, 0x3a, 0x2d, 0xed, 0x04, 0x99, 0xfc, 0xfe, + 0x7e, 0xfa, 0xff, 0xde, 0xb3, 0xdf, 0xc3, 0x58, 0x55, 0xc0, 0xfc, 0x4a, 0x0a, 0x2d, 0x88, 0xb5, + 0x8d, 0x2f, 0x5e, 0x64, 0xb9, 0xbe, 0xab, 0x13, 0x9f, 0x09, 0x1e, 0x64, 0x22, 0x13, 0x81, 0x49, + 0x26, 0xf5, 0x27, 0xa3, 0x8c, 0x30, 0x51, 0x6f, 0xba, 0x38, 0x63, 0xb2, 0xa9, 0xf4, 0x5e, 0x3d, + 0x4a, 0xe2, 0x22, 0x2e, 0x19, 0xf4, 0x72, 0xfe, 0xd5, 0xc2, 0x8f, 0x6f, 0x81, 0x57, 0x45, 0xac, + 0x61, 0xc9, 0x98, 0xa8, 0x4b, 0x4d, 0x08, 0xb6, 0x3e, 0xc4, 0x1c, 0x6c, 0xe4, 0x22, 0x6f, 0x1a, + 0x99, 0x98, 0x70, 0x3c, 0x59, 0xa6, 0xa9, 0x04, 0xa5, 0xec, 0x07, 0x2e, 0xf2, 0xce, 0xc2, 0x9b, + 0x55, 0x47, 0x2f, 0x8f, 0x1a, 0xb9, 0x6b, 0x2a, 0x90, 0x05, 0xa4, 0x19, 0xc8, 0x20, 0xa9, 0xa5, + 0x14, 0x9f, 0x83, 0x5d, 0xdd, 0x9d, 0xef, 0x57, 0x47, 0xf1, 0xa5, 0xe0, 0xb9, 0x06, 0x5e, 0xe9, + 0xe6, 0x77, 0x47, 0xcf, 0xb5, 0xe0, 0xc5, 0xd5, 0xfc, 0x70, 0x37, 0x8f, 0xf6, 0x35, 0xc8, 0x2d, + 0x9e, 0x5e, 0xd7, 0x49, 0x91, 0xb3, 0xf7, 0xd0, 0xd8, 0x63, 0x17, 0x79, 0xb3, 0xc5, 0xb9, 0xbf, + 0xe3, 0xfd, 0x4d, 0x84, 0x4f, 0x87, 0x30, 0x0f, 0x20, 0x72, 0x83, 0x27, 0x4b, 0xbe, 0x7d, 0xa2, + 0xb2, 0x2d, 0x77, 0xec, 0xcd, 0x16, 0x4f, 0xfc, 0xfd, 0x6f, 0x84, 0xfd, 0x19, 0x3e, 0x6b, 0x3b, + 0x3a, 0x1a, 0xd6, 0x6a, 0x4f, 0x22, 0x6f, 0xf1, 0xec, 0x1a, 0x24, 0xcf, 0x95, 0xca, 0x45, 0xa9, + 0xec, 0x13, 0x77, 0xec, 0x4d, 0x87, 0x75, 0x76, 0xec, 0x23, 0xaf, 0xf0, 0x49, 0x24, 0x0a, 0x50, + 0xf6, 0xe9, 0x70, 0x40, 0xef, 0x20, 0xef, 0xb0, 0xf5, 0x46, 0xa4, 0x60, 0x4f, 0xcc, 0x60, 0x16, + 0x6d, 0x47, 0xd1, 0xaa, 0xa3, 0xcf, 0xff, 0x3d, 0x9c, 0x98, 0x71, 0x3f, 0x6c, 0x34, 0x30, 0x91, + 0x42, 0x64, 0xfc, 0x57, 0x0f, 0xbf, 0xdc, 0xd3, 0xd1, 0xb7, 0x7b, 0x3a, 0x0a, 0x5f, 0xb7, 0x6b, + 0x07, 0xfd, 0x58, 0x3b, 0xe8, 0xe7, 0xda, 0x41, 0xdf, 0x37, 0x0e, 0x6a, 0x37, 0x0e, 0xfa, 0xf8, + 0x1f, 0x62, 0x06, 0x25, 0xa8, 0x5c, 0x05, 0xdb, 0x1d, 0x4d, 0x4e, 0xcd, 0x7a, 0xbd, 0xfc, 0x13, + 0x00, 0x00, 0xff, 0xff, 0x3b, 0xf1, 0x47, 0x6d, 0xbe, 0x02, 0x00, 0x00, } func (m *TemplateAccount) Marshal() (dAtA []byte, err error) { @@ -181,29 +179,19 @@ func (m *TemplateAccount) MarshalTo(dAtA []byte) (int, error) { } i += n1 } - if m.NodeAddress != nil { - dAtA[i] = 0x1a - i++ - i = encodeVarintSpec(dAtA, i, uint64(m.NodeAddress.Size())) - n2, err := m.NodeAddress.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err - } - i += n2 - } if m.PublicKey != nil { - dAtA[i] = 0x22 + dAtA[i] = 0x1a i++ i = encodeVarintSpec(dAtA, i, uint64(m.PublicKey.Size())) - n3, err := m.PublicKey.MarshalTo(dAtA[i:]) + n2, err := m.PublicKey.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n3 + i += n2 } if len(m.Amounts) > 0 { for _, msg := range m.Amounts { - dAtA[i] = 0x2a + dAtA[i] = 0x22 i++ i = encodeVarintSpec(dAtA, i, uint64(msg.Size())) n, err := msg.MarshalTo(dAtA[i:]) @@ -215,7 +203,7 @@ func (m *TemplateAccount) MarshalTo(dAtA []byte) (int, error) { } if len(m.Permissions) > 0 { for _, s := range m.Permissions { - dAtA[i] = 0x32 + dAtA[i] = 0x2a i++ l = len(s) for l >= 1<<7 { @@ -230,7 +218,7 @@ func (m *TemplateAccount) MarshalTo(dAtA []byte) (int, error) { } if len(m.Roles) > 0 { for _, s := range m.Roles { - dAtA[i] = 0x3a + dAtA[i] = 0x32 i++ l = len(s) for l >= 1<<7 { @@ -244,14 +232,14 @@ func (m *TemplateAccount) MarshalTo(dAtA []byte) (int, error) { } } if m.Code != nil { - dAtA[i] = 0x42 + dAtA[i] = 0x3a i++ i = encodeVarintSpec(dAtA, i, uint64(m.Code.Size())) - n4, err := m.Code.MarshalTo(dAtA[i:]) + n3, err := m.Code.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n4 + i += n3 } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) @@ -282,10 +270,6 @@ func (m *TemplateAccount) Size() (n int) { l = m.Address.Size() n += 1 + l + sovSpec(uint64(l)) } - if m.NodeAddress != nil { - l = m.NodeAddress.Size() - n += 1 + l + sovSpec(uint64(l)) - } if m.PublicKey != nil { l = m.PublicKey.Size() n += 1 + l + sovSpec(uint64(l)) @@ -428,41 +412,6 @@ func (m *TemplateAccount) Unmarshal(dAtA []byte) error { } iNdEx = postIndex case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field NodeAddress", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSpec - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthSpec - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthSpec - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var v github_com_hyperledger_burrow_crypto.Address - m.NodeAddress = &v - if err := m.NodeAddress.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field PublicKey", wireType) } @@ -498,7 +447,7 @@ func (m *TemplateAccount) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 5: + case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Amounts", wireType) } @@ -532,7 +481,7 @@ func (m *TemplateAccount) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 6: + case 5: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Permissions", wireType) } @@ -564,7 +513,7 @@ func (m *TemplateAccount) Unmarshal(dAtA []byte) error { } m.Permissions = append(m.Permissions, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex - case 7: + case 6: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Roles", wireType) } @@ -596,7 +545,7 @@ func (m *TemplateAccount) Unmarshal(dAtA []byte) error { } m.Roles = append(m.Roles, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex - case 8: + case 7: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Code", wireType) } diff --git a/genesis/spec/template_account.go b/genesis/spec/template_account.go index 6848d4ca6..7ac6804cf 100644 --- a/genesis/spec/template_account.go +++ b/genesis/spec/template_account.go @@ -10,21 +10,13 @@ import ( "github.com/hyperledger/burrow/permission" ) -func (ta TemplateAccount) Validator(keyClient keys.KeyClient, index int, generateNodeKeys bool) (*genesis.Validator, error) { +func (ta TemplateAccount) Validator(keyClient keys.KeyClient, index int) (*genesis.Validator, error) { var err error gv := new(genesis.Validator) gv.PublicKey, gv.Address, err = ta.RealisePublicKeyAndAddress(keyClient) if err != nil { return nil, err } - if generateNodeKeys && ta.NodeAddress == nil { - // If neither PublicKey or Address set then generate a new one - address, err := keyClient.Generate("nodekey-"+ta.Name, crypto.CurveTypeEd25519) - if err != nil { - return nil, err - } - ta.NodeAddress = &address - } gv.Amount = ta.Balances().GetPower(DefaultPower) if ta.Name == "" { gv.Name = accountNameFromIndex(index) @@ -37,7 +29,6 @@ func (ta TemplateAccount) Validator(keyClient keys.KeyClient, index int, generat PublicKey: gv.PublicKey, Amount: gv.Amount, }} - gv.NodeAddress = ta.NodeAddress return gv, nil } diff --git a/go.mod b/go.mod index 320a33d04..1792aba69 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,8 @@ module github.com/hyperledger/burrow go 1.12 +replace github.com/go-interpreter/wagon v0.0.0 => github.com/perlin-network/wagon v0.3.1-0.20180825141017-f8cb99b55a39 + require ( github.com/BurntSushi/toml v0.3.1 github.com/OneOfOne/xxhash v1.2.5 @@ -36,6 +38,7 @@ require ( github.com/magiconair/properties v1.8.0 github.com/mattn/go-sqlite3 v1.10.0 github.com/monax/relic v2.0.0+incompatible + github.com/perlin-network/life v0.0.0-20190521143330-57f3819c2df0 github.com/pkg/errors v0.8.1 github.com/prometheus/client_golang v0.9.2 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 @@ -62,4 +65,5 @@ require ( google.golang.org/grpc v1.20.1 gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect gopkg.in/yaml.v2 v2.2.2 + honnef.co/go/tools v0.0.0-20190614002413-cb51c254f01b // indirect ) diff --git a/go.sum b/go.sum index e5b763c27..deaaddd66 100644 --- a/go.sum +++ b/go.sum @@ -71,6 +71,7 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pO github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= @@ -100,6 +101,9 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGi github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= @@ -122,6 +126,10 @@ github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/perlin-network/life v0.0.0-20190521143330-57f3819c2df0 h1:fP9xTEHvfuArvWXQhRDYHSBNX/3ZaAfFKlxzpZtUsqs= +github.com/perlin-network/life v0.0.0-20190521143330-57f3819c2df0/go.mod h1:z/EH0mO9zbeuTT5NX4u2VqVSG8y2vDQXz6iDKxikW2I= +github.com/perlin-network/wagon v0.3.1-0.20180825141017-f8cb99b55a39 h1:CYHXy6CWxxL7ugjvCbTELOm2j5iRLEWGPl3AQYvretw= +github.com/perlin-network/wagon v0.3.1-0.20180825141017-f8cb99b55a39/go.mod h1:zHOMvbitcZek8oshsMO5VpyBjWjV9X8cn8WTZwdebpM= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -136,6 +144,7 @@ github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nL github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= @@ -169,6 +178,8 @@ github.com/tendermint/tendermint v0.31.5/go.mod h1:ymcPyWblXCplCPQjbOYbrF1fWnpsl github.com/tmthrgd/go-hex v0.0.0-20190303111820-0bdcb15db631 h1:IlK6taZBmMKDcGfMqIlD4la5BlekNrrLsdtCMSn6aJI= github.com/tmthrgd/go-hex v0.0.0-20190303111820-0bdcb15db631/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= +github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= @@ -181,9 +192,11 @@ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1: golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f h1:R423Cnkcp5JABoeemiGEPlt9tHXFfw5kvc0yqlxRPWo= golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -193,6 +206,7 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -208,6 +222,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190530171427-2b03ca6e44eb h1:mnQlcVx8Qq8L70HV0DxUGuiuAtiEHTwF1gYJE/EL9nU= +golang.org/x/tools v0.0.0-20190530171427-2b03ca6e44eb/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= @@ -218,6 +234,8 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= @@ -226,3 +244,5 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190614002413-cb51c254f01b h1:SWAO5HXhUnouVG7YwFyCqej4vr94EiYYu4O7YRXsxBU= +honnef.co/go/tools v0.0.0-20190614002413-cb51c254f01b/go.mod h1:JlmFZigtG9vBVR3QGIQ9g/Usz4BzH+Xm6Z8iHQWRYUw= diff --git a/integration/core/kernel_test.go b/integration/core/kernel_test.go index 9438a964c..d80abfd9c 100644 --- a/integration/core/kernel_test.go +++ b/integration/core/kernel_test.go @@ -48,7 +48,7 @@ func TestKernelNoConsensus(t *testing.T) { func testKernel(t *testing.T, opts ...func(*config.BurrowConfig)) { t.Run(fmt.Sprintf("Group"), func(t *testing.T) { t.Parallel() - genesisDoc, privateAccounts, privateValidators := genesis.NewDeterministicGenesis(123).GenesisDoc(1, true, 1000, 1, true, 1000) + genesisDoc, privateAccounts, privateValidators := genesis.NewDeterministicGenesis(123).GenesisDoc(1, 1) t.Run("BootThenShutdown", func(t *testing.T) { conf, cleanup := integration.NewTestConfig(genesisDoc, opts...) defer cleanup() diff --git a/integration/rpctest/helpers.go b/integration/rpctest/helpers.go index 3aab10ecd..cdfa99def 100644 --- a/integration/rpctest/helpers.go +++ b/integration/rpctest/helpers.go @@ -25,8 +25,6 @@ import ( // so... (I didn't say it had to make sense): const UpsieDownsieCallCount = 1 + (34 - 17) + 1 + (34 - 23) -var i = UpsieDownsieCallCount - var PrivateAccounts = integration.MakePrivateAccounts(10) // make keys var GenesisDoc = integration.TestGenesisDoc(PrivateAccounts) diff --git a/keys/core.go b/keys/core.go index aaaa92071..d4176c4b0 100644 --- a/keys/core.go +++ b/keys/core.go @@ -39,7 +39,7 @@ func returnNamesDir(dir string) (string, error) { func writeKey(keyDir string, addr, keyJson []byte) ([]byte, error) { dir, err := returnDataDir(keyDir) if err != nil { - return nil, fmt.Errorf("Failed to get keys dir: %v", err) + return nil, fmt.Errorf("failed to get keys dir: %v", err) } if err := WriteKeyFile(addr, dir, keyJson); err != nil { return nil, err @@ -60,7 +60,7 @@ func coreNameAdd(keysDir, name, addr string) error { return err } if _, err := os.Stat(path.Join(dataDir, addr+".json")); err != nil { - return fmt.Errorf("Unknown key %s", addr) + return fmt.Errorf("unknown key %s", addr) } return ioutil.WriteFile(path.Join(namesDir, name), []byte(addr), 0600) } @@ -85,22 +85,6 @@ func coreNameList(keysDir string) (map[string]string, error) { return names, nil } -func coreAddrList(keysDir string) (map[int]string, error) { - dir, err := returnDataDir(keysDir) - if err != nil { - return nil, err - } - addrs := make(map[int]string) - fs, err := ioutil.ReadDir(dir) - if err != nil { - return nil, err - } - for i := 0; i < len(fs); i++ { - addrs[i] = fs[i].Name() - } - return addrs, nil -} - func coreNameRm(keysDir string, name string) error { dir, err := returnNamesDir(keysDir) if err != nil { diff --git a/keys/key_client.go b/keys/key_client.go index 36c48af28..2414cf4e7 100644 --- a/keys/key_client.go +++ b/keys/key_client.go @@ -56,7 +56,7 @@ type remoteKeyClient struct { } func (l *localKeyClient) Sign(signAddress crypto.Address, message []byte) (*crypto.Signature, error) { - resp, err := l.ks.Sign(nil, &SignRequest{Address: signAddress.String(), Message: message}) + resp, err := l.ks.Sign(context.Background(), &SignRequest{Address: signAddress.String(), Message: message}) if err != nil { return nil, err } @@ -64,7 +64,7 @@ func (l *localKeyClient) Sign(signAddress crypto.Address, message []byte) (*cryp } func (l *localKeyClient) PublicKey(address crypto.Address) (publicKey crypto.PublicKey, err error) { - resp, err := l.ks.PublicKey(nil, &PubRequest{Address: address.String()}) + resp, err := l.ks.PublicKey(context.Background(), &PubRequest{Address: address.String()}) if err != nil { return crypto.PublicKey{}, err } @@ -77,7 +77,7 @@ func (l *localKeyClient) PublicKey(address crypto.Address) (publicKey crypto.Pub // Generate requests that a key be generate within the keys instance and returns the address func (l *localKeyClient) Generate(keyName string, curveType crypto.CurveType) (keyAddress crypto.Address, err error) { - resp, err := l.ks.GenerateKey(nil, &GenRequest{KeyName: keyName, CurveType: curveType.String()}) + resp, err := l.ks.GenerateKey(context.Background(), &GenRequest{KeyName: keyName, CurveType: curveType.String()}) if err != nil { return crypto.Address{}, err } diff --git a/keys/key_store.go b/keys/key_store.go index 86ae353a8..e782bd8d7 100644 --- a/keys/key_store.go +++ b/keys/key_store.go @@ -13,8 +13,7 @@ import ( "sync" "github.com/hyperledger/burrow/crypto" - "github.com/hyperledger/burrow/logging" - hex "github.com/tmthrgd/go-hex" + "github.com/tmthrgd/go-hex" "golang.org/x/crypto/scrypt" ) @@ -114,7 +113,6 @@ type KeyStore struct { sync.Mutex AllowBadFilePermissions bool keysDirPath string - logger *logging.Logger } func (ks *KeyStore) Gen(passphrase string, curveType crypto.CurveType) (key *Key, err error) { diff --git a/keys/server.go b/keys/server.go index cedaa5d60..975d58244 100644 --- a/keys/server.go +++ b/keys/server.go @@ -151,7 +151,7 @@ func (k *KeyStore) Hash(ctx context.Context, in *HashRequest) (*HashResponse, er hasher = sha256.New() // case "sha3": default: - return nil, fmt.Errorf("Unknown hash type %v", in.GetHashtype()) + return nil, fmt.Errorf("unknown hash type %v", in.GetHashtype()) } hasher.Write(in.GetMessage()) diff --git a/logging/lifecycle/lifecycle.go b/logging/lifecycle/lifecycle.go index 3ba9e1d25..d9eb037c2 100644 --- a/logging/lifecycle/lifecycle.go +++ b/logging/lifecycle/lifecycle.go @@ -58,13 +58,13 @@ func NewLoggerFromLoggingConfig(loggingConfig *logconfig.LoggingConfig) (*loggin // Hot swap logging config by replacing output loggers of passed InfoTraceLogger // with those built from loggingConfig -func SwapOutputLoggersFromLoggingConfig(logger *logging.Logger, loggingConfig *logconfig.LoggingConfig) (error, channels.Channel) { +func SwapOutputLoggersFromLoggingConfig(logger *logging.Logger, loggingConfig *logconfig.LoggingConfig) (channels.Channel, error) { outputLogger, errCh, err := loggerFromLoggingConfig(loggingConfig) if err != nil { - return err, channels.NewDeadChannel() + return channels.NewDeadChannel(), err } logger.SwapOutput(outputLogger) - return nil, errCh + return errCh, nil } func NewStdErrLogger() (*logging.Logger, error) { diff --git a/logging/logconfig/sinks.go b/logging/logconfig/sinks.go index 8cef644e2..2d7de7c91 100644 --- a/logging/logconfig/sinks.go +++ b/logging/logconfig/sinks.go @@ -74,7 +74,7 @@ func (mode filterMode) Exclude() bool { // The predicate should evaluate true if at least one of the key value predicates matches func (mode filterMode) MatchAny() bool { - return !mode.MatchAny() + return !mode.MatchAll() } // Sink configuration types diff --git a/logging/logger.go b/logging/logger.go index e1ac1d288..a88b8499a 100644 --- a/logging/logger.go +++ b/logging/logger.go @@ -17,6 +17,7 @@ package logging import ( "github.com/go-kit/kit/log" "github.com/hyperledger/burrow/logging/structure" + "github.com/hyperledger/burrow/util/slice" ) // InfoTraceLogger maintains provides two logging 'channels' that are interlaced @@ -149,6 +150,6 @@ func (l *Logger) WithScope(scopeName string) *Logger { // Record a structured log line with a message func Msg(logger log.Logger, message string, keyvals ...interface{}) error { - prepended := structure.CopyPrepend(keyvals, structure.MessageKey, message) + prepended := slice.CopyPrepend(keyvals, structure.MessageKey, message) return logger.Log(prepended...) } diff --git a/logging/loggers/burrow_format_logger.go b/logging/loggers/burrow_format_logger.go index 5f3c21e07..cf02702fd 100644 --- a/logging/loggers/burrow_format_logger.go +++ b/logging/loggers/burrow_format_logger.go @@ -16,13 +16,12 @@ package loggers import ( "fmt" - "time" - "sync" + "time" "github.com/go-kit/kit/log" "github.com/hyperledger/burrow/logging/structure" - hex "github.com/tmthrgd/go-hex" + "github.com/tmthrgd/go-hex" ) // Logger that implements some formatting conventions for burrow and burrow-client @@ -49,12 +48,12 @@ func (bfl *burrowFormatLogger) Log(keyvals ...interface{}) error { func(key interface{}, value interface{}) (interface{}, interface{}) { switch v := value.(type) { case string: + case time.Time: + value = v.Format(time.RFC3339Nano) case fmt.Stringer: value = v.String() case []byte: value = hex.EncodeUpperToString(v) - case time.Time: - value = v.Format(time.RFC3339Nano) } return structure.StringifyKey(key), value }) diff --git a/logging/loggers/stream_logger.go b/logging/loggers/stream_logger.go index 644f239ad..70ba74b57 100644 --- a/logging/loggers/stream_logger.go +++ b/logging/loggers/stream_logger.go @@ -17,10 +17,6 @@ const ( defaultFormatName = TerminalFormat ) -const ( - newline = '\n' -) - type Syncable interface { Sync() error } diff --git a/logging/loggers/stream_logger_test.go b/logging/loggers/stream_logger_test.go index 474228384..7ce9bd0b4 100644 --- a/logging/loggers/stream_logger_test.go +++ b/logging/loggers/stream_logger_test.go @@ -19,7 +19,7 @@ func TestNewStreamLogger(t *testing.T) { err = structure.Sync(logger) require.NoError(t, err) - assert.Equal(t, "oh=my\n", string(buf.Bytes())) + assert.Equal(t, "oh=my\n", buf.String()) } func TestNewTemplateLogger(t *testing.T) { diff --git a/logging/structure/structure.go b/logging/structure/structure.go index 2b47f2690..f9e196ec3 100644 --- a/logging/structure/structure.go +++ b/logging/structure/structure.go @@ -237,19 +237,6 @@ func DeleteAt(slice []interface{}, i int) []interface{} { return Delete(slice, i, 1) } -// Prepend elements to slice in the order they appear -func CopyPrepend(slice []interface{}, elements ...interface{}) []interface{} { - elementsLength := len(elements) - newSlice := make([]interface{}, len(slice)+elementsLength) - for i, e := range elements { - newSlice[i] = e - } - for i, e := range slice { - newSlice[elementsLength+i] = e - } - return newSlice -} - // Provides a canonical way to stringify keys func StringifyKey(key interface{}) string { switch key { diff --git a/logging/structure/structure_test.go b/logging/structure/structure_test.go index ee55756fb..e8064908b 100644 --- a/logging/structure/structure_test.go +++ b/logging/structure/structure_test.go @@ -17,6 +17,8 @@ package structure import ( "testing" + "github.com/hyperledger/burrow/util/slice" + "github.com/stretchr/testify/assert" ) @@ -99,8 +101,8 @@ func TestDelete(t *testing.T) { func TestCopyPrepend(t *testing.T) { assert.Equal(t, []interface{}{"three", 4, 1, "two"}, - CopyPrepend([]interface{}{1, "two"}, "three", 4)) - assert.Equal(t, []interface{}{}, CopyPrepend(nil)) - assert.Equal(t, []interface{}{1}, CopyPrepend(nil, 1)) - assert.Equal(t, []interface{}{1}, CopyPrepend([]interface{}{1})) + slice.CopyPrepend([]interface{}{1, "two"}, "three", 4)) + assert.Equal(t, []interface{}{}, slice.CopyPrepend(nil)) + assert.Equal(t, []interface{}{1}, slice.CopyPrepend(nil, 1)) + assert.Equal(t, []interface{}{1}, slice.CopyPrepend([]interface{}{1})) } diff --git a/permission/perm_flag.go b/permission/perm_flag.go index 8284cb728..dedc52825 100644 --- a/permission/perm_flag.go +++ b/permission/perm_flag.go @@ -58,16 +58,16 @@ const ( DefaultPermFlags PermFlag = Send | Call | CreateContract | CreateAccount | Bond | Name | HasBase | HasRole | Proposal | Input | Batch // Chain permissions strings - RootString string = "root" - SendString = "send" - CallString = "call" - CreateContractString = "createContract" - CreateAccountString = "createAccount" - BondString = "bond" - NameString = "name" - ProposalString = "proposal" - InputString = "input" - BatchString = "batch" + RootString = "root" + SendString = "send" + CallString = "call" + CreateContractString = "createContract" + CreateAccountString = "createAccount" + BondString = "bond" + NameString = "name" + ProposalString = "proposal" + InputString = "input" + BatchString = "batch" // Moderator permissions strings HasBaseString = "hasBase" diff --git a/project/history.go b/project/history.go index ea1969c07..f9d484cf3 100644 --- a/project/history.go +++ b/project/history.go @@ -48,8 +48,16 @@ func FullVersion() string { // release tagging script: ./scripts/tag_release.sh var History relic.ImmutableHistory = relic.NewHistory("Hyperledger Burrow", "https://github.com/hyperledger/burrow"). MustDeclareReleases( - "", - ``, + "0.27.0 - 2019-06-23", + `### Added +- [WASM] Support for WASM contracts written in Solidity compiled using solang + +### Fixed +-[RPC/Transact] CallCodeSim and CallTxSim were run against uncommitted checker state rather than committed state were all other reads are routed. They were also passed through Transactor for no particularly good reason. This changes them to run against committed DB state and removes the code path through Transactor. + +### Changed +- [State] TxExecution's Envelope now stored in state so will be reproduced in Vent Tx tables and over RPC, and so matches TxExecutions served from *Sync rpctransact methods +`, "0.26.2 - 2019-06-19", `### Fixed - [Blockchain] Persist LastBlockTime in Blockchain - before this patch LastBlockTime would only be set correctly after the first block had been received after a node is restarted - this can lead to non-determinism in the EVM via the TIMESTAMP opcode that use the LastBlockTime which is itself sourced from Tendermint's block header (from their implementation of BFT time). Implementing no empty blocks made observing this bug more likely by increasing the amount of time spent in a bad state (LastBlockTime is initially set to GenesisTime). diff --git a/protobuf/acm.proto b/protobuf/acm.proto index b3eb08114..76966b83b 100644 --- a/protobuf/acm.proto +++ b/protobuf/acm.proto @@ -21,6 +21,7 @@ message Account { crypto.PublicKey PublicKey = 2 [(gogoproto.nullable) = false]; uint64 Sequence = 3; uint64 Balance = 4; - bytes Code = 5 [(gogoproto.customtype) = "Bytecode", (gogoproto.nullable) = false]; + bytes EVMCode = 5 [(gogoproto.customtype) = "Bytecode", (gogoproto.nullable) = false]; permission.AccountPermissions Permissions = 6 [(gogoproto.nullable) = false]; + bytes WASMCode = 7 [(gogoproto.customtype) = "Bytecode", (gogoproto.jsontag) = ",omitempty", (gogoproto.nullable) = false]; } diff --git a/protobuf/dump.proto b/protobuf/dump.proto index 93d3a39a2..9f0bc24f0 100644 --- a/protobuf/dump.proto +++ b/protobuf/dump.proto @@ -24,7 +24,7 @@ option (gogoproto.messagename_all) = true; message Storage { bytes Key = 1 [(gogoproto.customtype) = "github.com/hyperledger/burrow/binary.Word256", (gogoproto.nullable) = false]; - bytes Value = 2 [(gogoproto.customtype) = "github.com/hyperledger/burrow/binary.Word256", (gogoproto.nullable) = false]; + bytes Value = 2 [(gogoproto.customtype) = "github.com/hyperledger/burrow/binary.HexBytes", (gogoproto.nullable) = false]; } message AccountStorage { diff --git a/protobuf/payload.proto b/protobuf/payload.proto index f712d324c..867787ee5 100644 --- a/protobuf/payload.proto +++ b/protobuf/payload.proto @@ -66,9 +66,10 @@ message CallTx { uint64 GasLimit = 3; // Fee to offer validators for processing transaction uint64 Fee = 4; - // EVM bytecode payload + // EVM bytecode bytes Data = 5 [(gogoproto.customtype) = "github.com/hyperledger/burrow/binary.HexBytes", (gogoproto.nullable) = false]; - + // WASM bytecode + bytes WASM = 6 [(gogoproto.customtype) = "github.com/hyperledger/burrow/binary.HexBytes", (gogoproto.nullable) = false, (gogoproto.jsontag)="tags,omitempty"]; } // A payment between two sets of parties diff --git a/protobuf/rpcquery.proto b/protobuf/rpcquery.proto index c5acdd397..c52bf156a 100644 --- a/protobuf/rpcquery.proto +++ b/protobuf/rpcquery.proto @@ -55,7 +55,7 @@ message GetStorageParam { } message StorageValue { - bytes Value = 1 [(gogoproto.customtype) = "github.com/hyperledger/burrow/binary.Word256", (gogoproto.nullable) = false]; + bytes Value = 1 [(gogoproto.customtype) = "github.com/hyperledger/burrow/binary.HexBytes", (gogoproto.nullable) = false]; } message ListAccountsParam { diff --git a/protobuf/spec.proto b/protobuf/spec.proto index c7119306e..b28f8a827 100644 --- a/protobuf/spec.proto +++ b/protobuf/spec.proto @@ -22,11 +22,10 @@ message TemplateAccount { string Name = 1; bytes Address = 2 [(gogoproto.customtype) = "github.com/hyperledger/burrow/crypto.Address", (gogoproto.jsontag) = ",omitempty", (gogoproto.moretags) = "toml:\",omitempty\""]; - bytes NodeAddress = 3 [(gogoproto.customtype) = "github.com/hyperledger/burrow/crypto.Address", (gogoproto.jsontag) = ",omitempty", (gogoproto.moretags) = "toml:\",omitempty\""]; - crypto.PublicKey PublicKey = 4 [(gogoproto.jsontag) = ",omitempty", (gogoproto.moretags) = "toml:\",omitempty\""]; - repeated balance.Balance Amounts = 5 [(gogoproto.nullable) = false, (gogoproto.jsontag) = ",omitempty", (gogoproto.moretags) = "toml:\",omitempty\""]; - repeated string Permissions = 6 [(gogoproto.jsontag) = ",omitempty", (gogoproto.moretags) = "toml:\",omitempty\""]; - repeated string Roles = 7 [(gogoproto.jsontag) = ",omitempty", (gogoproto.moretags) = "toml:\",omitempty\""]; - bytes Code = 8 [(gogoproto.nullable) = true, (gogoproto.customtype) = "github.com/hyperledger/burrow/acm.Bytecode"]; + crypto.PublicKey PublicKey = 3 [(gogoproto.jsontag) = ",omitempty", (gogoproto.moretags) = "toml:\",omitempty\""]; + repeated balance.Balance Amounts = 4 [(gogoproto.nullable) = false, (gogoproto.jsontag) = ",omitempty", (gogoproto.moretags) = "toml:\",omitempty\""]; + repeated string Permissions = 5 [(gogoproto.jsontag) = ",omitempty", (gogoproto.moretags) = "toml:\",omitempty\""]; + repeated string Roles = 6 [(gogoproto.jsontag) = ",omitempty", (gogoproto.moretags) = "toml:\",omitempty\""]; + bytes Code = 7 [(gogoproto.nullable) = true, (gogoproto.customtype) = "github.com/hyperledger/burrow/acm.Bytecode"]; } diff --git a/rpc/lib/rpc_test.go b/rpc/lib/rpc_test.go index 5d49945ea..9d2840bbe 100644 --- a/rpc/lib/rpc_test.go +++ b/rpc/lib/rpc_test.go @@ -15,7 +15,6 @@ import ( "github.com/hyperledger/burrow/process" - "github.com/go-kit/kit/log/term" "github.com/hyperledger/burrow/logging/lifecycle" "github.com/hyperledger/burrow/rpc/lib/client" "github.com/hyperledger/burrow/rpc/lib/server" @@ -87,19 +86,6 @@ func TestMain(m *testing.M) { os.Exit(code) } -var colorFn = func(keyvals ...interface{}) term.FgBgColor { - for i := 0; i < len(keyvals)-1; i += 2 { - if keyvals[i] == "socket" { - if keyvals[i+1] == "tcp" { - return term.FgBgColor{Fg: term.DarkBlue} - } else if keyvals[i+1] == "unix" { - return term.FgBgColor{Fg: term.DarkCyan} - } - } - } - return term.FgBgColor{} -} - // launch unix and tcp servers func setup() { logger, _ := lifecycle.NewStdErrLogger() diff --git a/rpc/lib/server/handlers.go b/rpc/lib/server/handlers.go index 274ee30f2..b26ef5d17 100644 --- a/rpc/lib/server/handlers.go +++ b/rpc/lib/server/handlers.go @@ -278,11 +278,11 @@ func httpParamsToArgs(rpcFunc *RPCFunc, r *http.Request) ([]reflect.Value, error arg := GetParam(r, name) // log.Notice("param to arg", "argType", argType, "name", name, "arg", arg) - if "" == arg { + if arg == "" { continue } - v, err, ok := nonJSONToArg(argType, arg) + v, ok, err := nonJSONToArg(argType, arg) if err != nil { return nil, err } @@ -310,7 +310,7 @@ func jsonStringToArg(ty reflect.Type, arg string) (reflect.Value, error) { return v, nil } -func nonJSONToArg(ty reflect.Type, arg string) (reflect.Value, error, bool) { +func nonJSONToArg(ty reflect.Type, arg string) (reflect.Value, bool, error) { expectingString := ty.Kind() == reflect.String expectingBytes := (ty.Kind() == reflect.Slice || ty.Kind() == reflect.Array) && ty.Elem().Kind() == reflect.Uint8 @@ -318,7 +318,7 @@ func nonJSONToArg(ty reflect.Type, arg string) (reflect.Value, error, bool) { // Throw quoted strings at JSON parser later... because it always has... if expectingString && !isQuotedString { - return reflect.ValueOf(arg), nil, true + return reflect.ValueOf(arg), true, nil } if expectingBytes { @@ -326,9 +326,9 @@ func nonJSONToArg(ty reflect.Type, arg string) (reflect.Value, error, bool) { rv := reflect.New(ty) err := json.Unmarshal([]byte(arg), rv.Interface()) if err != nil { - return reflect.ValueOf(nil), err, false + return reflect.ValueOf(nil), false, err } - return rv.Elem(), nil, true + return rv.Elem(), true, nil } if strings.HasPrefix(strings.ToLower(arg), "0x") { arg = arg[2:] @@ -336,18 +336,18 @@ func nonJSONToArg(ty reflect.Type, arg string) (reflect.Value, error, bool) { var value []byte value, err := hex.DecodeString(arg) if err != nil { - return reflect.ValueOf(nil), err, false + return reflect.ValueOf(nil), false, err } if ty.Kind() == reflect.Array { // Gives us an empty array of the right type rv := reflect.New(ty).Elem() reflect.Copy(rv, reflect.ValueOf(value)) - return rv, nil, true + return rv, true, nil } - return reflect.ValueOf(value), nil, true + return reflect.ValueOf(value), true, nil } - return reflect.ValueOf(nil), nil, false + return reflect.ValueOf(nil), false, nil } // rpc.http diff --git a/rpc/metrics/exporter.go b/rpc/metrics/exporter.go index 3e9f19a1c..b6a46c882 100644 --- a/rpc/metrics/exporter.go +++ b/rpc/metrics/exporter.go @@ -250,8 +250,7 @@ func (e *Exporter) getPeers() error { func (e *Exporter) getBlocks() (*rpc.ResultBlocks, error) { var minHeight uint64 - var maxHeight uint64 - maxHeight = uint64(e.datum.LatestBlockHeight) + maxHeight := uint64(e.datum.LatestBlockHeight) if maxHeight >= e.blockSampleSize { minHeight = maxHeight - (e.blockSampleSize - 1) diff --git a/rpc/rpcinfo/info_server.go b/rpc/rpcinfo/info_server.go index 949d581b4..156f9c831 100644 --- a/rpc/rpcinfo/info_server.go +++ b/rpc/rpcinfo/info_server.go @@ -26,7 +26,7 @@ import ( func StartServer(service *rpc.Service, pattern string, listener net.Listener, logger *logging.Logger) (*http.Server, error) { logger = logger.With(structure.ComponentKey, "RPC_Info") - routes := GetRoutes(service, logger) + routes := GetRoutes(service) mux := http.NewServeMux() wm := server.NewWebsocketManager(routes, logger) mux.HandleFunc(pattern, wm.WebsocketHandler) diff --git a/rpc/rpcinfo/methods.go b/rpc/rpcinfo/methods.go index 3066e4160..1309aecfc 100644 --- a/rpc/rpcinfo/methods.go +++ b/rpc/rpcinfo/methods.go @@ -2,7 +2,6 @@ package rpcinfo import ( "github.com/hyperledger/burrow/acm" - "github.com/hyperledger/burrow/logging" "github.com/hyperledger/burrow/rpc" "github.com/hyperledger/burrow/rpc/lib/server" ) @@ -41,8 +40,7 @@ const ( Consensus = "consensus" ) -func GetRoutes(service *rpc.Service, logger *logging.Logger) map[string]*server.RPCFunc { - logger = logger.WithScope("GetRoutes") +func GetRoutes(service *rpc.Service) map[string]*server.RPCFunc { return map[string]*server.RPCFunc{ // Status Status: server.NewRPCFunc(service.StatusWithin, "block_time_within,block_seen_time_within"), diff --git a/rpc/rpcquery/query_server.go b/rpc/rpcquery/query_server.go index 82805dd2d..9fab09099 100644 --- a/rpc/rpcquery/query_server.go +++ b/rpc/rpcquery/query_server.go @@ -66,6 +66,9 @@ func (qs *queryServer) GetStorage(ctx context.Context, param *GetStorageParam) ( func (qs *queryServer) ListAccounts(param *ListAccountsParam, stream Query_ListAccountsServer) error { qry, err := query.NewOrEmpty(param.Query) + if err != nil { + return err + } var streamErr error err = qs.accounts.IterateAccounts(func(acc *acm.Account) error { if qry.Matches(acc.Tagged()) { @@ -155,7 +158,7 @@ func (qs *queryServer) GetProposal(ctx context.Context, param *GetProposalParam) func (qs *queryServer) ListProposals(param *ListProposalsParam, stream Query_ListProposalsServer) error { var streamErr error err := qs.proposalReg.IterateProposals(func(hash []byte, ballot *payload.Ballot) error { - if param.GetProposed() == false || ballot.ProposalState == payload.Ballot_PROPOSED { + if !param.GetProposed() || ballot.ProposalState == payload.Ballot_PROPOSED { return stream.Send(&ProposalResult{Hash: hash, Ballot: ballot}) } else { return nil diff --git a/rpc/rpcquery/rpcquery.pb.go b/rpc/rpcquery/rpcquery.pb.go index 0001ec590..d9ea7463d 100644 --- a/rpc/rpcquery/rpcquery.pb.go +++ b/rpc/rpcquery/rpcquery.pb.go @@ -184,10 +184,10 @@ func (*GetStorageParam) XXX_MessageName() string { } type StorageValue struct { - Value github_com_hyperledger_burrow_binary.Word256 `protobuf:"bytes,1,opt,name=Value,proto3,customtype=github.com/hyperledger/burrow/binary.Word256" json:"Value"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Value github_com_hyperledger_burrow_binary.HexBytes `protobuf:"bytes,1,opt,name=Value,proto3,customtype=github.com/hyperledger/burrow/binary.HexBytes" json:"Value"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *StorageValue) Reset() { *m = StorageValue{} } @@ -939,62 +939,63 @@ func init() { proto.RegisterFile("rpcquery.proto", fileDescriptor_88e25d9b99e39f func init() { golang_proto.RegisterFile("rpcquery.proto", fileDescriptor_88e25d9b99e39f02) } var fileDescriptor_88e25d9b99e39f02 = []byte{ - // 872 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0x4f, 0x8f, 0xdb, 0x44, - 0x14, 0xc7, 0xbb, 0xdd, 0xec, 0xee, 0xcb, 0xbf, 0x76, 0xba, 0x84, 0xe0, 0x42, 0x5a, 0x8d, 0xc4, - 0x76, 0xa9, 0xc0, 0x89, 0x42, 0x17, 0x10, 0x1c, 0xa0, 0x41, 0x90, 0x2c, 0x7f, 0x56, 0x8b, 0x83, - 0x5a, 0xa9, 0x07, 0xa4, 0x89, 0x3d, 0x24, 0x16, 0x8e, 0xc7, 0x8c, 0xc7, 0x45, 0xfe, 0x48, 0x7c, - 0x0b, 0x8e, 0x7b, 0xe4, 0xcc, 0xa1, 0x42, 0xdb, 0x6f, 0xc1, 0x09, 0x79, 0xfe, 0x38, 0xb6, 0x37, - 0xad, 0xe0, 0xc0, 0x25, 0x7a, 0xef, 0xcd, 0xef, 0xfd, 0x9e, 0xf3, 0xe6, 0xfd, 0xde, 0x40, 0x87, - 0xc7, 0xde, 0x2f, 0x29, 0xe5, 0x99, 0x13, 0x73, 0x26, 0x18, 0x3a, 0x30, 0xbe, 0xfd, 0xfe, 0x32, - 0x10, 0xab, 0x74, 0xe1, 0x78, 0x6c, 0x3d, 0x5c, 0xb2, 0x25, 0x1b, 0x4a, 0xc0, 0x22, 0xfd, 0x49, - 0x7a, 0xd2, 0x91, 0x96, 0x4a, 0xb4, 0x3f, 0x2a, 0xc1, 0x05, 0x8d, 0x7c, 0xca, 0xd7, 0x41, 0x24, - 0xca, 0x26, 0x59, 0x78, 0xc1, 0x50, 0x64, 0x31, 0x4d, 0xd4, 0xaf, 0x4e, 0x6c, 0x46, 0x64, 0x5d, - 0x38, 0x87, 0xc4, 0x5b, 0x6b, 0xb3, 0xfb, 0x8c, 0x84, 0x81, 0x4f, 0x04, 0xe3, 0xe6, 0x8c, 0xc7, - 0x9e, 0x36, 0xdb, 0x31, 0xc9, 0x42, 0x46, 0x7c, 0xe5, 0xe2, 0x00, 0x9a, 0x73, 0x41, 0x44, 0x9a, - 0x5c, 0x10, 0x4e, 0xd6, 0xe8, 0x04, 0xba, 0x93, 0x90, 0x79, 0x3f, 0xff, 0x10, 0xac, 0xe9, 0x93, - 0x40, 0xac, 0x82, 0xa8, 0x6f, 0xdd, 0xb3, 0x4e, 0x0e, 0xdd, 0x7a, 0x18, 0x8d, 0xe0, 0xb6, 0x0c, - 0xcd, 0x29, 0x8d, 0x4a, 0xe8, 0x1d, 0x89, 0xde, 0x76, 0x84, 0x09, 0x74, 0xa7, 0x54, 0x3c, 0xf2, - 0x3c, 0x96, 0x46, 0x42, 0x95, 0x3b, 0x87, 0xfd, 0x47, 0xbe, 0xcf, 0x69, 0x92, 0xc8, 0x32, 0xad, - 0xc9, 0xc3, 0xcb, 0xe7, 0x77, 0x5f, 0xfb, 0xf3, 0xf9, 0xdd, 0xf7, 0x4a, 0x2d, 0x59, 0x65, 0x31, - 0xe5, 0x21, 0xf5, 0x97, 0x94, 0x0f, 0x17, 0x29, 0xe7, 0xec, 0xd7, 0xa1, 0xc7, 0xb3, 0x58, 0x30, - 0x47, 0xe7, 0xba, 0x86, 0x04, 0xff, 0x66, 0xc9, 0x1a, 0x73, 0xc1, 0x38, 0x59, 0xd2, 0xff, 0xa5, - 0x06, 0xfa, 0x0a, 0x76, 0xbf, 0xa1, 0x99, 0xfc, 0xa3, 0xff, 0x9a, 0x6b, 0x11, 0x44, 0x84, 0x67, - 0xce, 0x13, 0xc6, 0xfd, 0xf1, 0xe9, 0x87, 0x6e, 0x4e, 0x80, 0x9f, 0x42, 0x4b, 0x7f, 0xe7, 0x63, - 0x12, 0xa6, 0x14, 0x7d, 0x0d, 0x7b, 0xd2, 0xf8, 0x6f, 0x5f, 0x59, 0x63, 0x56, 0x14, 0xf8, 0x5d, - 0xb8, 0xf5, 0x6d, 0x90, 0x98, 0x5e, 0xeb, 0xbb, 0x3d, 0x82, 0xbd, 0xef, 0xf3, 0xf1, 0xd4, 0x37, - 0xaa, 0x1c, 0x8c, 0xa1, 0x35, 0xa5, 0xe2, 0x9c, 0xac, 0x75, 0xbb, 0x10, 0xdc, 0xc8, 0x1d, 0x0d, - 0x92, 0x36, 0x3e, 0x86, 0x4e, 0x4e, 0x97, 0xdb, 0xaf, 0xe4, 0xea, 0xc1, 0xd1, 0x94, 0x8a, 0xc7, - 0x66, 0xf8, 0xe6, 0x54, 0x5d, 0x33, 0x9e, 0xc2, 0x9d, 0x5a, 0x7c, 0x16, 0x24, 0x82, 0xf1, 0xac, - 0x18, 0xba, 0xb3, 0xc8, 0x0b, 0x53, 0x9f, 0x5e, 0x70, 0xfa, 0x2c, 0x60, 0xa9, 0xba, 0xa9, 0x5d, - 0xb7, 0x1e, 0xc6, 0x53, 0xb8, 0xbd, 0x85, 0x05, 0x8d, 0x60, 0x5f, 0x9b, 0x7d, 0xeb, 0xde, 0xee, - 0x49, 0x73, 0xdc, 0x73, 0x0a, 0x6d, 0x96, 0xf1, 0xae, 0x81, 0xe1, 0x73, 0x68, 0x95, 0x0f, 0x50, - 0x0f, 0x1a, 0x2b, 0x1a, 0x2c, 0x57, 0x42, 0x56, 0xbe, 0xe1, 0x6a, 0x0f, 0x1d, 0xc3, 0xee, 0x9c, - 0x8a, 0xfe, 0x8e, 0x64, 0x3d, 0x72, 0x36, 0xba, 0x2a, 0xb2, 0xdd, 0x1c, 0x80, 0x8f, 0xe1, 0xe6, - 0x94, 0x8a, 0x0b, 0xce, 0x62, 0x96, 0x90, 0xb0, 0xe8, 0xe4, 0x8c, 0x24, 0x2b, 0x75, 0x9f, 0xae, - 0xb4, 0xf1, 0x08, 0x50, 0xde, 0x49, 0x03, 0xd4, 0xdd, 0xb4, 0xe1, 0x40, 0x45, 0xa8, 0x2f, 0xd1, - 0x07, 0x6e, 0xe1, 0xe3, 0xef, 0xa0, 0x63, 0xd0, 0x2e, 0x4d, 0xd2, 0x50, 0x6c, 0xe3, 0x45, 0xf7, - 0xa1, 0x31, 0x21, 0x61, 0xc8, 0x84, 0x9c, 0xcb, 0xe6, 0xb8, 0xeb, 0x18, 0x99, 0xab, 0xb0, 0xab, - 0x8f, 0x71, 0x17, 0xda, 0x52, 0x20, 0x44, 0x4f, 0x05, 0xa6, 0xb0, 0x27, 0x3d, 0xf4, 0x00, 0x6e, - 0x9a, 0x79, 0xc9, 0x05, 0xfb, 0x05, 0xf3, 0xa9, 0x6e, 0xc6, 0xb5, 0x78, 0x2e, 0xfe, 0x72, 0x8c, - 0xa5, 0x42, 0xc2, 0x77, 0x24, 0x7c, 0xdb, 0x11, 0xbe, 0x2f, 0xeb, 0xca, 0xb5, 0xa0, 0xfe, 0x73, - 0x0f, 0x1a, 0xb3, 0x4a, 0xc7, 0x95, 0x37, 0xfe, 0x7b, 0x4f, 0x8f, 0x16, 0x1a, 0x43, 0x43, 0xad, - 0x26, 0xf4, 0xfa, 0xe6, 0x3a, 0x4b, 0xcb, 0xca, 0xbe, 0x95, 0x87, 0x1d, 0xd5, 0x15, 0x8d, 0x3c, - 0x05, 0xd8, 0xec, 0x18, 0xf4, 0xe6, 0x26, 0xaf, 0xb6, 0x79, 0xec, 0x96, 0x93, 0xaf, 0x4b, 0x03, - 0xfc, 0x4c, 0xa6, 0x69, 0x39, 0xd6, 0xd2, 0xca, 0xcb, 0xc4, 0xee, 0x95, 0xbf, 0xa4, 0x24, 0xde, - 0x4f, 0xa1, 0x55, 0x16, 0x1c, 0xba, 0xb3, 0xc1, 0x5d, 0x13, 0x62, 0xb5, 0xf6, 0xc8, 0x42, 0x43, - 0xd8, 0xd7, 0x12, 0x44, 0xbd, 0x4a, 0xe9, 0x42, 0x95, 0x76, 0xcb, 0x51, 0xab, 0xfe, 0xcb, 0x48, - 0xf0, 0x0c, 0x9d, 0xc2, 0x61, 0xa1, 0x47, 0xd4, 0xaf, 0x96, 0xda, 0x88, 0xb4, 0x9a, 0x34, 0xb2, - 0xd0, 0x99, 0x5c, 0x8e, 0x95, 0xb9, 0x1f, 0x54, 0xea, 0x5d, 0x53, 0xae, 0xfd, 0x12, 0x21, 0xa1, - 0x1f, 0xa1, 0xb7, 0x5d, 0xd1, 0xe8, 0x9d, 0x97, 0x32, 0x96, 0x35, 0x6f, 0xbf, 0xbd, 0x9d, 0xd8, - 0xb0, 0x7c, 0x02, 0xcd, 0x92, 0x9e, 0x90, 0x5d, 0x21, 0xad, 0xc8, 0xcc, 0xae, 0x8f, 0x3a, 0x3a, - 0x83, 0x76, 0x45, 0x63, 0xe8, 0xad, 0x6a, 0x87, 0xaa, 0xe2, 0xb3, 0x4b, 0xfd, 0xab, 0x0a, 0x6d, - 0x64, 0xa1, 0x87, 0x70, 0x60, 0xd4, 0x82, 0xde, 0xa8, 0x4d, 0x85, 0x51, 0x90, 0xdd, 0xad, 0x4e, - 0x67, 0x82, 0x3e, 0x86, 0x8e, 0x99, 0xf5, 0x19, 0x25, 0x3e, 0xe5, 0xb5, 0xdc, 0x8d, 0x0a, 0xec, - 0xb6, 0xa3, 0xde, 0x73, 0x85, 0x9b, 0x7c, 0x7e, 0x79, 0x35, 0xb0, 0xfe, 0xb8, 0x1a, 0x58, 0x7f, - 0x5d, 0x0d, 0xac, 0xdf, 0x5f, 0x0c, 0xac, 0xcb, 0x17, 0x03, 0xeb, 0xe9, 0x83, 0x57, 0x3f, 0x01, - 0x3c, 0xf6, 0x86, 0x86, 0x7e, 0xd1, 0x90, 0xcf, 0xfa, 0x07, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, - 0x3d, 0x0c, 0x60, 0xec, 0x9d, 0x08, 0x00, 0x00, + // 883 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0x5f, 0x8f, 0xdb, 0x44, + 0x10, 0xc7, 0x77, 0xbd, 0xdc, 0xdd, 0x24, 0x77, 0x69, 0xb7, 0x47, 0x08, 0x2e, 0xa4, 0xd5, 0x4a, + 0x5c, 0x8f, 0x8a, 0x3a, 0x51, 0x68, 0x00, 0xc1, 0x03, 0x34, 0x08, 0x92, 0x53, 0xe1, 0x74, 0x38, + 0xa8, 0x95, 0x40, 0x42, 0xda, 0xd8, 0x4b, 0x62, 0xe1, 0x78, 0xcd, 0x7a, 0x5d, 0xf0, 0x47, 0xe2, + 0x5b, 0xf0, 0x78, 0x8f, 0x3c, 0xf3, 0x50, 0xa1, 0xeb, 0xb7, 0xe0, 0x09, 0x79, 0xff, 0x38, 0xb6, + 0x2f, 0xad, 0xee, 0x85, 0x97, 0x68, 0x66, 0xf6, 0x37, 0xbf, 0x71, 0x66, 0xe7, 0x37, 0x0b, 0x87, + 0x3c, 0xf6, 0x7e, 0x4d, 0x29, 0xcf, 0x9c, 0x98, 0x33, 0xc1, 0xd0, 0x9e, 0xf1, 0xed, 0x87, 0x8b, + 0x40, 0x2c, 0xd3, 0xb9, 0xe3, 0xb1, 0x55, 0x7f, 0xc1, 0x16, 0xac, 0x2f, 0x01, 0xf3, 0xf4, 0x67, + 0xe9, 0x49, 0x47, 0x5a, 0x2a, 0xd1, 0xfe, 0xb8, 0x04, 0x17, 0x34, 0xf2, 0x29, 0x5f, 0x05, 0x91, + 0x28, 0x9b, 0x64, 0xee, 0x05, 0x7d, 0x91, 0xc5, 0x34, 0x51, 0xbf, 0x3a, 0xb1, 0x19, 0x91, 0x55, + 0xe1, 0xec, 0x13, 0x6f, 0xa5, 0xcd, 0xf6, 0x73, 0x12, 0x06, 0x3e, 0x11, 0x8c, 0x9b, 0x33, 0x1e, + 0x7b, 0xda, 0x3c, 0x88, 0x49, 0x16, 0x32, 0xe2, 0x2b, 0x17, 0x07, 0xd0, 0x9c, 0x09, 0x22, 0xd2, + 0xe4, 0x9c, 0x70, 0xb2, 0x42, 0x27, 0xd0, 0x1e, 0x87, 0xcc, 0xfb, 0xe5, 0xfb, 0x60, 0x45, 0x9f, + 0x05, 0x62, 0x19, 0x44, 0x5d, 0xeb, 0x9e, 0x75, 0xb2, 0xef, 0xd6, 0xc3, 0x68, 0x00, 0xb7, 0x65, + 0x68, 0x46, 0x69, 0x54, 0x42, 0x6f, 0x49, 0xf4, 0xa6, 0x23, 0x4c, 0xa0, 0x3d, 0xa1, 0xe2, 0xb1, + 0xe7, 0xb1, 0x34, 0x12, 0xaa, 0xdc, 0x19, 0xec, 0x3e, 0xf6, 0x7d, 0x4e, 0x93, 0x44, 0x96, 0x69, + 0x8d, 0x1f, 0x5d, 0xbc, 0xb8, 0xfb, 0xc6, 0xdf, 0x2f, 0xee, 0x7e, 0x50, 0x6a, 0xc9, 0x32, 0x8b, + 0x29, 0x0f, 0xa9, 0xbf, 0xa0, 0xbc, 0x3f, 0x4f, 0x39, 0x67, 0xbf, 0xf5, 0x3d, 0x9e, 0xc5, 0x82, + 0x39, 0x3a, 0xd7, 0x35, 0x24, 0xf8, 0x0f, 0x4b, 0xd6, 0x98, 0x09, 0xc6, 0xc9, 0x82, 0xfe, 0x2f, + 0x35, 0xd0, 0xd7, 0xb0, 0xfd, 0x84, 0x66, 0xf2, 0x8f, 0x5e, 0x9b, 0x6b, 0x1e, 0x44, 0x84, 0x67, + 0xce, 0x33, 0xc6, 0xfd, 0xe1, 0xe8, 0x23, 0x37, 0x27, 0xc0, 0x3f, 0x42, 0x4b, 0x7f, 0xe7, 0x53, + 0x12, 0xa6, 0x14, 0x3d, 0x81, 0x1d, 0x69, 0xe8, 0xaf, 0x1c, 0x69, 0xe6, 0x87, 0xd7, 0x62, 0x9e, + 0xd2, 0xdf, 0xc7, 0x99, 0xa0, 0x89, 0xab, 0x38, 0xf0, 0xfb, 0x70, 0xeb, 0x9b, 0x20, 0x31, 0xcd, + 0xd6, 0x97, 0x7b, 0x04, 0x3b, 0xdf, 0xe5, 0xf3, 0xa9, 0xaf, 0x54, 0x39, 0x18, 0x43, 0x6b, 0x42, + 0xc5, 0x19, 0x59, 0xe9, 0x7e, 0x21, 0xb8, 0x91, 0x3b, 0x1a, 0x24, 0x6d, 0x7c, 0x0c, 0x87, 0x39, + 0x5d, 0x6e, 0xbf, 0x96, 0xab, 0x03, 0x47, 0x13, 0x2a, 0x9e, 0x9a, 0xe9, 0x9b, 0x51, 0x75, 0xcf, + 0x78, 0x02, 0x77, 0x6a, 0xf1, 0x69, 0x90, 0x08, 0xc6, 0xb3, 0x62, 0xea, 0x4e, 0x23, 0x2f, 0x4c, + 0x7d, 0x7a, 0xce, 0xe9, 0xf3, 0x80, 0xa5, 0xea, 0xaa, 0xb6, 0xdd, 0x7a, 0x18, 0x4f, 0xe0, 0xf6, + 0x06, 0x16, 0x34, 0x80, 0x5d, 0x6d, 0x76, 0xad, 0x7b, 0xdb, 0x27, 0xcd, 0x61, 0xc7, 0x29, 0xc4, + 0x59, 0xc6, 0xbb, 0x06, 0x86, 0xcf, 0xa0, 0x55, 0x3e, 0x40, 0x1d, 0x68, 0x2c, 0x69, 0xb0, 0x58, + 0x0a, 0x59, 0xf9, 0x86, 0xab, 0x3d, 0x74, 0x0c, 0xdb, 0x33, 0x2a, 0xba, 0x5b, 0x92, 0xf5, 0xc8, + 0x59, 0x0b, 0xab, 0xc8, 0x76, 0x73, 0x00, 0x3e, 0x86, 0x9b, 0x13, 0x2a, 0xce, 0x39, 0x8b, 0x59, + 0x42, 0xc2, 0xa2, 0x93, 0x53, 0x92, 0x2c, 0xd5, 0x85, 0xba, 0xd2, 0xc6, 0x03, 0x40, 0x79, 0x27, + 0x0d, 0x50, 0x77, 0xd3, 0x86, 0x3d, 0x15, 0xa1, 0xbe, 0x44, 0xef, 0xb9, 0x85, 0x8f, 0xbf, 0x85, + 0x43, 0x83, 0x76, 0x69, 0x92, 0x86, 0x62, 0x13, 0x2f, 0xba, 0x0f, 0x8d, 0x31, 0x09, 0x43, 0x26, + 0xe4, 0x60, 0x36, 0x87, 0x6d, 0xc7, 0xe8, 0x5c, 0x85, 0x5d, 0x7d, 0x8c, 0xdb, 0x70, 0x20, 0x15, + 0x42, 0xf4, 0x54, 0x60, 0x0a, 0x3b, 0xd2, 0x43, 0x0f, 0xe0, 0xa6, 0x99, 0x97, 0x5c, 0xb1, 0x5f, + 0x32, 0x9f, 0xea, 0x66, 0x5c, 0x89, 0xe7, 0xea, 0x2f, 0xc7, 0x58, 0x2a, 0x24, 0x7c, 0x4b, 0xc2, + 0x37, 0x1d, 0xe1, 0xfb, 0xb2, 0xae, 0xdc, 0x0b, 0xea, 0x3f, 0x77, 0xa0, 0x31, 0xad, 0x74, 0x5c, + 0x79, 0xc3, 0x7f, 0x77, 0xf4, 0x68, 0xa1, 0x21, 0x34, 0xd4, 0x6e, 0x42, 0x6f, 0xae, 0xaf, 0xb3, + 0xb4, 0xad, 0xec, 0x5b, 0x79, 0xd8, 0x51, 0x5d, 0xd1, 0xc8, 0x11, 0xc0, 0x7a, 0xc9, 0xa0, 0xb7, + 0xd7, 0x79, 0xb5, 0xd5, 0x63, 0xb7, 0x9c, 0x7c, 0x5f, 0x1a, 0xe0, 0xe7, 0x32, 0x4d, 0xeb, 0xb1, + 0x96, 0x56, 0xde, 0x26, 0x76, 0xa7, 0xfc, 0x25, 0x25, 0xf5, 0x7e, 0x06, 0xad, 0xb2, 0xe0, 0xd0, + 0x9d, 0x35, 0xee, 0x8a, 0x10, 0xab, 0xb5, 0x07, 0x16, 0xea, 0xc3, 0xae, 0x96, 0x20, 0xea, 0x54, + 0x4a, 0x17, 0xaa, 0xb4, 0x5b, 0x8e, 0xda, 0xf5, 0x5f, 0x45, 0x82, 0x67, 0x68, 0x04, 0xfb, 0x85, + 0x1e, 0x51, 0xb7, 0x5a, 0x6a, 0x2d, 0xd2, 0x6a, 0xd2, 0xc0, 0x42, 0xa7, 0x72, 0x3b, 0x56, 0xe6, + 0xbe, 0x57, 0xa9, 0x77, 0x45, 0xb9, 0xf6, 0x2b, 0x84, 0x84, 0x7e, 0x82, 0xce, 0x66, 0x45, 0xa3, + 0xf7, 0x5e, 0xc9, 0x58, 0xd6, 0xbc, 0xfd, 0xee, 0x66, 0x62, 0xc3, 0xf2, 0x29, 0x34, 0x4b, 0x7a, + 0x42, 0x76, 0x85, 0xb4, 0x22, 0x33, 0xbb, 0x3e, 0xea, 0xe8, 0x14, 0x0e, 0x2a, 0x1a, 0x43, 0xef, + 0x54, 0x3b, 0x54, 0x15, 0x9f, 0x5d, 0xea, 0x5f, 0x55, 0x68, 0x03, 0x0b, 0x3d, 0x82, 0x3d, 0xa3, + 0x16, 0xf4, 0x56, 0x6d, 0x2a, 0x8c, 0x82, 0xec, 0x76, 0x75, 0x3a, 0x13, 0xf4, 0x09, 0x1c, 0x9a, + 0x59, 0x9f, 0x52, 0xe2, 0x53, 0x5e, 0xcb, 0x5d, 0xab, 0xc0, 0x3e, 0x70, 0xd4, 0x83, 0xae, 0x70, + 0xe3, 0x2f, 0x2e, 0x2e, 0x7b, 0xd6, 0x5f, 0x97, 0x3d, 0xeb, 0x9f, 0xcb, 0x9e, 0xf5, 0xe7, 0xcb, + 0x9e, 0x75, 0xf1, 0xb2, 0x67, 0xfd, 0xf0, 0xe0, 0xf5, 0x6f, 0x00, 0x8f, 0xbd, 0xbe, 0xa1, 0x9f, + 0x37, 0xe4, 0xbb, 0xfe, 0xe1, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xac, 0x5a, 0x15, 0x64, 0x9e, + 0x08, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/rpc/rpctransact/transact_server.go b/rpc/rpctransact/transact_server.go index 329c06876..644bbf907 100644 --- a/rpc/rpctransact/transact_server.go +++ b/rpc/rpctransact/transact_server.go @@ -4,6 +4,11 @@ import ( "fmt" "time" + "github.com/hyperledger/burrow/logging" + + "github.com/hyperledger/burrow/acm/acmstate" + "github.com/hyperledger/burrow/bcm" + "github.com/hyperledger/burrow/execution" "github.com/hyperledger/burrow/execution/exec" "github.com/hyperledger/burrow/txs" @@ -15,14 +20,21 @@ import ( const maxBroadcastSyncTimeout = time.Hour type transactServer struct { + state acmstate.Reader + blockchain bcm.BlockchainInfo transactor *execution.Transactor txCodec txs.Codec + logger *logging.Logger } -func NewTransactServer(transactor *execution.Transactor, txCodec txs.Codec) TransactServer { +func NewTransactServer(state acmstate.Reader, blockchain bcm.BlockchainInfo, transactor *execution.Transactor, + txCodec txs.Codec, logger *logging.Logger) TransactServer { return &transactServer{ + state: state, + blockchain: blockchain, transactor: transactor, txCodec: txCodec, + logger: logger.WithScope("NewTransactServer()"), } } @@ -88,11 +100,12 @@ func (ts *transactServer) CallTxSim(ctx context.Context, param *payload.CallTx) if param.Address == nil { return nil, fmt.Errorf("CallSim requires a non-nil address from which to retrieve code") } - return ts.transactor.CallSim(param.Input.Address, *param.Address, param.Data) + return execution.CallSim(ts.state, ts.blockchain, param.Input.Address, *param.Address, param.Data, ts.logger) } func (ts *transactServer) CallCodeSim(ctx context.Context, param *CallCodeParam) (*exec.TxExecution, error) { - return ts.transactor.CallCodeSim(param.FromAddress, param.Code, param.Data) + return execution.CallCodeSim(ts.state, ts.blockchain, param.FromAddress, param.FromAddress, param.Code, param.Data, + ts.logger) } func (ts *transactServer) SendTxSync(ctx context.Context, param *payload.SendTx) (*exec.TxExecution, error) { diff --git a/rpc/service.go b/rpc/service.go index 690fb5698..eb366bd8a 100644 --- a/rpc/service.go +++ b/rpc/service.go @@ -90,9 +90,7 @@ func (s *Service) UnconfirmedTxs(maxTxs int64) (*ResultUnconfirmedTxs, error) { return nil, err } wrappedTxs := make([]*txs.Envelope, len(transactions)) - for i, tx := range transactions { - wrappedTxs[i] = tx - } + copy(wrappedTxs, transactions) return &ResultUnconfirmedTxs{ NumTxs: len(transactions), Txs: wrappedTxs, @@ -192,10 +190,7 @@ func (s *Service) Storage(address crypto.Address, key []byte) (*ResultStorage, e if err != nil { return nil, err } - if value == binary.Zero256 { - return &ResultStorage{Key: key, Value: nil}, nil - } - return &ResultStorage{Key: key, Value: value.UnpadLeft()}, nil + return &ResultStorage{Key: key, Value: value}, nil } func (s *Service) DumpStorage(address crypto.Address) (*ResultDumpStorage, error) { @@ -207,8 +202,8 @@ func (s *Service) DumpStorage(address crypto.Address) (*ResultDumpStorage, error return nil, fmt.Errorf("UnknownAddress: %X", address) } var storageItems []StorageItem - err = s.state.IterateStorage(address, func(key, value binary.Word256) error { - storageItems = append(storageItems, StorageItem{Key: key.UnpadLeft(), Value: value.UnpadLeft()}) + err = s.state.IterateStorage(address, func(key binary.Word256, value []byte) error { + storageItems = append(storageItems, StorageItem{Key: key.UnpadLeft(), Value: value}) return nil }) if err != nil { @@ -227,7 +222,7 @@ func (s *Service) AccountHumanReadable(address crypto.Address) (*ResultAccountHu if acc == nil { return &ResultAccountHumanReadable{}, nil } - tokens, err := acc.Code.Tokens() + tokens, err := acc.EVMCode.Tokens() if err != nil { return nil, err } diff --git a/storage/channel_iterator_test.go b/storage/channel_iterator_test.go deleted file mode 100644 index 482467059..000000000 --- a/storage/channel_iterator_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package storage - -import "testing" - -func TestNewChannelIterator(t *testing.T) { - ch := make(chan KVPair) - go sendKVPair(ch, kvPairs("a", "hello", "b", "channel", "c", "this is nice")) - ci := NewChannelIterator(ch, bz("a"), bz("c")) - checkItem(t, ci, bz("a"), bz("hello")) - checkNext(t, ci, true) - checkItem(t, ci, bz("b"), bz("channel")) - checkNext(t, ci, true) - checkItem(t, ci, bz("c"), bz("this is nice")) - checkNext(t, ci, false) - checkInvalid(t, ci) -} diff --git a/storage/commit_id.go b/storage/commit_id.go deleted file mode 100644 index eff39ae88..000000000 --- a/storage/commit_id.go +++ /dev/null @@ -1,44 +0,0 @@ -package storage - -import ( - "fmt" - - "github.com/hyperledger/burrow/binary" - amino "github.com/tendermint/go-amino" -) - -var codec = amino.NewCodec() - -type CommitID struct { - Hash binary.HexBytes - Version int64 -} - -func MarshalCommitID(hash []byte, version int64) ([]byte, error) { - commitID := CommitID{ - Version: version, - Hash: hash, - } - bs, err := codec.MarshalBinaryBare(commitID) - if err != nil { - return nil, fmt.Errorf("MarshalCommitID() could not encode CommitID %v: %v", commitID, err) - } - if bs == nil { - // Normalise zero value to non-nil so we can store it IAVL tree without panic - return []byte{}, nil - } - return bs, nil -} - -func UnmarshalCommitID(bs []byte) (*CommitID, error) { - commitID := new(CommitID) - err := codec.UnmarshalBinaryBare(bs, commitID) - if err != nil { - return nil, fmt.Errorf("could not unmarshal CommitID: %v", err) - } - return commitID, nil -} - -func (cid CommitID) String() string { - return fmt.Sprintf("Commit{Hash: %v, Version: %v}", cid.Hash, cid.Version) -} diff --git a/storage/forest.go b/storage/forest.go new file mode 100644 index 000000000..63823ede7 --- /dev/null +++ b/storage/forest.go @@ -0,0 +1,347 @@ +package storage + +import ( + "fmt" + + lru "github.com/hashicorp/golang-lru" + "github.com/hyperledger/burrow/binary" + "github.com/tendermint/go-amino" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/xlab/treeprint" +) + +const ( + commitsPrefix = "c" + treePrefix = "t" +) + +// Access the read path of a forest +type ForestReader interface { + Reader(prefix []byte) (KVCallbackIterableReader, error) +} + +// MutableForest is a collection of versioned lazily-loaded RWTrees organised by prefix. It maintains a global state hash +// by storing CommitIDs in a special commitsTree (you could think of it is a two-layer single tree rather than a forest). +// +// The trees (or sub-trees if you prefer) in the forest are RWTrees which wrap an IAVL MutableTree routing writes to the +// MutableTree and reads to the last saved ImmutableTree. In this way reads act only against committed state and can be +// lock free (this allows us to avoid blocking commits - particularly for long-running iterations). +// +// The trees in the forest are created lazily as required by new writes. There is a cache of most recently used trees +// and trees that may require a save are marked as such. New writes are only available to read after a Save(). +// +// Here is an example forest (the output is generated by the Dump() function): +// . +// ├── balances +// │   ├── Caitlin -> 2344 +// │   ├── Cora -> 654456 +// │   ├── Edward -> 34 +// │   └── Lindsay -> 654 +// └── names +// ├── Caitlin -> female +// ├── Cora -> female +// ├── Edward -> male +// └── Lindsay -> unisex +// +// Here there are two tree indexed by the prefixes 'balances' and 'names'. +// +// To perform reads of the forest we access it in the following way: +// +// tree, err := forest.Reader("names") +// gender := tree.Get("Cora") +// +// To perform writes: +// +// tree, err := forest.Writer("names") +// tree.Set("Cora", "unspecified") +// +// If there is no tree currently stored at the prefix passed then it will be created when the forest is saved: +// +// hash, version, err := forest.Save() +// +// where the global version for the forest is returned. + +type MutableForest struct { + // A tree containing a reference for all contained trees in the form of prefix -> CommitID + commitsTree *RWTree + // Much of the implementation of MutableForest is contained in ImmutableForest which is embedded here and used + // mutable via its private API. This embedded instance holds a reference to commitsTree above. + *ImmutableForest + // Map of prefix -> tree for trees that may require a save (but only will be if they have actually been updated) + dirty map[string]*RWTree + // List of dirty prefixes in deterministic order so we may loop over them on Save() and obtain a consistent commitTree hash + dirtyPrefixes []string +} + +// ImmutableForest contains much of the implementation for MutableForest yet it's external API is immutable +type ImmutableForest struct { + // Store of tree prefix -> last commitID (version + hash) - serves as a set of all known trees and provides a global hash + commitsTree KVCallbackIterableReader + treeDB dbm.DB + // Cache for frequently used trees + treeCache *lru.Cache + // Cache size is used in multiple places - for the LRU cache and node cache for any trees created - it probably + // makes sense for them to be roughly the same size + cacheSize int + // Determines whether we use LoadVersionForOverwriting on underlying MutableTrees - since ImmutableForest is used + // by MutableForest in a writing context sometimes we do need to load a version destructively + overwriting bool +} + +// This is the object that is stored in the leaves of the commitsTree - it captures the sub-tree hashes so that the +// commitsTree's hash becomes a mixture of the hashes of all the sub-trees. +type CommitID struct { + Hash binary.HexBytes + Version int64 +} + +type ForestOption func(*ImmutableForest) + +var WithOverwriting ForestOption = func(imf *ImmutableForest) { imf.overwriting = true } + +func NewMutableForest(db dbm.DB, cacheSize int) (*MutableForest, error) { + // The tree whose state root hash is the global state hash + commitsTree := NewRWTree(NewPrefixDB(db, commitsPrefix), cacheSize) + forest, err := NewImmutableForest(commitsTree, NewPrefixDB(db, treePrefix), cacheSize, WithOverwriting) + if err != nil { + return nil, err + } + return &MutableForest{ + ImmutableForest: forest, + commitsTree: commitsTree, + dirty: make(map[string]*RWTree), + }, nil +} + +func NewImmutableForest(commitsTree KVCallbackIterableReader, treeDB dbm.DB, cacheSize int, + options ...ForestOption) (*ImmutableForest, error) { + cache, err := lru.New(cacheSize) + if err != nil { + return nil, fmt.Errorf("NewImmutableForest() could not create cache: %v", err) + } + imf := &ImmutableForest{ + commitsTree: commitsTree, + treeDB: treeDB, + treeCache: cache, + cacheSize: cacheSize, + } + for _, opt := range options { + opt(imf) + } + return imf, nil +} + +// Load mutable forest from database +func (muf *MutableForest) Load(version int64) error { + return muf.commitsTree.Load(version, true) +} + +func (muf *MutableForest) Save() (hash []byte, version int64, _ error) { + // Save each tree in forest that requires save + for _, prefix := range muf.dirtyPrefixes { + tree := muf.dirty[prefix] + if tree.Updated() { + err := muf.saveTree([]byte(prefix), tree) + if err != nil { + return nil, 0, err + } + } + } + // empty dirty cache + muf.dirty = make(map[string]*RWTree, len(muf.dirty)) + muf.dirtyPrefixes = muf.dirtyPrefixes[:0] + return muf.commitsTree.Save() +} + +func (muf *MutableForest) GetImmutable(version int64) (*ImmutableForest, error) { + commitsTree, err := muf.commitsTree.GetImmutable(version) + if err != nil { + return nil, fmt.Errorf("MutableForest.GetImmutable() could not get commits tree for version %d: %v", + version, err) + } + return NewImmutableForest(commitsTree, muf.treeDB, muf.cacheSize) +} + +// Calls to writer should be serialised as should writes to the tree +func (muf *MutableForest) Writer(prefix []byte) (*RWTree, error) { + // Try dirty cache first (if tree is new it may only be in this location) + prefixString := string(prefix) + if tree, ok := muf.dirty[prefixString]; ok { + return tree, nil + } + tree, err := muf.tree(prefix) + if err != nil { + return nil, err + } + // Mark tree as dirty + muf.dirty[prefixString] = tree + muf.dirtyPrefixes = append(muf.dirtyPrefixes, prefixString) + return tree, nil +} + +func (muf *MutableForest) IterateRWTree(start, end []byte, ascending bool, fn func(prefix []byte, tree *RWTree) error) error { + return muf.commitsTree.Iterate(start, end, ascending, func(prefix []byte, _ []byte) error { + rwt, err := muf.tree(prefix) + if err != nil { + return err + } + return fn(prefix, rwt) + }) +} + +// Delete a tree - if the tree exists will return the CommitID of the latest saved version +func (muf *MutableForest) Delete(prefix []byte) (*CommitID, error) { + bs, removed := muf.commitsTree.Delete(prefix) + if !removed { + return nil, nil + } + return unmarshalCommitID(bs) +} + +// Get the current global hash for all trees in this forest +func (muf *MutableForest) Hash() []byte { + return muf.commitsTree.Hash() +} + +// Get the current global version for all versions of all trees in this forest +func (muf *MutableForest) Version() int64 { + return muf.commitsTree.Version() +} + +func (muf *MutableForest) saveTree(prefix []byte, tree *RWTree) error { + hash, version, err := tree.Save() + if err != nil { + return fmt.Errorf("MutableForest.saveTree() could not save tree: %v", err) + } + return muf.setCommit(prefix, hash, version) +} + +func (muf *MutableForest) setCommit(prefix, hash []byte, version int64) error { + bs, err := marshalCommitID(hash, version) + if err != nil { + return fmt.Errorf("MutableForest.setCommit() could not marshal CommitID: %v", err) + } + muf.commitsTree.Set([]byte(prefix), bs) + return nil +} + +// ImmutableForest + +// Get the tree at prefix for making reads +func (imf *ImmutableForest) Reader(prefix []byte) (KVCallbackIterableReader, error) { + return imf.tree(prefix) +} + +func (imf *ImmutableForest) Iterate(start, end []byte, ascending bool, fn func(prefix []byte, tree KVCallbackIterableReader) error) error { + return imf.commitsTree.Iterate(start, end, ascending, func(prefix []byte, _ []byte) error { + rwt, err := imf.tree(prefix) + if err != nil { + return err + } + return fn(prefix, rwt) + }) +} + +func (imf *ImmutableForest) Dump() string { + dump := treeprint.New() + AddTreePrintTree("Commits", dump, imf.commitsTree) + err := imf.Iterate(nil, nil, true, func(prefix []byte, tree KVCallbackIterableReader) error { + AddTreePrintTree(string(prefix), dump, tree) + return nil + }) + if err != nil { + return fmt.Sprintf("ImmutableForest.Dump(): iteration error: %v", err) + } + return dump.String() +} + +// Shared implementation - these methods + +// Lazy load tree +func (imf *ImmutableForest) tree(prefix []byte) (*RWTree, error) { + // Try cache + if value, ok := imf.treeCache.Get(string(prefix)); ok { + return value.(*RWTree), nil + } + // Not in caches but non-negative version - we should be able to load into memory + return imf.loadOrCreateTree(prefix) +} + +func (imf *ImmutableForest) commitID(prefix []byte) (*CommitID, error) { + bs := imf.commitsTree.Get(prefix) + if bs == nil { + return new(CommitID), nil + } + commitID, err := unmarshalCommitID(bs) + if err != nil { + return nil, fmt.Errorf("could not get commitID for prefix %X: %v", prefix, err) + } + return commitID, nil +} + +func (imf *ImmutableForest) loadOrCreateTree(prefix []byte) (*RWTree, error) { + const errHeader = "ImmutableForest.loadOrCreateTree():" + tree := imf.newTree(prefix) + commitID, err := imf.commitID(prefix) + if err != nil { + return nil, fmt.Errorf("%s %v", errHeader, err) + } + if commitID.Version == 0 { + // This is the first time we have been asked to load this tree + return imf.newTree(prefix), nil + } + err = tree.Load(commitID.Version, imf.overwriting) + if err != nil { + return nil, fmt.Errorf("%s could not load tree: %v", errHeader, err) + } + return tree, nil +} + +// Create a new in-memory IAVL tree +func (imf *ImmutableForest) newTree(prefix []byte) *RWTree { + p := string(prefix) + tree := NewRWTree(NewPrefixDB(imf.treeDB, p), imf.cacheSize) + imf.treeCache.Add(p, tree) + return tree +} + +// CommitID serialisation + +var codec = amino.NewCodec() + +func (cid *CommitID) UnmarshalBinary(data []byte) error { + return codec.UnmarshalBinaryBare(data, cid) +} + +func (cid *CommitID) MarshalBinary() (data []byte, err error) { + return codec.MarshalBinaryBare(cid) +} + +func (cid CommitID) String() string { + return fmt.Sprintf("Commit{Hash: %v, Version: %v}", cid.Hash, cid.Version) +} + +func marshalCommitID(hash []byte, version int64) ([]byte, error) { + commitID := CommitID{ + Version: version, + Hash: hash, + } + bs, err := commitID.MarshalBinary() + if err != nil { + return nil, fmt.Errorf("MarshalCommitID() could not encode CommitID %v: %v", commitID, err) + } + if bs == nil { + // Normalise zero value to non-nil so we can store it IAVL tree without panic + return []byte{}, nil + } + return bs, nil +} + +func unmarshalCommitID(bs []byte) (*CommitID, error) { + commitID := new(CommitID) + err := commitID.UnmarshalBinary(bs) + if err != nil { + return nil, fmt.Errorf("could not unmarshal CommitID: %v", err) + } + return commitID, nil +} diff --git a/storage/mutable_forest_test.go b/storage/forest_test.go similarity index 92% rename from storage/mutable_forest_test.go rename to storage/forest_test.go index e1766bb9e..97ccad8d4 100644 --- a/storage/mutable_forest_test.go +++ b/storage/forest_test.go @@ -14,11 +14,11 @@ import ( func TestMutableForest_Genesis(t *testing.T) { rwf, err := NewMutableForest(dbm.NewMemDB(), 100) require.NoError(t, err) - prefix := bz("fooos") + prefix := []byte("fooos") tree, err := rwf.Writer(prefix) require.NoError(t, err) - key1 := bz("bar") - val1 := bz("nog") + key1 := []byte("bar") + val1 := []byte("nog") tree.Set(key1, val1) _, _, err = rwf.Save() @@ -38,11 +38,11 @@ func TestMutableForest_Genesis(t *testing.T) { func TestMutableForest_Save(t *testing.T) { forest, err := NewMutableForest(dbm.NewMemDB(), 100) require.NoError(t, err) - prefix1 := bz("fooos") + prefix1 := []byte("fooos") tree, err := forest.Writer(prefix1) require.NoError(t, err) - key1 := bz("bar") - val1 := bz("nog") + key1 := []byte("bar") + val1 := []byte("nog") tree.Set(key1, val1) hash1, version1, err := forest.Save() @@ -55,9 +55,9 @@ func TestMutableForest_Save(t *testing.T) { └── "bar" -> "nog" `) - prefix2 := bz("prefixo") - key2 := bz("hogs") - val2 := bz("they are dogs") + prefix2 := []byte("prefixo") + key2 := []byte("hogs") + val2 := []byte("they are dogs") tree, err = forest.Writer(prefix2) require.NoError(t, err) tree.Set(key2, val2) @@ -83,11 +83,11 @@ func TestMutableForest_Load(t *testing.T) { db := dbm.NewMemDB() forest, err := NewMutableForest(db, 100) require.NoError(t, err) - prefix1 := bz("prefixes can be long if you want") + prefix1 := []byte("prefixes can be long if you want") tree, err := forest.Writer(prefix1) require.NoError(t, err) - key1 := bz("El Nubble") - val1 := bz("Diplodicus") + key1 := []byte("El Nubble") + val1 := []byte("Diplodicus") tree.Set(key1, val1) hash, version, err := forest.Save() @@ -121,8 +121,10 @@ func TestSorted(t *testing.T) { setForest(t, forest, "balances", "Lindsay", "654") setForest(t, forest, "balances", "Cora", "654456") _, _, err = forest.Save() - tree, err := forest.Writer(bz("age")) - tree.Get(bz("foo")) + require.NoError(t, err) + tree, err := forest.Writer([]byte("age")) + require.NoError(t, err) + tree.Get([]byte("foo")) setForest(t, forest, "age", "Lindsay", "34") setForest(t, forest, "age", "Cora", "1") _, _, err = forest.Save() diff --git a/storage/immutable_forest.go b/storage/immutable_forest.go deleted file mode 100644 index 1922bef55..000000000 --- a/storage/immutable_forest.go +++ /dev/null @@ -1,129 +0,0 @@ -package storage - -import ( - "fmt" - - "github.com/xlab/treeprint" - - lru "github.com/hashicorp/golang-lru" - dbm "github.com/tendermint/tendermint/libs/db" -) - -type ImmutableForest struct { - // Store of tree prefix -> last commitID (version + hash) - serves as a set of all known trees and provides a global hash - commitsTree KVCallbackIterableReader - treeDB dbm.DB - // Cache for frequently used trees - treeCache *lru.Cache - // Cache size is used in multiple places - for the LRU cache and node cache for any trees created - it probably - // makes sense for them to be roughly the same size - cacheSize int - // Determines whether we use LoadVersionForOverwriting on underlying MutableTrees - since ImmutableForest is used - // by MutableForest in a writing context sometimes we do need to load a version destructively - overwriting bool -} - -type ForestOption func(*ImmutableForest) - -var WithOverwriting ForestOption = func(imf *ImmutableForest) { imf.overwriting = true } - -func NewImmutableForest(commitsTree KVCallbackIterableReader, treeDB dbm.DB, cacheSize int, - options ...ForestOption) (*ImmutableForest, error) { - cache, err := lru.New(cacheSize) - if err != nil { - return nil, fmt.Errorf("NewImmutableForest() could not create cache: %v", err) - } - imf := &ImmutableForest{ - commitsTree: commitsTree, - treeDB: treeDB, - treeCache: cache, - cacheSize: cacheSize, - } - for _, opt := range options { - opt(imf) - } - return imf, nil -} - -func (imf *ImmutableForest) Iterate(start, end []byte, ascending bool, fn func(prefix []byte, tree KVCallbackIterableReader) error) error { - return imf.commitsTree.Iterate(start, end, ascending, func(prefix []byte, _ []byte) error { - rwt, err := imf.tree(prefix) - if err != nil { - return err - } - return fn(prefix, rwt) - }) -} - -func (imf *ImmutableForest) IterateRWTree(start, end []byte, ascending bool, fn func(prefix []byte, tree *RWTree) error) error { - return imf.commitsTree.Iterate(start, end, ascending, func(prefix []byte, _ []byte) error { - rwt, err := imf.tree(prefix) - if err != nil { - return err - } - return fn(prefix, rwt) - }) -} - -// Get the tree at prefix for making reads -func (imf *ImmutableForest) Reader(prefix []byte) (KVCallbackIterableReader, error) { - return imf.tree(prefix) -} - -// Lazy load tree -func (imf *ImmutableForest) tree(prefix []byte) (*RWTree, error) { - // Try cache - if value, ok := imf.treeCache.Get(string(prefix)); ok { - return value.(*RWTree), nil - } - // Not in caches but non-negative version - we should be able to load into memory - return imf.loadOrCreateTree(prefix) -} - -func (imf *ImmutableForest) commitID(prefix []byte) (*CommitID, error) { - bs := imf.commitsTree.Get(prefix) - if bs == nil { - return new(CommitID), nil - } - commitID, err := UnmarshalCommitID(bs) - if err != nil { - return nil, fmt.Errorf("could not get commitID for prefix %X: %v", prefix, err) - } - return commitID, nil -} - -func (imf *ImmutableForest) loadOrCreateTree(prefix []byte) (*RWTree, error) { - const errHeader = "ImmutableForest.loadOrCreateTree():" - tree := imf.newTree(prefix) - commitID, err := imf.commitID(prefix) - if err != nil { - return nil, fmt.Errorf("%s %v", errHeader, err) - } - if commitID.Version == 0 { - // This is the first time we have been asked to load this tree - return imf.newTree(prefix), nil - } - err = tree.Load(commitID.Version, imf.overwriting) - if err != nil { - return nil, fmt.Errorf("%s could not load tree: %v", errHeader, err) - } - return tree, nil -} - -// Create a new in-memory IAVL tree -func (imf *ImmutableForest) newTree(prefix []byte) *RWTree { - p := string(prefix) - tree := NewRWTree(NewPrefixDB(imf.treeDB, p), imf.cacheSize) - imf.treeCache.Add(p, tree) - return tree -} - -func (imf *ImmutableForest) Dump() string { - dump := treeprint.New() - AddTreePrintTree("Commits", dump, imf.commitsTree) - imf.Iterate(nil, nil, true, func(prefix []byte, tree KVCallbackIterableReader) error { - AddTreePrintTree(string(prefix), dump, tree) - return nil - }) - return dump.String() -} diff --git a/storage/immutable_tree.go b/storage/immutable_tree.go deleted file mode 100644 index c9aa347ee..000000000 --- a/storage/immutable_tree.go +++ /dev/null @@ -1,28 +0,0 @@ -package storage - -import "github.com/tendermint/iavl" - -// We wrap IAVL's tree types in order to provide iteration helpers and to harmonise other interface types with what we -// expect - -type ImmutableTree struct { - *iavl.ImmutableTree -} - -func (imt *ImmutableTree) Get(key []byte) []byte { - _, value := imt.ImmutableTree.Get(key) - return value -} - -func (imt *ImmutableTree) Iterate(start, end []byte, ascending bool, fn func(key []byte, value []byte) error) error { - var err error - imt.ImmutableTree.IterateRange(start, end, ascending, func(key, value []byte) bool { - err = fn(key, value) - if err != nil { - // stop - return true - } - return false - }) - return err -} diff --git a/storage/key_format.go b/storage/key_format.go index db0812406..dc3201153 100644 --- a/storage/key_format.go +++ b/storage/key_format.go @@ -1,10 +1,10 @@ package storage import ( + "encoding/binary" "fmt" + "reflect" "strings" - - "github.com/hyperledger/burrow/binary" ) const ( @@ -61,6 +61,39 @@ func NewKeyFormat(prefix string, layout ...int) (*KeyFormat, error) { return kf, nil } +var expectedKeyFormatType = reflect.TypeOf(MustKeyFormat{}) + +// Checks that a struct containing KeyFormat fields has no collisions on prefix and so acts as a sane 'KeyFormatStore' +func EnsureKeyFormatStore(ks interface{}) error { + rv := reflect.ValueOf(ks) + if rv.Kind() == reflect.Ptr { + rv = rv.Elem() + } + rt := rv.Type() + + keyFormats := make(map[string]MustKeyFormat) + for i := 0; i < rt.NumField(); i++ { + fv := rv.Field(i) + if fv.Kind() == reflect.Ptr { + if fv.IsNil() { + return fmt.Errorf("key format field '%s' is nil", rt.Field(i).Name) + } + fv = fv.Elem() + } + ft := fv.Type() + if ft == expectedKeyFormatType { + kf := fv.Interface().(MustKeyFormat) + prefix := kf.Prefix().String() + if kfDuplicate, ok := keyFormats[prefix]; ok { + return fmt.Errorf("duplicate prefix %q between key format %v and %v", + prefix, kfDuplicate, kf) + } + keyFormats[prefix] = kf + } + } + return nil +} + // Format the byte segments into the key format - will panic if the segment lengths do not match the layout. func (kf *KeyFormat) KeyBytes(segments ...[]byte) ([]byte, error) { key := make([]byte, kf.length) @@ -236,9 +269,9 @@ func scan(a interface{}, value []byte) { // Ignore - allows for omitted values case *int64: // Negative values will be mapped correctly when read in as uint64 and then type converted - *v = binary.GetInt64(value) + *v = int64(binary.BigEndian.Uint64(value)) case *uint64: - *v = binary.GetUint64(value) + *v = binary.BigEndian.Uint64(value) case *[]byte: *v = value case *string: @@ -251,14 +284,14 @@ func scan(a interface{}, value []byte) { func format(a interface{}) []byte { switch v := a.(type) { case uint64: - return binary.Uint64Bytes(v) + return uint64Bytes(v) case int64: - return binary.Uint64Bytes(uint64(v)) + return uint64Bytes(uint64(v)) // Provide formatting from int,uint as a convenience to avoid casting arguments case uint: - return binary.Uint64Bytes(uint64(v)) + return uint64Bytes(uint64(v)) case int: - return binary.Uint64Bytes(uint64(v)) + return uint64Bytes(uint64(v)) case []byte: return v case ByteSlicable: @@ -270,6 +303,12 @@ func format(a interface{}) []byte { } } +func uint64Bytes(v uint64) []byte { + bs := make([]byte, 8) + binary.BigEndian.PutUint64(bs, v) + return bs +} + // MustKeyFormat for panicking early when a KeyFormat does not parse type MustKeyFormat struct { KeyFormat diff --git a/storage/key_format_store.go b/storage/key_format_store.go deleted file mode 100644 index 99975afb1..000000000 --- a/storage/key_format_store.go +++ /dev/null @@ -1,38 +0,0 @@ -package storage - -import ( - "fmt" - "reflect" -) - -var expectedKeyFormatType = reflect.TypeOf(MustKeyFormat{}) - -func EnsureKeyFormatStore(ks interface{}) error { - rv := reflect.ValueOf(ks) - if rv.Kind() == reflect.Ptr { - rv = rv.Elem() - } - rt := rv.Type() - - keyFormats := make(map[string]MustKeyFormat) - for i := 0; i < rt.NumField(); i++ { - fv := rv.Field(i) - if fv.Kind() == reflect.Ptr { - if fv.IsNil() { - return fmt.Errorf("key format field '%s' is nil", rt.Field(i).Name) - } - fv = fv.Elem() - } - ft := fv.Type() - if ft == expectedKeyFormatType { - kf := fv.Interface().(MustKeyFormat) - prefix := kf.Prefix().String() - if kfDuplicate, ok := keyFormats[prefix]; ok { - return fmt.Errorf("duplicate prefix %q between key format %v and %v", - prefix, kfDuplicate, kf) - } - keyFormats[prefix] = kf - } - } - return nil -} diff --git a/storage/key_format_store_test.go b/storage/key_format_store_test.go deleted file mode 100644 index 1331c5068..000000000 --- a/storage/key_format_store_test.go +++ /dev/null @@ -1,77 +0,0 @@ -package storage - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -type testKeyStore = struct { - Accounts *MustKeyFormat - Storage *MustKeyFormat - foo string -} - -func TestEnsureKeyStore(t *testing.T) { - keyStore := testKeyStore{ - Accounts: NewMustKeyFormat("foo", 4, 5, 6), - Storage: NewMustKeyFormat("foos", 4, 5, 6), - } - err := EnsureKeyFormatStore(keyStore) - require.NoError(t, err) - - err = EnsureKeyFormatStore(&keyStore) - require.NoError(t, err, "pointer to keystore should work") - - keyStore = testKeyStore{ - Accounts: NewMustKeyFormat("foo", 4, 5, 6), - Storage: NewMustKeyFormat("foo", 4, 5, 6), - } - err = EnsureKeyFormatStore(&keyStore) - require.Error(t, err, "duplicate prefixes should be detected") - - // Test missing formats - keyStore = testKeyStore{} - err = EnsureKeyFormatStore(&keyStore) - require.Error(t, err, "all formats should be set") - - keyStore = testKeyStore{ - Accounts: NewMustKeyFormat("foo", 4, 5, 6), - } - err = EnsureKeyFormatStore(&keyStore) - require.Error(t, err, "all formats should be set") - - keyStore2 := struct { - Accounts MustKeyFormat - Storage *MustKeyFormat - }{ - Accounts: *NewMustKeyFormat("foo", 56, 6), - Storage: NewMustKeyFormat("foo2", 1, 2), - } - - err = EnsureKeyFormatStore(keyStore2) - require.NoError(t, err) - - keyStore2 = struct { - Accounts MustKeyFormat - Storage *MustKeyFormat - }{ - Storage: NewMustKeyFormat("foo2", 1, 2), - } - err = EnsureKeyFormatStore(keyStore2) - require.NoError(t, err) - - err = EnsureKeyFormatStore(keyStore2) - require.NoError(t, err) - - keyStore2 = struct { - Accounts MustKeyFormat - Storage *MustKeyFormat - }{ - Accounts: *NewMustKeyFormat("foo", 56, 6), - Storage: NewMustKeyFormat("foo", 1, 2), - } - - err = EnsureKeyFormatStore(keyStore2) - require.Error(t, err, "duplicate prefixes should be detected") -} diff --git a/storage/key_format_test.go b/storage/key_format_test.go index 0a9c0f179..bc7d61ee1 100644 --- a/storage/key_format_test.go +++ b/storage/key_format_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestKeyFormatBytes(t *testing.T) { @@ -33,7 +34,7 @@ func TestKeyFormat(t *testing.T) { assert.Equal(t, b, *bo) assert.Equal(t, c, *co) - ao, bo, co = new(int64), new(int64), new(int64) + ao, bo, _ = new(int64), new(int64), new(int64) bs := new([]byte) kf.Scan(key, ao, bo, bs) assert.Equal(t, a, *ao) @@ -108,3 +109,73 @@ func TestKeyFormat_Layout(t *testing.T) { key := kf.KeyNoPrefix([]byte("Hi, "), "dinosaur") assert.Equal(t, "Hi, dinosaur", key.String()) } + +type testKeyStore = struct { + Accounts *MustKeyFormat + Storage *MustKeyFormat + foo string +} + +func TestEnsureKeyStore(t *testing.T) { + keyStore := testKeyStore{ + Accounts: NewMustKeyFormat("foo", 4, 5, 6), + Storage: NewMustKeyFormat("foos", 4, 5, 6), + } + err := EnsureKeyFormatStore(keyStore) + require.NoError(t, err) + + err = EnsureKeyFormatStore(&keyStore) + require.NoError(t, err, "pointer to keystore should work") + + keyStore = testKeyStore{ + Accounts: NewMustKeyFormat("foo", 4, 5, 6), + Storage: NewMustKeyFormat("foo", 4, 5, 6), + } + err = EnsureKeyFormatStore(&keyStore) + require.Error(t, err, "duplicate prefixes should be detected") + + // Test missing formats + keyStore = testKeyStore{} + err = EnsureKeyFormatStore(&keyStore) + require.Error(t, err, "all formats should be set") + + keyStore = testKeyStore{ + Accounts: NewMustKeyFormat("foo", 4, 5, 6), + } + err = EnsureKeyFormatStore(&keyStore) + require.Error(t, err, "all formats should be set") + + keyStore2 := struct { + Accounts MustKeyFormat + Storage *MustKeyFormat + }{ + Accounts: *NewMustKeyFormat("foo", 56, 6), + Storage: NewMustKeyFormat("foo2", 1, 2), + } + + err = EnsureKeyFormatStore(keyStore2) + require.NoError(t, err) + + keyStore2 = struct { + Accounts MustKeyFormat + Storage *MustKeyFormat + }{ + Storage: NewMustKeyFormat("foo2", 1, 2), + } + err = EnsureKeyFormatStore(keyStore2) + require.NoError(t, err) + + err = EnsureKeyFormatStore(keyStore2) + require.NoError(t, err) + + keyStore2 = struct { + Accounts MustKeyFormat + Storage *MustKeyFormat + }{ + Accounts: *NewMustKeyFormat("foo", 56, 6), + Storage: NewMustKeyFormat("foo", 1, 2), + } + + err = EnsureKeyFormatStore(keyStore2) + require.Error(t, err, "duplicate prefixes should be detected") +} diff --git a/storage/kvcascade.go b/storage/kvcascade.go deleted file mode 100644 index 581167f57..000000000 --- a/storage/kvcascade.go +++ /dev/null @@ -1,39 +0,0 @@ -package storage - -type KVCascade []KVIterableReader - -func (kvc KVCascade) Get(key []byte) []byte { - for _, kvs := range kvc { - value := kvs.Get(key) - if value != nil { - return value - } - } - return nil -} - -func (kvc KVCascade) Has(key []byte) bool { - for _, kvs := range kvc { - has := kvs.Has(key) - if has { - return true - } - } - return false -} - -func (kvc KVCascade) Iterator(low, high []byte) KVIterator { - iterators := make([]KVIterator, len(kvc)) - for i, kvs := range kvc { - iterators[i] = kvs.Iterator(low, high) - } - return NewMultiIterator(false, iterators...) -} - -func (kvc KVCascade) ReverseIterator(low, high []byte) KVIterator { - iterators := make([]KVIterator, len(kvc)) - for i, kvs := range kvc { - iterators[i] = kvs.ReverseIterator(low, high) - } - return NewMultiIterator(true, iterators...) -} diff --git a/storage/kvstore.go b/storage/kvstore.go index 2ac984528..ee02e6bd9 100644 --- a/storage/kvstore.go +++ b/storage/kvstore.go @@ -32,18 +32,6 @@ type KVCallbackIterable interface { Iterate(low, high []byte, ascending bool, fn func(key []byte, value []byte) error) error } -func KVCallbackIterator(rit KVCallbackIterable, ascending bool, low, high []byte) dbm.Iterator { - ch := make(chan KVPair) - go func() { - defer close(ch) - rit.Iterate(low, high, ascending, func(key, value []byte) (err error) { - ch <- KVPair{key, value} - return - }) - }() - return NewChannelIterator(ch, low, high) -} - type KVReader interface { // Get returns nil iff key doesn't exist. Panics on nil key. Get(key []byte) []byte @@ -79,14 +67,6 @@ type KVStore interface { KVIterable } -// NormaliseDomain encodes the assumption that when nil is used as a lower bound is interpreted as low rather than high -func NormaliseDomain(low, high []byte) ([]byte, []byte) { - if len(low) == 0 { - low = []byte{} - } - return low, high -} - // KeyOrder maps []byte{} -> -1, []byte(nil) -> 1, and everything else to 0. This encodes the assumptions of the // KVIterator domain endpoints func KeyOrder(key []byte) int { @@ -114,3 +94,11 @@ func CompareKeys(k1, k2 []byte) int { } return bytes.Compare(k1, k2) } + +// NormaliseDomain encodes the assumption that when nil is used as a lower bound is interpreted as low rather than high +func NormaliseDomain(low, high []byte) ([]byte, []byte) { + if len(low) == 0 { + low = []byte{} + } + return low, high +} diff --git a/storage/mutable_forest.go b/storage/mutable_forest.go deleted file mode 100644 index 10d473ebb..000000000 --- a/storage/mutable_forest.go +++ /dev/null @@ -1,165 +0,0 @@ -package storage - -import ( - "fmt" - - dbm "github.com/tendermint/tendermint/libs/db" -) - -const ( - commitsPrefix = "c" - treePrefix = "t" -) - -type ForestReader interface { - Reader(prefix []byte) (KVCallbackIterableReader, error) -} - -// MutableForest is a collection of versioned lazily-loaded RWTrees organised by prefix. It maintains a global state hash -// by storing CommitIDs in a special commitsTree (you could think of it is a two-layer single tree rather than a forest). -// -// The trees (or sub-trees if you prefer) in the forest are RWTrees which wrap an IAVL MutableTree routing writes to the -// MutableTree and reads to the last saved ImmutableTree. In this way reads act only against committed state and can be -// lock free (this allows us to avoid blocking commits - particularly for long-running iterations). -// -// The trees in the forest are created lazily as required by new writes. There is a cache of most recently used trees -// and trees that may require a save are marked as such. New writes are only available to read after a Save(). -// -// Here is an example forest (the output is generated by the Dump() function): -// . -// ├── balances -// │   ├── Caitlin -> 2344 -// │   ├── Cora -> 654456 -// │   ├── Edward -> 34 -// │   └── Lindsay -> 654 -// └── names -// ├── Caitlin -> female -// ├── Cora -> female -// ├── Edward -> male -// └── Lindsay -> unisex -// -// Here there are two tree indexed by the prefixes 'balances' and 'names'. -// -// To perform reads of the forest we access it in the following way: -// -// tree, err := forest.Reader("names") -// gender := tree.Get("Cora") -// -// To perform writes: -// -// tree, err := forest.Writer("names") -// tree.Set("Cora", "unspecified") -// -// If there is no tree currently stored at the prefix passed then it will be created when the forest is saved: -// -// hash, version, err := forest.Save() -// -// where the global version for the forest is returned. - -type MutableForest struct { - // A tree containing a reference for all contained trees in the form of prefix -> CommitID - commitsTree *RWTree - *ImmutableForest - // Map of prefix -> tree for trees that may require a save (but only will be if they have actually been updated) - dirty map[string]*RWTree - // List of dirty prefixes in deterministic order so we may loop over them on Save() and obtain a consistent commitTree hash - dirtyPrefixes []string -} - -func NewMutableForest(db dbm.DB, cacheSize int) (*MutableForest, error) { - tree := NewRWTree(NewPrefixDB(db, commitsPrefix), cacheSize) - forest, err := NewImmutableForest(tree, NewPrefixDB(db, treePrefix), cacheSize, WithOverwriting) - if err != nil { - return nil, err - } - return &MutableForest{ - ImmutableForest: forest, - commitsTree: tree, - dirty: make(map[string]*RWTree), - }, nil -} - -// Load mutable forest from database, pass overwriting = true if you wish to make writes to version version + 1. -// this will -func (muf *MutableForest) Load(version int64) error { - return muf.commitsTree.Load(version, true) -} - -func (muf *MutableForest) Save() ([]byte, int64, error) { - // Save each tree in forest that requires save - for _, prefix := range muf.dirtyPrefixes { - tree := muf.dirty[prefix] - if tree.Updated() { - err := muf.saveTree([]byte(prefix), tree) - if err != nil { - return nil, 0, err - } - } - } - // empty dirty cache - muf.dirty = make(map[string]*RWTree, len(muf.dirty)) - muf.dirtyPrefixes = muf.dirtyPrefixes[:0] - return muf.commitsTree.Save() -} - -func (muf *MutableForest) GetImmutable(version int64) (*ImmutableForest, error) { - commitsTree, err := muf.commitsTree.GetImmutable(version) - if err != nil { - return nil, fmt.Errorf("MutableForest.GetImmutable() could not get commits tree for version %d: %v", - version, err) - } - return NewImmutableForest(commitsTree, muf.treeDB, muf.cacheSize) -} - -// Calls to writer should be serialised as should writes to the tree -func (muf *MutableForest) Writer(prefix []byte) (*RWTree, error) { - // Try dirty cache first (if tree is new it may only be in this location) - prefixString := string(prefix) - if tree, ok := muf.dirty[prefixString]; ok { - return tree, nil - } - tree, err := muf.tree(prefix) - if err != nil { - return nil, err - } - // Mark tree as dirty - muf.dirty[prefixString] = tree - muf.dirtyPrefixes = append(muf.dirtyPrefixes, prefixString) - return tree, nil -} - -// Delete a tree - if the tree exists will return the CommitID of the latest saved version -func (muf *MutableForest) Delete(prefix []byte) (*CommitID, error) { - bs, removed := muf.commitsTree.Delete(prefix) - if !removed { - return nil, nil - } - return UnmarshalCommitID(bs) -} - -// Get the current global hash for all trees in this forest -func (muf *MutableForest) Hash() []byte { - return muf.commitsTree.Hash() -} - -// Get the current global version for all versions of all trees in this forest -func (muf *MutableForest) Version() int64 { - return muf.commitsTree.Version() -} - -func (muf *MutableForest) saveTree(prefix []byte, tree *RWTree) error { - hash, version, err := tree.Save() - if err != nil { - return fmt.Errorf("MutableForest.saveTree() could not save tree: %v", err) - } - return muf.setCommit(prefix, hash, version) -} - -func (muf *MutableForest) setCommit(prefix, hash []byte, version int64) error { - bs, err := MarshalCommitID(hash, version) - if err != nil { - return fmt.Errorf("MutableForest.setCommit() could not marshal CommitID: %v", err) - } - muf.commitsTree.Set([]byte(prefix), bs) - return nil -} diff --git a/storage/prefix_db_test.go b/storage/prefix_db_test.go index 9469eba50..23b1771a2 100644 --- a/storage/prefix_db_test.go +++ b/storage/prefix_db_test.go @@ -13,15 +13,15 @@ import ( func mockDBWithStuff() dbm.DB { db := dbm.NewMemDB() // Under "key" prefix - db.Set(bz("key"), bz("value")) - db.Set(bz("key1"), bz("value1")) - db.Set(bz("key2"), bz("value2")) - db.Set(bz("key3"), bz("value3")) - db.Set(bz("something"), bz("else")) - db.Set(bz(""), bz("")) - db.Set(bz("k"), bz("val")) - db.Set(bz("ke"), bz("valu")) - db.Set(bz("kee"), bz("valuu")) + db.Set([]byte("key"), []byte("value")) + db.Set([]byte("key1"), []byte("value1")) + db.Set([]byte("key2"), []byte("value2")) + db.Set([]byte("key3"), []byte("value3")) + db.Set([]byte("something"), []byte("else")) + db.Set([]byte(""), []byte("")) + db.Set([]byte("k"), []byte("val")) + db.Set([]byte("ke"), []byte("valu")) + db.Set([]byte("kee"), []byte("valuu")) return db } @@ -29,18 +29,18 @@ func TestPrefixDBSimple(t *testing.T) { db := mockDBWithStuff() pdb := NewPrefixDB(db, "key") - checkValue(t, pdb, bz("key"), nil) - checkValue(t, pdb, bz(""), bz("value")) - checkValue(t, pdb, bz("key1"), nil) - checkValue(t, pdb, bz("1"), bz("value1")) - checkValue(t, pdb, bz("key2"), nil) - checkValue(t, pdb, bz("2"), bz("value2")) - checkValue(t, pdb, bz("key3"), nil) - checkValue(t, pdb, bz("3"), bz("value3")) - checkValue(t, pdb, bz("something"), nil) - checkValue(t, pdb, bz("k"), nil) - checkValue(t, pdb, bz("ke"), nil) - checkValue(t, pdb, bz("kee"), nil) + checkValue(t, pdb, []byte("key"), nil) + checkValue(t, pdb, []byte(""), []byte("value")) + checkValue(t, pdb, []byte("key1"), nil) + checkValue(t, pdb, []byte("1"), []byte("value1")) + checkValue(t, pdb, []byte("key2"), nil) + checkValue(t, pdb, []byte("2"), []byte("value2")) + checkValue(t, pdb, []byte("key3"), nil) + checkValue(t, pdb, []byte("3"), []byte("value3")) + checkValue(t, pdb, []byte("something"), nil) + checkValue(t, pdb, []byte("k"), nil) + checkValue(t, pdb, []byte("ke"), nil) + checkValue(t, pdb, []byte("kee"), nil) } func TestPrefixDBIterator1(t *testing.T) { @@ -49,13 +49,13 @@ func TestPrefixDBIterator1(t *testing.T) { itr := pdb.Iterator(nil, nil) checkDomain(t, itr, nil, nil) - checkItem(t, itr, bz(""), bz("value")) + checkItem(t, itr, []byte(""), []byte("value")) checkNext(t, itr, true) - checkItem(t, itr, bz("1"), bz("value1")) + checkItem(t, itr, []byte("1"), []byte("value1")) checkNext(t, itr, true) - checkItem(t, itr, bz("2"), bz("value2")) + checkItem(t, itr, []byte("2"), []byte("value2")) checkNext(t, itr, true) - checkItem(t, itr, bz("3"), bz("value3")) + checkItem(t, itr, []byte("3"), []byte("value3")) checkNext(t, itr, false) checkInvalid(t, itr) itr.Close() @@ -65,8 +65,8 @@ func TestPrefixDBIterator2(t *testing.T) { db := mockDBWithStuff() pdb := NewPrefixDB(db, "key") - itr := pdb.Iterator(nil, bz("")) - checkDomain(t, itr, nil, bz("")) + itr := pdb.Iterator(nil, []byte("")) + checkDomain(t, itr, nil, []byte("")) checkInvalid(t, itr) itr.Close() } @@ -75,15 +75,15 @@ func TestPrefixDBIterator3(t *testing.T) { db := mockDBWithStuff() pdb := NewPrefixDB(db, "key") - itr := pdb.Iterator(bz(""), nil) - checkDomain(t, itr, bz(""), nil) - checkItem(t, itr, bz(""), bz("value")) + itr := pdb.Iterator([]byte(""), nil) + checkDomain(t, itr, []byte(""), nil) + checkItem(t, itr, []byte(""), []byte("value")) checkNext(t, itr, true) - checkItem(t, itr, bz("1"), bz("value1")) + checkItem(t, itr, []byte("1"), []byte("value1")) checkNext(t, itr, true) - checkItem(t, itr, bz("2"), bz("value2")) + checkItem(t, itr, []byte("2"), []byte("value2")) checkNext(t, itr, true) - checkItem(t, itr, bz("3"), bz("value3")) + checkItem(t, itr, []byte("3"), []byte("value3")) checkNext(t, itr, false) checkInvalid(t, itr) itr.Close() @@ -93,8 +93,8 @@ func TestPrefixDBIterator4(t *testing.T) { db := mockDBWithStuff() pdb := NewPrefixDB(db, "key") - itr := pdb.Iterator(bz(""), bz("")) - checkDomain(t, itr, bz(""), bz("")) + itr := pdb.Iterator([]byte(""), []byte("")) + checkDomain(t, itr, []byte(""), []byte("")) checkInvalid(t, itr) itr.Close() } @@ -105,13 +105,13 @@ func TestPrefixDBReverseIterator1(t *testing.T) { itr := pdb.ReverseIterator(nil, nil) checkDomain(t, itr, nil, nil) - checkItem(t, itr, bz("3"), bz("value3")) + checkItem(t, itr, []byte("3"), []byte("value3")) checkNext(t, itr, true) - checkItem(t, itr, bz("2"), bz("value2")) + checkItem(t, itr, []byte("2"), []byte("value2")) checkNext(t, itr, true) - checkItem(t, itr, bz("1"), bz("value1")) + checkItem(t, itr, []byte("1"), []byte("value1")) checkNext(t, itr, true) - checkItem(t, itr, bz(""), bz("value")) + checkItem(t, itr, []byte(""), []byte("value")) checkNext(t, itr, false) checkInvalid(t, itr) itr.Close() @@ -121,15 +121,15 @@ func TestPrefixDBReverseIterator2(t *testing.T) { db := mockDBWithStuff() pdb := NewPrefixDB(db, "key") - itr := pdb.ReverseIterator(bz(""), nil) - checkDomain(t, itr, bz(""), nil) - checkItem(t, itr, bz("3"), bz("value3")) + itr := pdb.ReverseIterator([]byte(""), nil) + checkDomain(t, itr, []byte(""), nil) + checkItem(t, itr, []byte("3"), []byte("value3")) checkNext(t, itr, true) - checkItem(t, itr, bz("2"), bz("value2")) + checkItem(t, itr, []byte("2"), []byte("value2")) checkNext(t, itr, true) - checkItem(t, itr, bz("1"), bz("value1")) + checkItem(t, itr, []byte("1"), []byte("value1")) checkNext(t, itr, true) - checkItem(t, itr, bz(""), bz("value")) + checkItem(t, itr, []byte(""), []byte("value")) checkNext(t, itr, false) checkInvalid(t, itr) itr.Close() @@ -139,8 +139,8 @@ func TestPrefixDBReverseIterator3(t *testing.T) { db := mockDBWithStuff() pdb := NewPrefixDB(db, "key") - itr := pdb.ReverseIterator(nil, bz("")) - checkDomain(t, itr, nil, bz("")) + itr := pdb.ReverseIterator(nil, []byte("")) + checkDomain(t, itr, nil, []byte("")) checkInvalid(t, itr) itr.Close() } @@ -149,8 +149,8 @@ func TestPrefixDBReverseIterator4(t *testing.T) { db := mockDBWithStuff() pdb := NewPrefixDB(db, "key") - itr := pdb.ReverseIterator(bz(""), bz("")) - checkDomain(t, itr, bz(""), bz("")) + itr := pdb.ReverseIterator([]byte(""), []byte("")) + checkDomain(t, itr, []byte(""), []byte("")) checkInvalid(t, itr) itr.Close() } @@ -159,13 +159,13 @@ func TestPrefixDBReverseIterator5(t *testing.T) { db := mockDBWithStuff() pdb := NewPrefixDB(db, "key") - itr := pdb.ReverseIterator(bz("1"), nil) - checkDomain(t, itr, bz("1"), nil) - checkItem(t, itr, bz("3"), bz("value3")) + itr := pdb.ReverseIterator([]byte("1"), nil) + checkDomain(t, itr, []byte("1"), nil) + checkItem(t, itr, []byte("3"), []byte("value3")) checkNext(t, itr, true) - checkItem(t, itr, bz("2"), bz("value2")) + checkItem(t, itr, []byte("2"), []byte("value2")) checkNext(t, itr, true) - checkItem(t, itr, bz("1"), bz("value1")) + checkItem(t, itr, []byte("1"), []byte("value1")) checkNext(t, itr, false) checkInvalid(t, itr) itr.Close() @@ -175,11 +175,11 @@ func TestPrefixDBReverseIterator6(t *testing.T) { db := mockDBWithStuff() pdb := NewPrefixDB(db, "key") - itr := pdb.ReverseIterator(bz("2"), nil) - checkDomain(t, itr, bz("2"), nil) - checkItem(t, itr, bz("3"), bz("value3")) + itr := pdb.ReverseIterator([]byte("2"), nil) + checkDomain(t, itr, []byte("2"), nil) + checkItem(t, itr, []byte("3"), []byte("value3")) checkNext(t, itr, true) - checkItem(t, itr, bz("2"), bz("value2")) + checkItem(t, itr, []byte("2"), []byte("value2")) checkNext(t, itr, false) checkInvalid(t, itr) itr.Close() @@ -189,11 +189,11 @@ func TestPrefixDBReverseIterator7(t *testing.T) { db := mockDBWithStuff() pdb := NewPrefixDB(db, "key") - itr := pdb.ReverseIterator(nil, bz("2")) - checkDomain(t, itr, nil, bz("2")) - checkItem(t, itr, bz("1"), bz("value1")) + itr := pdb.ReverseIterator(nil, []byte("2")) + checkDomain(t, itr, nil, []byte("2")) + checkItem(t, itr, []byte("1"), []byte("value1")) checkNext(t, itr, true) - checkItem(t, itr, bz(""), bz("value")) + checkItem(t, itr, []byte(""), []byte("value")) checkNext(t, itr, false) checkInvalid(t, itr) itr.Close() diff --git a/storage/rwtree.go b/storage/rwtree.go index ce7cb6666..7dce9f4fd 100644 --- a/storage/rwtree.go +++ b/storage/rwtree.go @@ -9,6 +9,9 @@ import ( "github.com/xlab/treeprint" ) +// RWTree provides an abstraction over IAVL that maintains separate read and write paths. Reads are routed to the most +// recently saved version of the tree - which provides immutable access. Writes are routed to a working tree that is +// mutable. On save the working tree is saved to DB, frozen, and replaces the previous immutable read tree. type RWTree struct { // Working tree accumulating writes tree *MutableTree diff --git a/storage/rwtree_test.go b/storage/rwtree_test.go index 2de7292dd..dd5afc2d5 100644 --- a/storage/rwtree_test.go +++ b/storage/rwtree_test.go @@ -13,14 +13,15 @@ import ( func TestSave(t *testing.T) { db := dbm.NewMemDB() rwt := NewRWTree(db, 100) - foo := bz("foo") - gaa := bz("gaa") - dam := bz("dam") + foo := []byte("foo") + gaa := []byte("gaa") + dam := []byte("dam") rwt.Set(foo, gaa) - rwt.Save() + _, _, err := rwt.Save() + require.NoError(t, err) assert.Equal(t, gaa, rwt.Get(foo)) rwt.Set(foo, dam) - _, _, err := rwt.Save() + _, _, err = rwt.Save() require.NoError(t, err) assert.Equal(t, dam, rwt.Get(foo)) } @@ -34,12 +35,13 @@ func TestEmptyTree(t *testing.T) { func TestRollback(t *testing.T) { db := dbm.NewMemDB() rwt := NewRWTree(db, 100) - rwt.Set(bz("Raffle"), bz("Topper")) + rwt.Set([]byte("Raffle"), []byte("Topper")) _, _, err := rwt.Save() + require.NoError(t, err) - foo := bz("foo") - gaa := bz("gaa") - dam := bz("dam") + foo := []byte("foo") + gaa := []byte("gaa") + dam := []byte("dam") rwt.Set(foo, gaa) hash1, version1, err := rwt.Save() require.NoError(t, err) @@ -48,7 +50,8 @@ func TestRollback(t *testing.T) { rwt.Set(foo, gaa) rwt.Set(gaa, dam) hash2, version2, err := rwt.Save() - rwt.Iterate(nil, nil, true, func(key, value []byte) error { + require.NoError(t, err) + err = rwt.Iterate(nil, nil, true, func(key, value []byte) error { fmt.Println(string(key), " => ", string(value)) return nil }) @@ -66,10 +69,11 @@ func TestRollback(t *testing.T) { rwt.Set(gaa, dam) hash3, version3, err := rwt.Save() require.NoError(t, err) - rwt.Iterate(nil, nil, true, func(key, value []byte) error { + err = rwt.Iterate(nil, nil, true, func(key, value []byte) error { fmt.Println(string(key), " => ", string(value)) return nil }) + require.NoError(t, err) // Expect the same hashes assert.Equal(t, hash2, hash3) @@ -79,18 +83,18 @@ func TestRollback(t *testing.T) { func TestVersionDivergence(t *testing.T) { // This test serves as a reminder that IAVL nodes contain the version and a new node is created for every write rwt1 := NewRWTree(dbm.NewMemDB(), 100) - rwt1.Set(bz("Raffle"), bz("Topper")) + rwt1.Set([]byte("Raffle"), []byte("Topper")) hash11, _, err := rwt1.Save() require.NoError(t, err) rwt2 := NewRWTree(dbm.NewMemDB(), 100) - rwt2.Set(bz("Raffle"), bz("Topper")) + rwt2.Set([]byte("Raffle"), []byte("Topper")) hash21, _, err := rwt2.Save() require.NoError(t, err) // The following 'ought' to be idempotent but isn't since it replaces the previous node with an identical one, but // with an incremented version number - rwt2.Set(bz("Raffle"), bz("Topper")) + rwt2.Set([]byte("Raffle"), []byte("Topper")) hash22, _, err := rwt2.Save() require.NoError(t, err) @@ -100,24 +104,24 @@ func TestVersionDivergence(t *testing.T) { func TestMutableTree_Iterate(t *testing.T) { mut := NewMutableTree(dbm.NewMemDB(), 100) - mut.Set(bz("aa"), bz("1")) - mut.Set(bz("aab"), bz("2")) - mut.Set(bz("aac"), bz("3")) - mut.Set(bz("aad"), bz("4")) - mut.Set(bz("ab"), bz("5")) + mut.Set([]byte("aa"), []byte("1")) + mut.Set([]byte("aab"), []byte("2")) + mut.Set([]byte("aac"), []byte("3")) + mut.Set([]byte("aad"), []byte("4")) + mut.Set([]byte("ab"), []byte("5")) _, _, err := mut.SaveVersion() require.NoError(t, err) - mut.IterateRange(bz("aab"), bz("aad"), true, func(key []byte, value []byte) bool { + mut.IterateRange([]byte("aab"), []byte("aad"), true, func(key []byte, value []byte) bool { fmt.Printf("%q -> %q\n", key, value) return false }) fmt.Println("foo") - mut.IterateRange(bz("aab"), bz("aad"), false, func(key []byte, value []byte) bool { + mut.IterateRange([]byte("aab"), []byte("aad"), false, func(key []byte, value []byte) bool { fmt.Printf("%q -> %q\n", key, value) return false }) fmt.Println("foo") - mut.IterateRange(bz("aad"), bz("aab"), true, func(key []byte, value []byte) bool { + mut.IterateRange([]byte("aad"), []byte("aab"), true, func(key []byte, value []byte) bool { fmt.Printf("%q -> %q\n", key, value) return false }) diff --git a/storage/mutable_tree.go b/storage/tree.go similarity index 76% rename from storage/mutable_tree.go rename to storage/tree.go index 045790c23..a216d3814 100644 --- a/storage/mutable_tree.go +++ b/storage/tree.go @@ -7,10 +7,15 @@ import ( dbm "github.com/tendermint/tendermint/libs/db" ) +// We wrap IAVL's tree types in order to implement standard DB interface and iteration helpers type MutableTree struct { *iavl.MutableTree } +type ImmutableTree struct { + *iavl.ImmutableTree +} + func NewMutableTree(db dbm.DB, cacheSize int) *MutableTree { tree := iavl.NewMutableTree(db, cacheSize) return &MutableTree{ @@ -39,6 +44,19 @@ func (mut *MutableTree) Load(version int64, overwriting bool) error { return nil } +func (mut *MutableTree) Iterate(start, end []byte, ascending bool, fn func(key []byte, value []byte) error) error { + return mut.asImmutable().Iterate(start, end, ascending, fn) +} + +func (mut *MutableTree) IterateWriteTree(start, end []byte, ascending bool, fn func(key []byte, value []byte) error) error { + var err error + mut.MutableTree.IterateRange(start, end, ascending, func(key, value []byte) (stop bool) { + err = fn(key, value) + return err != nil + }) + return err +} + func (mut *MutableTree) Get(key []byte) []byte { _, bs := mut.MutableTree.Get(key) return bs @@ -52,24 +70,21 @@ func (mut *MutableTree) GetImmutable(version int64) (*ImmutableTree, error) { return &ImmutableTree{tree}, nil } -// Get the current working tree as an ImmutableTree (for the methods - not immutable!) -func (mut *MutableTree) asImmutable() *ImmutableTree { - return &ImmutableTree{mut.MutableTree.ImmutableTree} -} - -func (mut *MutableTree) Iterate(start, end []byte, ascending bool, fn func(key []byte, value []byte) error) error { - return mut.asImmutable().Iterate(start, end, ascending, fn) +func (imt *ImmutableTree) Get(key []byte) []byte { + _, value := imt.ImmutableTree.Get(key) + return value } -func (mut *MutableTree) IterateWriteTree(start, end []byte, ascending bool, fn func(key []byte, value []byte) error) error { +func (imt *ImmutableTree) Iterate(start, end []byte, ascending bool, fn func(key []byte, value []byte) error) error { var err error - mut.MutableTree.IterateRange(start, end, ascending, func(key, value []byte) bool { + imt.ImmutableTree.IterateRange(start, end, ascending, func(key, value []byte) bool { err = fn(key, value) - if err != nil { - // stop - return true - } - return false + return err != nil }) return err } + +// Get the current working tree as an ImmutableTree (for the methods - not immutable!) +func (mut *MutableTree) asImmutable() *ImmutableTree { + return &ImmutableTree{mut.MutableTree.ImmutableTree} +} diff --git a/sync/ring_mutex.go b/sync/ring_mutex.go index 514bc3d39..d722687cb 100644 --- a/sync/ring_mutex.go +++ b/sync/ring_mutex.go @@ -45,8 +45,8 @@ func NewRingMutex(mutexCount int, hashMaker func() hash.Hash64) *RingMutex { ringMutex := &RingMutex{ mutexCount: uint64(mutexCount), // max slice length is bounded by max(int) thus the argument type - mutexes: make([]sync.RWMutex, mutexCount, mutexCount), - values: make([]Value, mutexCount, mutexCount), + mutexes: make([]sync.RWMutex, mutexCount), + values: make([]Value, mutexCount), hash: func(address []byte) uint64 { buf := make([]byte, 8) copy(buf, address) diff --git a/txs/json_codec_test.go b/txs/json_codec_test.go index 3ea74d06b..1c10c8568 100644 --- a/txs/json_codec_test.go +++ b/txs/json_codec_test.go @@ -52,6 +52,7 @@ func TestJSONEncodeTxDecodeTx_CallTx(t *testing.T) { Fee: 2, Address: nil, Data: []byte("code"), + WASM: []byte("wasm"), } txEnv := Enclose(chainID, tx) require.NoError(t, txEnv.Sign(inputAccount)) diff --git a/txs/payload/bond_tx.go b/txs/payload/bond_tx.go index d33f8b6ac..1aeb83f38 100644 --- a/txs/payload/bond_tx.go +++ b/txs/payload/bond_tx.go @@ -33,7 +33,7 @@ func (tx *BondTx) AddInput(st acmstate.AccountGetter, pubkey crypto.PublicKey, a return err } if acc == nil { - return fmt.Errorf("Invalid address %s from pubkey %s", addr, pubkey) + return fmt.Errorf("invalid address %s from pubkey %s", addr, pubkey) } return tx.AddInputWithSequence(pubkey, amt, acc.Sequence+uint64(1)) } diff --git a/txs/payload/payload.go b/txs/payload/payload.go index 1cdcacb85..cd2170580 100644 --- a/txs/payload/payload.go +++ b/txs/payload/payload.go @@ -42,6 +42,15 @@ const ( TypeProposal = Type(0x23) ) +type Payload interface { + String() string + GetInputs() []*TxInput + Type() Type + Any() *Any + // The serialised size in bytes + Size() int +} + var nameFromType = map[Type]string{ TypeUnknown: "UnknownTx", TypeSend: "SendTx", @@ -93,15 +102,6 @@ func (typ *Type) Unmarshal(data []byte) error { return typ.UnmarshalText(data) } -type Payload interface { - String() string - GetInputs() []*TxInput - Type() Type - Any() *Any - // The serialised size in bytes - Size() int -} - func InputsString(inputs []*TxInput) string { strs := make([]string, len(inputs)) for i, in := range inputs { diff --git a/txs/payload/payload.pb.go b/txs/payload/payload.pb.go index 7d8e45569..c99de74e1 100644 --- a/txs/payload/payload.pb.go +++ b/txs/payload/payload.pb.go @@ -301,8 +301,10 @@ type CallTx struct { GasLimit uint64 `protobuf:"varint,3,opt,name=GasLimit,proto3" json:"GasLimit,omitempty"` // Fee to offer validators for processing transaction Fee uint64 `protobuf:"varint,4,opt,name=Fee,proto3" json:"Fee,omitempty"` - // EVM bytecode payload - Data github_com_hyperledger_burrow_binary.HexBytes `protobuf:"bytes,5,opt,name=Data,proto3,customtype=github.com/hyperledger/burrow/binary.HexBytes" json:"Data"` + // EVM bytecode + Data github_com_hyperledger_burrow_binary.HexBytes `protobuf:"bytes,5,opt,name=Data,proto3,customtype=github.com/hyperledger/burrow/binary.HexBytes" json:"Data"` + // WASM bytecode + WASM github_com_hyperledger_burrow_binary.HexBytes `protobuf:"bytes,6,opt,name=WASM,proto3,customtype=github.com/hyperledger/burrow/binary.HexBytes" json:"tags,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -970,67 +972,69 @@ func init() { proto.RegisterFile("payload.proto", fileDescriptor_678c914f1bee6d5 func init() { golang_proto.RegisterFile("payload.proto", fileDescriptor_678c914f1bee6d56) } var fileDescriptor_678c914f1bee6d56 = []byte{ - // 958 bytes of a gzipped FileDescriptorProto + // 991 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0x4b, 0x6f, 0x23, 0x45, - 0x10, 0x4e, 0x67, 0xc6, 0x8f, 0xad, 0x75, 0x82, 0xb7, 0x79, 0xc8, 0x8a, 0x84, 0xbd, 0x32, 0x08, - 0x96, 0x47, 0x6c, 0xd8, 0xe5, 0x21, 0xe5, 0x82, 0x3c, 0xb1, 0xb3, 0x09, 0x5a, 0x25, 0x51, 0x67, - 0xb2, 0x20, 0x24, 0x0e, 0x63, 0xbb, 0xb1, 0x47, 0x8c, 0xa7, 0x87, 0x99, 0xf6, 0x32, 0xe6, 0xc4, - 0x81, 0x03, 0x57, 0xc4, 0x85, 0x63, 0x0e, 0xfc, 0x01, 0xfe, 0x01, 0xc7, 0x1c, 0x39, 0x73, 0x58, - 0xa1, 0xec, 0x85, 0xff, 0xc0, 0x05, 0x75, 0x4f, 0xf7, 0xb8, 0xed, 0x85, 0x5d, 0x27, 0xa0, 0xbd, - 0x4d, 0x55, 0x7d, 0xdd, 0x55, 0xf5, 0xd5, 0xa3, 0x07, 0x36, 0x22, 0x6f, 0x16, 0x30, 0x6f, 0xd8, - 0x8a, 0x62, 0xc6, 0x19, 0x2e, 0x29, 0x71, 0x6b, 0x7b, 0xe4, 0xf3, 0xf1, 0xb4, 0xdf, 0x1a, 0xb0, - 0x49, 0x7b, 0xc4, 0x46, 0xac, 0x2d, 0xed, 0xfd, 0xe9, 0x17, 0x52, 0x92, 0x82, 0xfc, 0xca, 0xce, - 0x6d, 0x55, 0x23, 0x1a, 0x4f, 0xfc, 0x24, 0xf1, 0x59, 0xa8, 0x34, 0x90, 0x44, 0x74, 0x90, 0x7d, - 0x37, 0x7f, 0xb0, 0xc0, 0xea, 0x84, 0x33, 0xfc, 0x3a, 0x14, 0x77, 0xbd, 0x20, 0x70, 0xd3, 0x1a, - 0xba, 0x89, 0x6e, 0x5d, 0xbf, 0xfd, 0x5c, 0x4b, 0x7b, 0xcf, 0xd4, 0x44, 0x99, 0x05, 0xf0, 0x84, - 0x86, 0x43, 0x37, 0xad, 0xad, 0x2f, 0x01, 0x33, 0x35, 0x51, 0x66, 0x01, 0x3c, 0xf4, 0x26, 0xd4, - 0x4d, 0x6b, 0xd6, 0x12, 0x30, 0x53, 0x13, 0x65, 0xc6, 0x6f, 0x42, 0xe9, 0x98, 0xc6, 0x93, 0xc4, - 0x4d, 0x6b, 0xb6, 0x44, 0x56, 0x73, 0xa4, 0xd2, 0x13, 0x0d, 0xc0, 0xaf, 0x42, 0xe1, 0x2e, 0x7b, - 0xe0, 0xa6, 0xb5, 0x82, 0x44, 0x6e, 0xe6, 0x48, 0xa9, 0x25, 0x99, 0x51, 0xb8, 0x76, 0x98, 0x8c, - 0xb1, 0xb8, 0xe4, 0x3a, 0x53, 0x13, 0x65, 0xc6, 0xdb, 0x50, 0x3e, 0x0d, 0xfb, 0x19, 0xb4, 0x24, - 0xa1, 0x37, 0x72, 0xa8, 0x36, 0x90, 0x1c, 0x22, 0x22, 0x75, 0x3c, 0x3e, 0x18, 0xbb, 0x69, 0xad, - 0xbc, 0x14, 0xa9, 0xd2, 0x13, 0x0d, 0xc0, 0x77, 0x00, 0x8e, 0x63, 0x16, 0xb1, 0xc4, 0x13, 0xa4, - 0x5e, 0x93, 0xf0, 0xe7, 0xe7, 0x89, 0xe5, 0x26, 0x62, 0xc0, 0x76, 0xec, 0xf3, 0xb3, 0x06, 0x6a, - 0xfe, 0x88, 0xa0, 0xe4, 0xa6, 0x07, 0x61, 0x34, 0xe5, 0xf8, 0x10, 0x4a, 0x9d, 0xe1, 0x30, 0xa6, - 0x49, 0x22, 0x0b, 0x53, 0x71, 0xde, 0x3b, 0x7f, 0xd8, 0x58, 0xfb, 0xfd, 0x61, 0xe3, 0x6d, 0xa3, - 0x0b, 0xc6, 0xb3, 0x88, 0xc6, 0x01, 0x1d, 0x8e, 0x68, 0xdc, 0xee, 0x4f, 0xe3, 0x98, 0x7d, 0xdd, - 0x1e, 0xc4, 0xb3, 0x88, 0xb3, 0x96, 0x3a, 0x4b, 0xf4, 0x25, 0xf8, 0x25, 0x28, 0x76, 0x26, 0x6c, - 0x1a, 0x72, 0x59, 0x3e, 0x9b, 0x28, 0x09, 0x6f, 0x41, 0xf9, 0x84, 0x7e, 0x35, 0xa5, 0xe1, 0x80, - 0xca, 0x7a, 0xd9, 0x24, 0x97, 0x77, 0xec, 0x9f, 0xce, 0x1a, 0x6b, 0xcd, 0x14, 0xca, 0x6e, 0x7a, - 0x34, 0xe5, 0xcf, 0x30, 0x2a, 0xe5, 0xf9, 0x2f, 0xa4, 0x9b, 0x13, 0xbf, 0x06, 0x05, 0xc9, 0x8b, - 0xea, 0xd2, 0x39, 0xff, 0x8a, 0x2f, 0x92, 0x99, 0xf1, 0xc7, 0xf3, 0x00, 0xd7, 0x65, 0x80, 0xef, - 0x5c, 0x3d, 0xb8, 0x2d, 0x28, 0xdf, 0xf5, 0x92, 0x7b, 0xfe, 0xc4, 0xe7, 0x9a, 0x1a, 0x2d, 0xe3, - 0x2a, 0x58, 0x7b, 0x94, 0xca, 0xbe, 0xb5, 0x89, 0xf8, 0xc4, 0x07, 0x60, 0x77, 0x3d, 0xee, 0xc9, - 0x06, 0xad, 0x38, 0xef, 0x2b, 0x5e, 0xb6, 0x9f, 0xec, 0xba, 0xef, 0x87, 0x5e, 0x3c, 0x6b, 0xed, - 0xd3, 0xd4, 0x99, 0x71, 0x9a, 0x10, 0x79, 0x85, 0xca, 0xde, 0xd7, 0x03, 0x87, 0x6f, 0x41, 0x51, - 0x66, 0x27, 0x48, 0xb7, 0xfe, 0x31, 0x7b, 0x65, 0xc7, 0x6f, 0x41, 0x29, 0xab, 0x94, 0x48, 0xdf, - 0x5a, 0x68, 0x6b, 0x5d, 0x43, 0xa2, 0x11, 0x3b, 0xe5, 0xef, 0xcf, 0x1a, 0x6b, 0xd2, 0x15, 0xcb, - 0x27, 0x71, 0x65, 0xa2, 0x3f, 0x80, 0xb2, 0x38, 0xd2, 0x89, 0x47, 0x89, 0x5a, 0x08, 0x2f, 0xb4, - 0x8c, 0x85, 0xa3, 0x6d, 0x8e, 0x2d, 0x88, 0x20, 0x39, 0x56, 0xe5, 0x16, 0xe9, 0x1d, 0xb1, 0xb2, - 0x3f, 0x0c, 0xb6, 0x38, 0x21, 0x7d, 0x5d, 0x23, 0xf2, 0x5b, 0xe8, 0x24, 0xe5, 0x56, 0xa6, 0x13, - 0xdf, 0x8f, 0x17, 0x46, 0x79, 0xfc, 0x52, 0xaf, 0x86, 0x4b, 0xb0, 0x39, 0xdf, 0x12, 0xec, 0xdf, - 0xe9, 0xcc, 0x21, 0x06, 0x9f, 0x3f, 0xa3, 0xf9, 0x7e, 0x59, 0x39, 0xc3, 0xc3, 0xe5, 0xd6, 0xfd, - 0xef, 0xb3, 0xb5, 0x4f, 0xfd, 0xd1, 0x58, 0x37, 0xaf, 0x92, 0x8c, 0x30, 0xbf, 0x45, 0x6a, 0xab, - 0x5e, 0x82, 0x93, 0x5d, 0xd8, 0xec, 0x0c, 0x06, 0x62, 0x48, 0x4f, 0xa3, 0xa1, 0xc7, 0xa9, 0x6e, - 0xb4, 0x17, 0x5b, 0xf2, 0x71, 0x71, 0xe9, 0x24, 0x0a, 0x3c, 0x4e, 0x15, 0x46, 0x96, 0x1f, 0x91, - 0xa5, 0x23, 0x46, 0x08, 0x7f, 0x22, 0x73, 0x5d, 0xae, 0xcc, 0x55, 0x13, 0x2a, 0xf7, 0x19, 0xf7, - 0xc3, 0xd1, 0x27, 0x59, 0x86, 0x82, 0x30, 0x8b, 0x2c, 0xe8, 0xf0, 0x29, 0x54, 0xf4, 0xcd, 0xfb, - 0x5e, 0x32, 0x96, 0x2c, 0x54, 0x9c, 0x77, 0x2f, 0x3f, 0x94, 0x0b, 0xd7, 0x88, 0xa6, 0xd0, 0xb2, - 0x7a, 0xb6, 0x6e, 0x3c, 0xb6, 0xdd, 0x49, 0x0e, 0x31, 0x52, 0xfd, 0x3c, 0x7f, 0x44, 0x2e, 0x41, - 0x77, 0x1d, 0x2c, 0x37, 0xd5, 0x1c, 0x57, 0x72, 0x58, 0x27, 0x9c, 0x11, 0x61, 0x30, 0xae, 0xff, - 0x0e, 0x81, 0x7d, 0x9f, 0x71, 0xfa, 0xbf, 0xef, 0xe8, 0x15, 0xb8, 0x36, 0xc2, 0x78, 0x30, 0xa7, - 0x27, 0x9f, 0x59, 0x64, 0xcc, 0xec, 0x4d, 0xb8, 0xde, 0xa5, 0xc9, 0x20, 0xf6, 0x23, 0xee, 0xb3, - 0x50, 0x8d, 0xb3, 0xa9, 0x32, 0x1f, 0x5b, 0xeb, 0x29, 0x8f, 0xad, 0xe1, 0xf7, 0x97, 0x75, 0x28, - 0x3a, 0x5e, 0x10, 0x30, 0xbe, 0x50, 0x21, 0xf4, 0xd4, 0x0a, 0x89, 0x3e, 0xd9, 0xf3, 0x43, 0x2f, - 0xf0, 0xbf, 0xf1, 0xc3, 0x91, 0xfa, 0xbd, 0xb9, 0x5a, 0x9f, 0x98, 0xd7, 0xe0, 0x5d, 0xd8, 0x88, - 0x94, 0x8b, 0x13, 0xee, 0xf1, 0x6c, 0x25, 0x6d, 0xde, 0x7e, 0xd9, 0x48, 0x46, 0x44, 0x9b, 0x47, - 0x24, 0x41, 0x64, 0xf1, 0x0c, 0x7e, 0x05, 0x0a, 0xa2, 0xa6, 0x49, 0xad, 0x20, 0x1b, 0x60, 0x23, - 0x3f, 0x2c, 0xb4, 0x24, 0xb3, 0x35, 0x3f, 0x84, 0x8d, 0x85, 0x4b, 0x70, 0x05, 0xca, 0xc7, 0xe4, - 0xe8, 0xf8, 0xe8, 0xa4, 0xd7, 0xad, 0xae, 0x09, 0xa9, 0xf7, 0x69, 0x6f, 0xf7, 0xd4, 0xed, 0x75, - 0xab, 0x08, 0x03, 0x14, 0xf7, 0x3a, 0x07, 0xf7, 0x7a, 0xdd, 0xea, 0xba, 0xf3, 0xd1, 0xf9, 0x45, - 0x1d, 0xfd, 0x76, 0x51, 0x47, 0x7f, 0x5c, 0xd4, 0xd1, 0xaf, 0x8f, 0xea, 0xe8, 0xfc, 0x51, 0x1d, - 0x7d, 0xf6, 0xc6, 0x93, 0xb3, 0xe6, 0x69, 0xd2, 0x56, 0x51, 0xf4, 0x8b, 0xf2, 0x5f, 0xf2, 0xce, - 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xa2, 0x4c, 0xec, 0xa1, 0xb2, 0x0a, 0x00, 0x00, + 0x10, 0xce, 0x78, 0xc6, 0x8f, 0xad, 0x75, 0x82, 0xb7, 0x79, 0xc8, 0x8a, 0x84, 0xbd, 0x32, 0x08, + 0x16, 0xd8, 0xd8, 0xb0, 0xcb, 0x43, 0xca, 0x05, 0x79, 0x62, 0xe7, 0x81, 0x96, 0x24, 0x6a, 0x4f, + 0x76, 0x11, 0x88, 0x43, 0xdb, 0x6e, 0xec, 0x11, 0x9e, 0xe9, 0x61, 0xa6, 0xbd, 0x8c, 0x39, 0x71, + 0xe0, 0xc0, 0x15, 0x71, 0xe1, 0x98, 0x03, 0x7f, 0x80, 0x7f, 0xc0, 0x31, 0x47, 0x8e, 0x88, 0x43, + 0x84, 0xb2, 0x17, 0xc4, 0xaf, 0x40, 0xdd, 0xd3, 0x3d, 0x1e, 0x7b, 0x61, 0xd7, 0x09, 0x88, 0xdb, + 0x54, 0xd5, 0xd7, 0x55, 0xd5, 0x5f, 0x3d, 0x7a, 0x60, 0x3d, 0x20, 0xb3, 0x09, 0x23, 0xc3, 0x66, + 0x10, 0x32, 0xce, 0x50, 0x51, 0x89, 0x9b, 0x5b, 0x23, 0x97, 0x8f, 0xa7, 0xfd, 0xe6, 0x80, 0x79, + 0xad, 0x11, 0x1b, 0xb1, 0x96, 0xb4, 0xf7, 0xa7, 0x9f, 0x49, 0x49, 0x0a, 0xf2, 0x2b, 0x39, 0xb7, + 0x59, 0x09, 0x68, 0xe8, 0xb9, 0x51, 0xe4, 0x32, 0x5f, 0x69, 0x20, 0x0a, 0xe8, 0x20, 0xf9, 0x6e, + 0x7c, 0x67, 0x82, 0xd9, 0xf6, 0x67, 0xe8, 0x55, 0x28, 0xec, 0x90, 0xc9, 0xc4, 0x89, 0xab, 0xc6, + 0x4d, 0xe3, 0xd6, 0xf5, 0x3b, 0xcf, 0x34, 0x75, 0xf4, 0x44, 0x8d, 0x95, 0x59, 0x00, 0x7b, 0xd4, + 0x1f, 0x3a, 0x71, 0x35, 0xb7, 0x04, 0x4c, 0xd4, 0x58, 0x99, 0x05, 0xf0, 0x90, 0x78, 0xd4, 0x89, + 0xab, 0xe6, 0x12, 0x30, 0x51, 0x63, 0x65, 0x46, 0xaf, 0x43, 0xf1, 0x98, 0x86, 0x5e, 0xe4, 0xc4, + 0x55, 0x4b, 0x22, 0x2b, 0x29, 0x52, 0xe9, 0xb1, 0x06, 0xa0, 0x97, 0x21, 0xbf, 0xc7, 0x1e, 0x3a, + 0x71, 0x35, 0x2f, 0x91, 0x1b, 0x29, 0x52, 0x6a, 0x71, 0x62, 0x14, 0xa1, 0x6d, 0x26, 0x73, 0x2c, + 0x2c, 0x85, 0x4e, 0xd4, 0x58, 0x99, 0xd1, 0x16, 0x94, 0x4e, 0xfc, 0x7e, 0x02, 0x2d, 0x4a, 0xe8, + 0x8d, 0x14, 0xaa, 0x0d, 0x38, 0x85, 0x88, 0x4c, 0x6d, 0xc2, 0x07, 0x63, 0x27, 0xae, 0x96, 0x96, + 0x32, 0x55, 0x7a, 0xac, 0x01, 0xe8, 0x2e, 0xc0, 0x71, 0xc8, 0x02, 0x16, 0x11, 0x41, 0xea, 0x35, + 0x09, 0x7f, 0x76, 0x7e, 0xb1, 0xd4, 0x84, 0x33, 0xb0, 0x6d, 0xeb, 0xec, 0xb4, 0x6e, 0x34, 0xbe, + 0x37, 0xa0, 0xe8, 0xc4, 0x07, 0x7e, 0x30, 0xe5, 0xe8, 0x10, 0x8a, 0xed, 0xe1, 0x30, 0xa4, 0x51, + 0x24, 0x0b, 0x53, 0xb6, 0xdf, 0x3e, 0x3b, 0xaf, 0xaf, 0xfd, 0x76, 0x5e, 0xbf, 0x9d, 0xe9, 0x82, + 0xf1, 0x2c, 0xa0, 0xe1, 0x84, 0x0e, 0x47, 0x34, 0x6c, 0xf5, 0xa7, 0x61, 0xc8, 0xbe, 0x6c, 0x0d, + 0xc2, 0x59, 0xc0, 0x59, 0x53, 0x9d, 0xc5, 0xda, 0x09, 0x7a, 0x01, 0x0a, 0x6d, 0x8f, 0x4d, 0x7d, + 0x2e, 0xcb, 0x67, 0x61, 0x25, 0xa1, 0x4d, 0x28, 0xf5, 0xe8, 0x17, 0x53, 0xea, 0x0f, 0xa8, 0xac, + 0x97, 0x85, 0x53, 0x79, 0xdb, 0xfa, 0xe1, 0xb4, 0xbe, 0xd6, 0x88, 0xa1, 0xe4, 0xc4, 0x47, 0x53, + 0xfe, 0x3f, 0x66, 0xa5, 0x22, 0xff, 0x9a, 0xd3, 0xcd, 0x89, 0x5e, 0x81, 0xbc, 0xe4, 0x45, 0x75, + 0xe9, 0x9c, 0x7f, 0xc5, 0x17, 0x4e, 0xcc, 0xe8, 0x83, 0x79, 0x82, 0x39, 0x99, 0xe0, 0x9b, 0x57, + 0x4f, 0x6e, 0x13, 0x4a, 0x7b, 0x24, 0xba, 0xe7, 0x7a, 0x2e, 0xd7, 0xd4, 0x68, 0x19, 0x55, 0xc0, + 0xdc, 0xa5, 0x54, 0xf6, 0xad, 0x85, 0xc5, 0x27, 0x3a, 0x00, 0xab, 0x43, 0x38, 0x91, 0x0d, 0x5a, + 0xb6, 0xdf, 0x51, 0xbc, 0x6c, 0x3d, 0x39, 0x74, 0xdf, 0xf5, 0x49, 0x38, 0x6b, 0xee, 0xd3, 0xd8, + 0x9e, 0x71, 0x1a, 0x61, 0xe9, 0x02, 0x7d, 0x02, 0xd6, 0x83, 0x76, 0xef, 0x43, 0xd9, 0xc4, 0x65, + 0x7b, 0xef, 0x4a, 0xae, 0xfe, 0x3c, 0xaf, 0x6f, 0x70, 0x32, 0x8a, 0x6e, 0x33, 0xcf, 0xe5, 0xd4, + 0x0b, 0xf8, 0x0c, 0x4b, 0xa7, 0x8a, 0x5a, 0x57, 0x4f, 0x33, 0xba, 0x05, 0x05, 0x49, 0x9d, 0xa8, + 0xa8, 0xf9, 0xb7, 0xd4, 0x2a, 0x3b, 0x7a, 0x03, 0x8a, 0x49, 0x1b, 0x08, 0x6e, 0xcd, 0x85, 0x99, + 0xd1, 0x0d, 0x82, 0x35, 0x62, 0xbb, 0xf4, 0xed, 0x69, 0x7d, 0x4d, 0x86, 0x62, 0xe9, 0x98, 0xaf, + 0x5c, 0xc5, 0x77, 0xa1, 0x24, 0x8e, 0xb4, 0xc3, 0x51, 0xa4, 0xb6, 0xcd, 0x73, 0xcd, 0xcc, 0x36, + 0xd3, 0x36, 0xdb, 0x12, 0xd4, 0xe0, 0x14, 0xab, 0xee, 0x16, 0xe8, 0x05, 0xb4, 0x72, 0x3c, 0x04, + 0x96, 0x38, 0x21, 0x63, 0x5d, 0xc3, 0xf2, 0x5b, 0xe8, 0x64, 0x3d, 0xcd, 0x44, 0x27, 0x0b, 0xf3, + 0x58, 0xd5, 0x55, 0xc4, 0xcf, 0xf5, 0xde, 0xb9, 0x04, 0x9b, 0xf3, 0x15, 0xc4, 0xfe, 0x99, 0xce, + 0x14, 0x92, 0xe1, 0xf3, 0x47, 0x63, 0xbe, 0xbc, 0x56, 0xbe, 0xe1, 0xe1, 0xf2, 0x5c, 0xfc, 0xfb, + 0xc1, 0xdd, 0xa7, 0xee, 0x68, 0xac, 0x27, 0x43, 0x49, 0x99, 0x34, 0xbf, 0x36, 0xd4, 0xca, 0xbe, + 0x04, 0x27, 0x3b, 0xb0, 0xd1, 0x1e, 0x0c, 0xc4, 0x06, 0x38, 0x09, 0x86, 0x84, 0x53, 0xdd, 0x68, + 0xcf, 0x37, 0xe5, 0xcb, 0xe5, 0x50, 0x2f, 0x98, 0x10, 0x4e, 0x15, 0x46, 0x96, 0xdf, 0xc0, 0x4b, + 0x47, 0x32, 0x29, 0xfc, 0x61, 0x64, 0x77, 0xf1, 0xca, 0x5c, 0x35, 0xa0, 0x7c, 0x9f, 0x71, 0xd7, + 0x1f, 0x3d, 0x48, 0x6e, 0x28, 0x08, 0x33, 0xf1, 0x82, 0x0e, 0x9d, 0x40, 0x59, 0x7b, 0xde, 0x27, + 0xd1, 0x58, 0xb2, 0x50, 0xb6, 0xdf, 0xba, 0xfc, 0xc4, 0x2f, 0xb8, 0x11, 0x4d, 0xa1, 0x65, 0xf5, + 0x26, 0xde, 0x78, 0xec, 0xe9, 0xc0, 0x29, 0x24, 0x73, 0xd5, 0x4f, 0xd3, 0x17, 0xea, 0x12, 0x74, + 0xd7, 0xc0, 0x74, 0x62, 0xcd, 0x71, 0x39, 0x85, 0xb5, 0xfd, 0x19, 0x16, 0x86, 0x8c, 0xfb, 0x6f, + 0x0c, 0xb0, 0xee, 0x33, 0x4e, 0xff, 0xf3, 0x07, 0x60, 0x05, 0xae, 0x33, 0x69, 0x3c, 0x9c, 0xd3, + 0x93, 0xce, 0xac, 0x91, 0x99, 0xd9, 0x9b, 0x70, 0xbd, 0x43, 0xa3, 0x41, 0xe8, 0x06, 0xdc, 0x65, + 0xbe, 0x1a, 0xe7, 0xac, 0x2a, 0xfb, 0x92, 0x9b, 0x4f, 0x79, 0xc9, 0x33, 0x71, 0x7f, 0xca, 0x41, + 0xc1, 0x26, 0x93, 0x09, 0xe3, 0x0b, 0x15, 0x32, 0x9e, 0x5a, 0x21, 0xd1, 0x27, 0xbb, 0xae, 0x4f, + 0x26, 0xee, 0x57, 0xae, 0x3f, 0x52, 0xff, 0x4e, 0x57, 0xeb, 0x93, 0xac, 0x1b, 0xb4, 0x03, 0xeb, + 0x81, 0x0a, 0xd1, 0xe3, 0x84, 0x27, 0x2b, 0x69, 0xe3, 0xce, 0x8b, 0x99, 0xcb, 0x88, 0x6c, 0xd3, + 0x8c, 0x24, 0x08, 0x2f, 0x9e, 0x41, 0x2f, 0x41, 0x5e, 0xd4, 0x34, 0xaa, 0xe6, 0x65, 0x03, 0xac, + 0xa7, 0x87, 0x85, 0x16, 0x27, 0xb6, 0xc6, 0x7b, 0xb0, 0xbe, 0xe0, 0x04, 0x95, 0xa1, 0x74, 0x8c, + 0x8f, 0x8e, 0x8f, 0x7a, 0xdd, 0x4e, 0x65, 0x4d, 0x48, 0xdd, 0x8f, 0xba, 0x3b, 0x27, 0x4e, 0xb7, + 0x53, 0x31, 0x10, 0x40, 0x61, 0xb7, 0x7d, 0x70, 0xaf, 0xdb, 0xa9, 0xe4, 0xec, 0xf7, 0xcf, 0x2e, + 0x6a, 0xc6, 0x2f, 0x17, 0x35, 0xe3, 0xf7, 0x8b, 0x9a, 0xf1, 0xf3, 0xa3, 0x9a, 0x71, 0xf6, 0xa8, + 0x66, 0x7c, 0xfc, 0xda, 0x93, 0x6f, 0xcd, 0xe3, 0xa8, 0xa5, 0xb2, 0xe8, 0x17, 0xe4, 0x8f, 0xea, + 0xdd, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0x02, 0x7a, 0xba, 0xca, 0x0f, 0x0b, 0x00, 0x00, } func (m *Any) Marshal() (dAtA []byte, err error) { @@ -1270,6 +1274,14 @@ func (m *CallTx) MarshalTo(dAtA []byte) (int, error) { return 0, err } i += n14 + dAtA[i] = 0x32 + i++ + i = encodeVarintPayload(dAtA, i, uint64(m.WASM.Size())) + n15, err := m.WASM.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n15 if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) } @@ -1340,20 +1352,20 @@ func (m *PermsTx) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintPayload(dAtA, i, uint64(m.Input.Size())) - n15, err := m.Input.MarshalTo(dAtA[i:]) + n16, err := m.Input.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n15 + i += n16 } dAtA[i] = 0x12 i++ i = encodeVarintPayload(dAtA, i, uint64(m.PermArgs.Size())) - n16, err := m.PermArgs.MarshalTo(dAtA[i:]) + n17, err := m.PermArgs.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n16 + i += n17 if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) } @@ -1379,11 +1391,11 @@ func (m *NameTx) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintPayload(dAtA, i, uint64(m.Input.Size())) - n17, err := m.Input.MarshalTo(dAtA[i:]) + n18, err := m.Input.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n17 + i += n18 } if len(m.Name) > 0 { dAtA[i] = 0x12 @@ -1472,20 +1484,20 @@ func (m *UnbondTx) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintPayload(dAtA, i, uint64(m.Input.Size())) - n18, err := m.Input.MarshalTo(dAtA[i:]) + n19, err := m.Input.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n18 + i += n19 } dAtA[i] = 0x12 i++ i = encodeVarintPayload(dAtA, i, uint64(m.Address.Size())) - n19, err := m.Address.MarshalTo(dAtA[i:]) + n20, err := m.Address.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n19 + i += n20 if m.Height != 0 { dAtA[i] = 0x18 i++ @@ -1561,11 +1573,11 @@ func (m *ProposalTx) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintPayload(dAtA, i, uint64(m.Input.Size())) - n20, err := m.Input.MarshalTo(dAtA[i:]) + n21, err := m.Input.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n20 + i += n21 } if m.VotingWeight != 0 { dAtA[i] = 0x10 @@ -1576,21 +1588,21 @@ func (m *ProposalTx) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x1a i++ i = encodeVarintPayload(dAtA, i, uint64(m.ProposalHash.Size())) - n21, err := m.ProposalHash.MarshalTo(dAtA[i:]) + n22, err := m.ProposalHash.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n21 + i += n22 } if m.Proposal != nil { dAtA[i] = 0x22 i++ i = encodeVarintPayload(dAtA, i, uint64(m.Proposal.Size())) - n22, err := m.Proposal.MarshalTo(dAtA[i:]) + n23, err := m.Proposal.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n22 + i += n23 } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) @@ -1661,11 +1673,11 @@ func (m *Vote) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintPayload(dAtA, i, uint64(m.Address.Size())) - n23, err := m.Address.MarshalTo(dAtA[i:]) + n24, err := m.Address.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n23 + i += n24 if m.VotingWeight != 0 { dAtA[i] = 0x10 i++ @@ -1708,11 +1720,11 @@ func (m *Proposal) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x1a i++ i = encodeVarintPayload(dAtA, i, uint64(m.BatchTx.Size())) - n24, err := m.BatchTx.MarshalTo(dAtA[i:]) + n25, err := m.BatchTx.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n24 + i += n25 } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) @@ -1739,21 +1751,21 @@ func (m *Ballot) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintPayload(dAtA, i, uint64(m.Proposal.Size())) - n25, err := m.Proposal.MarshalTo(dAtA[i:]) + n26, err := m.Proposal.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n25 + i += n26 } if m.FinalizingTx != nil { dAtA[i] = 0x12 i++ i = encodeVarintPayload(dAtA, i, uint64(m.FinalizingTx.Size())) - n26, err := m.FinalizingTx.MarshalTo(dAtA[i:]) + n27, err := m.FinalizingTx.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n26 + i += n27 } if m.ProposalState != 0 { dAtA[i] = 0x20 @@ -1894,6 +1906,8 @@ func (m *CallTx) Size() (n int) { } l = m.Data.Size() n += 1 + l + sovPayload(uint64(l)) + l = m.WASM.Size() + n += 1 + l + sovPayload(uint64(l)) if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -3008,6 +3022,39 @@ func (m *CallTx) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WASM", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPayload + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthPayload + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthPayload + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.WASM.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipPayload(dAtA[iNdEx:]) diff --git a/txs/tx.go b/txs/tx.go index 0e9e4eadb..1e9e17a7c 100644 --- a/txs/tx.go +++ b/txs/tx.go @@ -109,6 +109,9 @@ func (tx *Tx) UnmarshalJSON(data []byte) error { tx.ChainID = w.ChainID // Now we know the Type we can deserialise the Payload tx.Payload, err = payload.New(w.Type) + if err != nil { + return err + } return json.Unmarshal(w.Payload, tx.Payload) } diff --git a/util/fs.go b/util/fs.go index 7979db7e5..f9eea8576 100644 --- a/util/fs.go +++ b/util/fs.go @@ -24,12 +24,12 @@ import ( func EnsureDir(dir string, mode os.FileMode) error { if fileOptions, err := os.Stat(dir); os.IsNotExist(err) { if errMake := os.MkdirAll(dir, mode); errMake != nil { - return fmt.Errorf("Could not create directory %s. %v", dir, err) + return fmt.Errorf("could not create directory %s. %v", dir, err) } } else if err != nil { - return fmt.Errorf("Error asserting directory %s: %v", dir, err) + return fmt.Errorf("error asserting directory %s: %v", dir, err) } else if !fileOptions.IsDir() { - return fmt.Errorf("Path already exists as a file: %s", dir) + return fmt.Errorf("path already exists as a file: %s", dir) } return nil } diff --git a/util/slice/slice.go b/util/slice/slice.go index 485510ff7..945bee4e4 100644 --- a/util/slice/slice.go +++ b/util/slice/slice.go @@ -28,12 +28,8 @@ func EmptySlice() []interface{} { func CopyAppend(slice []interface{}, elements ...interface{}) []interface{} { sliceLength := len(slice) newSlice := make([]interface{}, sliceLength+len(elements)) - for i, e := range slice { - newSlice[i] = e - } - for i, e := range elements { - newSlice[sliceLength+i] = e - } + copy(newSlice, slice) + copy(newSlice[sliceLength:], elements) return newSlice } @@ -41,12 +37,8 @@ func CopyAppend(slice []interface{}, elements ...interface{}) []interface{} { func CopyPrepend(slice []interface{}, elements ...interface{}) []interface{} { elementsLength := len(elements) newSlice := make([]interface{}, len(slice)+elementsLength) - for i, e := range elements { - newSlice[i] = e - } - for i, e := range slice { - newSlice[elementsLength+i] = e - } + copy(newSlice, elements) + copy(newSlice[elementsLength:], slice) return newSlice } @@ -73,11 +65,6 @@ func Delete(slice []interface{}, i int, n int) []interface{} { return append(slice[:i], slice[i+n:]...) } -// Delete an element at a specific index and return the contracted list -func DeleteAt(slice []interface{}, i int) []interface{} { - return Delete(slice, i, 1) -} - // Flatten a slice by a list by splicing any elements of the list that are // themselves lists into the slice elements to the list in place of slice itself func Flatten(slice []interface{}) []interface{} { diff --git a/vent/service/decoder.go b/vent/service/decoder.go index 547aeee90..28c462e5b 100644 --- a/vent/service/decoder.go +++ b/vent/service/decoder.go @@ -21,7 +21,7 @@ func decodeEvent(header *exec.Header, log *exec.LogEvent, origin *exec.Origin, a evAbi, ok := abiSpec.EventsById[eventID] if !ok { - return nil, fmt.Errorf("Abi spec not found for event %x", eventID) + return nil, fmt.Errorf("abi spec not found for event %x", eventID) } // decode header to get context data for each event @@ -36,7 +36,7 @@ func decodeEvent(header *exec.Header, log *exec.LogEvent, origin *exec.Origin, a // unpack event data (topics & data part) if err := abi.UnpackEvent(&evAbi, log.Topics, log.Data, unpackedData...); err != nil { - return nil, errors.Wrap(err, "Could not unpack event data") + return nil, errors.Wrap(err, "could not unpack event data") } // for each decoded item value, stores it in given item name diff --git a/vent/service/rowbuilder.go b/vent/service/rowbuilder.go index 4d4b17bf4..72b8a255d 100644 --- a/vent/service/rowbuilder.go +++ b/vent/service/rowbuilder.go @@ -75,7 +75,7 @@ func buildBlkData(tbls types.EventTables, block *exec.BlockExecution) (types.Eve if _, ok := tbls[tables.Block]; ok { blockHeader, err := json.Marshal(block.Header) if err != nil { - return types.EventDataRow{}, fmt.Errorf("Couldn't marshal BlockHeader in block %v", block) + return types.EventDataRow{}, fmt.Errorf("couldn not marshal BlockHeader in block %v", block) } row[columns.Height] = fmt.Sprintf("%v", block.Height) diff --git a/vent/sqldb/adapters/postgres_adapter.go b/vent/sqldb/adapters/postgres_adapter.go index 1fc434231..a0e99a6f7 100644 --- a/vent/sqldb/adapters/postgres_adapter.go +++ b/vent/sqldb/adapters/postgres_adapter.go @@ -57,6 +57,9 @@ func (pa *PostgresAdapter) Open(dbURL string) (*sqlx.DB, error) { if pa.Schema != "" { err = ensureSchema(db, pa.Schema, pa.Log) + if err != nil { + return nil, err + } } else { return nil, fmt.Errorf("no schema supplied") } diff --git a/vent/sqlsol/projection.go b/vent/sqlsol/projection.go index 8dca7e4a0..d8b2a6d7a 100644 --- a/vent/sqlsol/projection.go +++ b/vent/sqlsol/projection.go @@ -256,7 +256,7 @@ func getSQLType(evmSignature string, bytesToString bool) (types.SQLColumnType, i return types.SQLColumnTypeNumeric, 0, nil } default: - return -1, 0, fmt.Errorf("Don't know how to map evmSignature: %s ", evmSignature) + return -1, 0, fmt.Errorf("do not know how to map evmSignature: %s ", evmSignature) } } diff --git a/vent/sqlsol/projection_test.go b/vent/sqlsol/projection_test.go index ca5b3ca11..40a5c2530 100644 --- a/vent/sqlsol/projection_test.go +++ b/vent/sqlsol/projection_test.go @@ -222,6 +222,6 @@ func TestNewProjectionFromEventSpec(t *testing.T) { // Create a column conflict between burn and unreliable fields (both map to burnt so the SQL column def must be identical) field = eventSpec[1].GetFieldMapping("unreliable") field.Primary = !field.Primary - projection, err = sqlsol.NewProjectionFromEventSpec(eventSpec) + _, err = sqlsol.NewProjectionFromEventSpec(eventSpec) require.Error(t, err) }