-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
🚧 WIP: Add off-chain-data go client application 🚧 #1269
base: main
Are you sure you want to change the base?
Conversation
45a2aac
to
09402bc
Compare
f7ede20
to
4e58c31
Compare
Created project structure, fixed typos. Implemented connect.go and getAllAssets.go. The latter uses an assetTransferBasic struct which provides a simple API for basic asset operations like create, transfer, etc. Added transact.go with some util functions. Using google uuid package to generate random UUIDs for the transactions. Implemented pretty printing of JSON results. Implemented app.go entry point with error handling. The existing commands are getAllAssets, transact and listen. They can be called from the command line via: "go run . <command> <command> ...". They will be executed in order and if a command is not known an the application panics and aborts before executing any of the commands. Implementing listen.go. Added checkpointer, context setups, call to BlockEvents and all the interfaces needed for parsing. Started implementing the interfaces needed to represent a block bottom up in structs. Finished NamespaceReadWriteSet, ReadWriteSet and EndorserTransaction. Signed-off-by: Stanislav Jakuschevskij <[email protected]>
4e58c31
to
1d3f283
Compare
For the GetCreator() method return the identity.Identity interface was also implemented.
type Block interface { | ||
GetNumber() uint64 | ||
GetTransactions() []Transaction | ||
ToProto() *common.Block | ||
} | ||
|
||
type ParsedBlock struct { | ||
block *common.Block | ||
validationCodes []byte | ||
transactions []Transaction | ||
} | ||
|
||
func NewParsedBlock(block *common.Block) Block { | ||
validationCodes := getTransactionValidationCodes(block) | ||
|
||
return &ParsedBlock{block, validationCodes, nil} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A more typical pattern in Go is to return concrete structs, and use interfaces for parameter types received by functions. Interfaces are typically used for return types only where different implementation structs might be returned.
For this case you might be better not to have an interface at all.
type Block interface { | |
GetNumber() uint64 | |
GetTransactions() []Transaction | |
ToProto() *common.Block | |
} | |
type ParsedBlock struct { | |
block *common.Block | |
validationCodes []byte | |
transactions []Transaction | |
} | |
func NewParsedBlock(block *common.Block) Block { | |
validationCodes := getTransactionValidationCodes(block) | |
return &ParsedBlock{block, validationCodes, nil} | |
} | |
type Block struct { | |
block *common.Block | |
validationCodes []byte | |
transactions []Transaction | |
} | |
func ParseBlock(block *common.Block) Block { | |
validationCodes := getTransactionValidationCodes(block) | |
return &Block{block, validationCodes, nil} | |
} |
To make it clearer you might consider moving the parsing code (and associated structs) into a different package. Then each Block variable in the application code will be referred to as either common.Block
or parser.Block
(for example).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A more typical pattern in Go is to return concrete structs, and use interfaces for parameter types received by functions.
Thx, didn't knew. Will do that.
Interfaces are typically used for return types only where different implementation structs might be returned.
Of course, that is right and not only in go. Will keep it in mind.
To make it clearer you might consider moving the parsing code (and associated structs) into a different package. Then each Block variable in the application code will be referred to as either
common.Block
orparser.Block
(for example).
Yes, that is exactly my plan once I'll make it work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For this case you might be better not to have an interface at all.
The TypeScript implementation is using interfaces. I thought I was supposed to follow it closely?
I will implement a version without interfaces and see how it is.
} | ||
|
||
// TODO: needs cache, getPayloads, parsePayload | ||
func (pb *ParsedBlock) GetTransactions() []Transaction { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Go typically doesn't use Get
for getters (although it can make sense in some cases). A more typical naming would just be Transactions
. See Effective Go.
func (pb *ParsedBlock) GetTransactions() []Transaction { | |
func (pb *ParsedBlock) Transactions() []Transaction { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes yes, this was also bothering me. I remember that one well.
On the side: getters and setters aren't a good pattern anyway imho. I agree mostly with Allen Holub on this one => good read Why getter and setter methods are evil. But I would not go as far as not using them at all. It depends on the project and style used.
} | ||
|
||
// Implements identity.Identity Interface | ||
type IdentityImpl struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's really an implementation class only created by implementation of this package then I would make it private (first character lower case). Often an interface is not used and the concrete class is returned, but reusing the fabric-gateway Identity interface might make sense here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will review and update the encapsulation once I refactored the code into the parser package.
off_chain_data/application-go/go.mod
Outdated
go 1.22.7 | ||
|
||
toolchain go1.23.0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I would recommend setting the minimum required Go version to 1.22.0 and removing the toolchain so it builds with the locally installed version of Go, provided it is at least the minimum required version. You can do that by running:
go get [email protected] toolchain@none
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thx. Will do.
Created parser, contract and utils packages and extracted each piece of functionality into its own files. Removed "Get" prefix from methods and changed return values from interfaces to structs.
Removed Block and Transaction interfaces and unused statusCode function. Using the struct instead of the interfaces now.
fc2ff58
to
c6d784a
Compare
90f1ff8
to
8a27031
Compare
Added block processor struct and the process method. Implemented getting valid transactions from the last processed index. Added data structures needed for the store. Decomposed the parser.Block.Transactions() method into readable chunks. Added transaction processor struct and process method. Unwrapping read write set data from the transaction, mapping to a new "write" data structure and passing down to the store. Store is an empty function and will be implemented next. Signed-off-by: Stanislav Jakuschevskij <[email protected]>
8a27031
to
0b9a1f0
Compare
Persisting ledger writes to the file system into the store.log file in the application-go directory. The write values are converted from bytes to a string when the read write sets are unwrapped in the transaction processor. Signed-off-by: Stanislav Jakuschevskij <[email protected]>
Don't close the PR. I am working on it. New commits are coming CW 52.
Description to be added...