From c12ed0670ec3b941fa8e7532ec94e5df04a08639 Mon Sep 17 00:00:00 2001 From: Inge Wallin Date: Fri, 21 Jun 2019 22:11:28 +0200 Subject: [PATCH 01/13] Fix #286: Compilation error when struct field is named 'input' or 'output' --- CHANGELOG.md | 2 +- cxgo/cxgo0/cxgo0.nex | 2 -- cxgo/cxgo0/cxgo0.y | 2 +- cxgo/parser/cxgo.nex | 4 ---- cxgo/parser/cxgo.y | 2 +- cxgo/parser/cxtok.go | 4 ---- tests/main.cx | 2 +- tests/testdata/tokens/issue-286.cx.txt | 4 ++-- tests/testdata/tokens/main.cx.txt | 2 +- 9 files changed, 7 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ebd2e243..e87fd80ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ * Libraries * ... * Fixed issues - * ... + * #286: Compilation error when struct field is named 'input' or 'output' * Documentation * ... * Miscellaneous diff --git a/cxgo/cxgo0/cxgo0.nex b/cxgo/cxgo0/cxgo0.nex index a7eac7b6a..c85d13ffb 100644 --- a/cxgo/cxgo0/cxgo0.nex +++ b/cxgo/cxgo0/cxgo0.nex @@ -121,8 +121,6 @@ /clauses/ { return f(CLAUSES) } /def/ { return f(DEF) } /field/ { return f(FIELD) } -/input/ { return f(INPUT) } -/output/ { return f(OUTPUT) } /import/ { return f(IMPORT) } /var/ { return f(VAR) } /"([^"]*)"/ { /* " */ diff --git a/cxgo/cxgo0/cxgo0.y b/cxgo/cxgo0/cxgo0.y index c47910dd6..5d2c97be4 100644 --- a/cxgo/cxgo0/cxgo0.y +++ b/cxgo/cxgo0/cxgo0.y @@ -98,7 +98,7 @@ /* Selectors */ SPACKAGE SSTRUCT SFUNC /* Removers */ - REM DEF EXPR FIELD INPUT OUTPUT CLAUSES OBJECT OBJECTS + REM DEF EXPR FIELD CLAUSES OBJECT OBJECTS /* Stepping */ STEP PSTEP TSTEP /* Debugging */ diff --git a/cxgo/parser/cxgo.nex b/cxgo/parser/cxgo.nex index 8fcf9ed11..426979681 100644 --- a/cxgo/parser/cxgo.nex +++ b/cxgo/parser/cxgo.nex @@ -117,8 +117,6 @@ /clauses/ { return f(CLAUSES) } /def/ { return f(DEF) } /field/ { return f(FIELD) } -/input/ { return f(INPUT) } -/output/ { return f(OUTPUT) } /import/ { return f(IMPORT) } /var/ { return f(VAR) } /"([^"]*)"/ { /* " */ @@ -397,8 +395,6 @@ var tokenNames = map[int]string { DEF: "DEF", EXPR: "EXPR", FIELD: "FIELD", - INPUT: "INPUT", - OUTPUT: "OUTPUT", CLAUSES: "CLAUSES", OBJECT: "OBJECT", OBJECTS: "OBJECTS", diff --git a/cxgo/parser/cxgo.y b/cxgo/parser/cxgo.y index 9a53bd86c..b4697e7f6 100644 --- a/cxgo/parser/cxgo.y +++ b/cxgo/parser/cxgo.y @@ -81,7 +81,7 @@ /* Selectors */ SPACKAGE SSTRUCT SFUNC /* Removers */ - REM DEF EXPR FIELD INPUT OUTPUT CLAUSES OBJECT OBJECTS + REM DEF EXPR FIELD CLAUSES OBJECT OBJECTS /* Stepping */ STEP PSTEP TSTEP /* Debugging */ diff --git a/cxgo/parser/cxtok.go b/cxgo/parser/cxtok.go index f6ee90207..5caad34cd 100644 --- a/cxgo/parser/cxtok.go +++ b/cxgo/parser/cxtok.go @@ -181,8 +181,6 @@ func tokenName(token int) string { return " INCOP" case INFER: return " INFER" - case INPUT: - return " INPUT" case INT_LITERAL: return "INTLIT" case LBRACE: @@ -247,8 +245,6 @@ func tokenName(token int) string { return " ORSET" case OR_OP: return " OROP" - case OUTPUT: - return "OUTPUT" case PACKAGE: return "PACKAG" case PERIOD: diff --git a/tests/main.cx b/tests/main.cx index a82a9362d..9f73f9fa3 100644 --- a/tests/main.cx +++ b/tests/main.cx @@ -425,7 +425,7 @@ func main ()() { runTestEx("issue-283.cx", cx.SUCCESS, "for loop using boolean value is not compiling", TEST_ISSUE, 0) runTest("issue-284.cx", cx.SUCCESS, "Concatenation of str variables with + operator doesn't work") runTest("issue-285.cx", cx.SUCCESS, "Short declaration doesn't compile with opcode return value") - runTestEx("issue-286.cx", cx.SUCCESS, "Compilation error when struct field is named 'input' or 'output'", TEST_ISSUE, 0) + runTest("issue-286.cx", cx.SUCCESS, "Compilation error when struct field is named 'input' or 'output'", TEST_ISSUE, 0) runTestEx("issue-287.cx", cx.COMPILATION_ERROR, "No compilation error when using empty argument list after function call", TEST_ISSUE, 0) runTest("issue-288.cx", cx.COMPILATION_ERROR, "No compilation error when using float value in place of boolean expression") runTest("issue-289.cx", cx.COMPILATION_ERROR, "Panic when package contains duplicate function signature") diff --git a/tests/testdata/tokens/issue-286.cx.txt b/tests/testdata/tokens/issue-286.cx.txt index 951bad8d3..d9c9ec5b1 100644 --- a/tests/testdata/tokens/issue-286.cx.txt +++ b/tests/testdata/tokens/issue-286.cx.txt @@ -5,10 +5,10 @@ SCOLON IDENT too STRUCT LBRACE - INPUT + IDENT input I32 i32 SCOLON -OUTPUT + IDENT output I32 i32 SCOLON RBRACE diff --git a/tests/testdata/tokens/main.cx.txt b/tests/testdata/tokens/main.cx.txt index 8348b17ed..c5322e778 100644 --- a/tests/testdata/tokens/main.cx.txt +++ b/tests/testdata/tokens/main.cx.txt @@ -3408,7 +3408,7 @@ PERIOD STRLIT Short declaration doesn't compile with opcode return value RPAREN SCOLON - IDENT runTestEx + IDENT runTest LPAREN STRLIT issue-286.cx COMMA From f789615293263f72d922deda8372628faaf3c0e3 Mon Sep 17 00:00:00 2001 From: Inge Wallin Date: Fri, 21 Jun 2019 22:24:58 +0200 Subject: [PATCH 02/13] Fix number of parameters for RunTest() --- tests/main.cx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/main.cx b/tests/main.cx index 9f73f9fa3..4108c1fad 100644 --- a/tests/main.cx +++ b/tests/main.cx @@ -425,7 +425,7 @@ func main ()() { runTestEx("issue-283.cx", cx.SUCCESS, "for loop using boolean value is not compiling", TEST_ISSUE, 0) runTest("issue-284.cx", cx.SUCCESS, "Concatenation of str variables with + operator doesn't work") runTest("issue-285.cx", cx.SUCCESS, "Short declaration doesn't compile with opcode return value") - runTest("issue-286.cx", cx.SUCCESS, "Compilation error when struct field is named 'input' or 'output'", TEST_ISSUE, 0) + runTest("issue-286.cx", cx.SUCCESS, "Compilation error when struct field is named 'input' or 'output'") runTestEx("issue-287.cx", cx.COMPILATION_ERROR, "No compilation error when using empty argument list after function call", TEST_ISSUE, 0) runTest("issue-288.cx", cx.COMPILATION_ERROR, "No compilation error when using float value in place of boolean expression") runTest("issue-289.cx", cx.COMPILATION_ERROR, "Panic when package contains duplicate function signature") From 7461e9a2c4860c1a98bfbf5d2ebb96fdb6931bba Mon Sep 17 00:00:00 2001 From: Inge Wallin Date: Fri, 21 Jun 2019 22:40:08 +0200 Subject: [PATCH 03/13] Re-update golden files --- tests/testdata/tokens/main.cx.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/testdata/tokens/main.cx.txt b/tests/testdata/tokens/main.cx.txt index c5322e778..d7184ea8f 100644 --- a/tests/testdata/tokens/main.cx.txt +++ b/tests/testdata/tokens/main.cx.txt @@ -3417,10 +3417,6 @@ PERIOD IDENT SUCCESS COMMA STRLIT Compilation error when struct field is named 'input' or 'output' - COMMA - IDENT TEST_ISSUE - COMMA -INTLIT 0 RPAREN SCOLON IDENT runTestEx From 9b4682116ffe61b88150c371afe5f2d6d541f37e Mon Sep 17 00:00:00 2001 From: Inge Wallin Date: Fri, 21 Jun 2019 23:12:00 +0200 Subject: [PATCH 04/13] Fix #323: Installation issues on Windows after merging #320 --- cx-setup.bat | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cx-setup.bat b/cx-setup.bat index 80000d923..c3ab1521b 100644 --- a/cx-setup.bat +++ b/cx-setup.bat @@ -235,10 +235,10 @@ exit /b %BIN_PATH%\goyacc -o %CXGO_PATH%\cxgo0\cxgo0.go %CXGO_PATH%\cxgo0\cxgo0.y call :showResults "goyacc cxgo0" "1st pass -" "ERROR in 1st pass -" - %BIN_PATH%\nex -e %CXGO_PATH%\cxgo.nex + %BIN_PATH%\nex -e %CXGO_PATH%\parser\cxgo.nex call :showResults "nex cxgo" "2nd pass -" "ERROR in 2nd pass -" - %BIN_PATH%\goyacc -o %CXGO_PATH%\cxgo.go %CXGO_PATH%\cxgo.y + %BIN_PATH%\goyacc -o %CXGO_PATH%\parser\cxgo.go %CXGO_PATH%\cxgo.y call :showResults "goyacc cxgo" "2nd pass -" "ERROR in 2nd pass -" From a7da5dd2f5df484a7fa6368640e7738221f81b49 Mon Sep 17 00:00:00 2001 From: Inge Wallin Date: Fri, 21 Jun 2019 23:18:31 +0200 Subject: [PATCH 05/13] Forgot to update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e87fd80ed..c373708c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ * ... * Fixed issues * #286: Compilation error when struct field is named 'input' or 'output' + * #323: Installation issues on Windows after merging #320 * Documentation * ... * Miscellaneous From 61335a3514f87d9280dd81ffad8c26c92389c693 Mon Sep 17 00:00:00 2001 From: Inge Wallin Date: Fri, 21 Jun 2019 23:21:46 +0200 Subject: [PATCH 06/13] Fix installation paths of cx.sh --- cx.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cx.sh b/cx.sh index 05cc82708..3ad23818f 100755 --- a/cx.sh +++ b/cx.sh @@ -154,13 +154,13 @@ if [ ! $? -eq 0 ]; then exit 0 fi -$INSTALLATION_PATH/bin/nex -e $INSTALLATION_PATH/src/github.com/skycoin/cx/cxgo/cxgo.nex +$INSTALLATION_PATH/bin/nex -e $INSTALLATION_PATH/src/github.com/skycoin/cx/cxgo/parser/cxgo.nex if [ ! $? -eq 0 ]; then echo "FAIL:\tThere was a problem compiling CX's lexical analyzer" exit 0 fi -$INSTALLATION_PATH/bin/goyacc -o $INSTALLATION_PATH/src/github.com/skycoin/cx/cxgo/cxgo.go $INSTALLATION_PATH/src/github.com/skycoin/cx/cxgo/cxgo.y +$INSTALLATION_PATH/bin/goyacc -o $INSTALLATION_PATH/src/github.com/skycoin/cx/cxgo/parser/cxgo.go $INSTALLATION_PATH/src/github.com/skycoin/cx/cxgo/parser/cxgo.y if [ ! $? -eq 0 ]; then echo "FAIL:\tThere was a problem compiling CX's parser" exit 0 From a56072197b9a9ef1e7cb560738751209b86b8f95 Mon Sep 17 00:00:00 2001 From: Amaury Hernandez-Aguila Date: Fri, 21 Jun 2019 14:46:26 -0700 Subject: [PATCH 07/13] Fixed a path and how tests are run in cx-setup.bat --- cx-setup.bat | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cx-setup.bat b/cx-setup.bat index c3ab1521b..a5aa2b043 100644 --- a/cx-setup.bat +++ b/cx-setup.bat @@ -109,7 +109,7 @@ if %ERRORLEVEL% neq 0 ( rem run CX tests -%BIN_PATH%\cx.exe %SKYCOIN_PATH%\cx\tests +%BIN_PATH%\cx.exe %SKYCOIN_PATH%\cx\tests\main.cx ++wdir=tests\ ++disable-tests=gui,issue call :showResults cx\tests "Tested" "ERROR while testing" call :echoWithColor yellow "You can re-run CX tests with:" @@ -238,7 +238,7 @@ exit /b %BIN_PATH%\nex -e %CXGO_PATH%\parser\cxgo.nex call :showResults "nex cxgo" "2nd pass -" "ERROR in 2nd pass -" - %BIN_PATH%\goyacc -o %CXGO_PATH%\parser\cxgo.go %CXGO_PATH%\cxgo.y + %BIN_PATH%\goyacc -o %CXGO_PATH%\parser\cxgo.go %CXGO_PATH%\parser\cxgo.y call :showResults "goyacc cxgo" "2nd pass -" "ERROR in 2nd pass -" From 97ece6b889d1eb31faa3e05300c1e143c1997a30 Mon Sep 17 00:00:00 2001 From: Inge Wallin Date: Sat, 22 Jun 2019 02:54:10 +0200 Subject: [PATCH 08/13] Add tests for issue 415 And add an old file for issue 283 also. --- tests/issue-283b.cx | 10 +++++++ tests/issue-415.cx | 8 ++++++ tests/main.cx | 1 + tests/testdata/tokens/issue-283b.cx.txt | 35 +++++++++++++++++++++++++ tests/testdata/tokens/issue-415.cx.txt | 22 ++++++++++++++++ tests/testdata/tokens/main.cx.txt | 15 +++++++++++ 6 files changed, 91 insertions(+) create mode 100644 tests/issue-283b.cx create mode 100644 tests/issue-415.cx create mode 100644 tests/testdata/tokens/issue-283b.cx.txt create mode 100644 tests/testdata/tokens/issue-415.cx.txt diff --git a/tests/issue-283b.cx b/tests/issue-283b.cx new file mode 100644 index 000000000..dab3c7784 --- /dev/null +++ b/tests/issue-283b.cx @@ -0,0 +1,10 @@ +package main + +func main()() { + var b bool = true + var i i32 = 3 + for b { + a := 1 + 2 + //printf("true\n") + } +} diff --git a/tests/issue-415.cx b/tests/issue-415.cx new file mode 100644 index 000000000..5400b6223 --- /dev/null +++ b/tests/issue-415.cx @@ -0,0 +1,8 @@ +package main + +func main() { + cat(1) +} + +func cat() { +} diff --git a/tests/main.cx b/tests/main.cx index 4108c1fad..d50431742 100644 --- a/tests/main.cx +++ b/tests/main.cx @@ -444,6 +444,7 @@ func main ()() { runTestEx("issue-360.cx", cx.COMPILATION_ERROR, "Panic when package keyword is misspelled", TEST_ISSUE, 0) runTestEx("issue-361.cx", cx.COMPILATION_ERROR, "No compilation error when assigning an literal which overflow the receiving type", TEST_ISSUE, 0) runTestEx("issue-362.cx", cx.SUCCESS, "Cx is not supporting short-circuit evaluation", TEST_ISSUE, 0) + runTestEx("issue-415.cx", cx.SUCCESS, "func defined with no arguments, called WITH arguments causes PANIC", TEST_ISSUE, 0) // We need to fix serialization and deserialization as user-callable functions // runTestEx("issue-309.cx", cx.SUCCESS, "Serialization is not taking into account non-default stack sizes.", TEST_ISSUE, 0) diff --git a/tests/testdata/tokens/issue-283b.cx.txt b/tests/testdata/tokens/issue-283b.cx.txt new file mode 100644 index 000000000..d224b51d8 --- /dev/null +++ b/tests/testdata/tokens/issue-283b.cx.txt @@ -0,0 +1,35 @@ +PACKAG + IDENT main +SCOLON + FUNC + IDENT main +LPAREN +RPAREN +LPAREN +RPAREN +LBRACE + VAR + IDENT b + BOOL bool + ASGN = +BOOLLT true +SCOLON + VAR + IDENT i + I32 i32 + ASGN = +INTLIT 3 +SCOLON + FOR + IDENT b +LBRACE + IDENT a +CASSGN := +INTLIT 1 + ADDOP + +INTLIT 2 +SCOLON +RBRACE +SCOLON +RBRACE +SCOLON diff --git a/tests/testdata/tokens/issue-415.cx.txt b/tests/testdata/tokens/issue-415.cx.txt new file mode 100644 index 000000000..f1b6a05b2 --- /dev/null +++ b/tests/testdata/tokens/issue-415.cx.txt @@ -0,0 +1,22 @@ +PACKAG + IDENT main +SCOLON + FUNC + IDENT main +LPAREN +RPAREN +LBRACE + IDENT cat +LPAREN +INTLIT 1 +RPAREN +SCOLON +RBRACE +SCOLON + FUNC + IDENT cat +LPAREN +RPAREN +LBRACE +RBRACE +SCOLON diff --git a/tests/testdata/tokens/main.cx.txt b/tests/testdata/tokens/main.cx.txt index d7184ea8f..a4749f278 100644 --- a/tests/testdata/tokens/main.cx.txt +++ b/tests/testdata/tokens/main.cx.txt @@ -3676,6 +3676,21 @@ STRLIT Cx is not supporting short-circuit evaluation COMMA INTLIT 0 RPAREN +SCOLON + IDENT runTestEx +LPAREN +STRLIT issue-415.cx + COMMA + IDENT cx +PERIOD + IDENT SUCCESS + COMMA +STRLIT Cx is not supporting short-circuit evaluation + COMMA + IDENT TEST_ISSUE + COMMA +INTLIT 0 +RPAREN SCOLON VAR IDENT end From e71ac7b4f7379a416f157fbbdd25363e5aa61841 Mon Sep 17 00:00:00 2001 From: Inge Wallin Date: Sat, 22 Jun 2019 03:19:57 +0200 Subject: [PATCH 09/13] Update golden files --- tests/testdata/tokens/main.cx.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testdata/tokens/main.cx.txt b/tests/testdata/tokens/main.cx.txt index a4749f278..901a4155f 100644 --- a/tests/testdata/tokens/main.cx.txt +++ b/tests/testdata/tokens/main.cx.txt @@ -3685,7 +3685,7 @@ STRLIT issue-415.cx PERIOD IDENT SUCCESS COMMA -STRLIT Cx is not supporting short-circuit evaluation +STRLIT func defined with no arguments, called WITH arguments causes PANIC COMMA IDENT TEST_ISSUE COMMA From 0ce695b3f15d997fe421f86fdb4925984249f678 Mon Sep 17 00:00:00 2001 From: Amaury Hernandez Date: Wed, 26 Jun 2019 01:27:05 -0700 Subject: [PATCH 10/13] Added function that prints information about the heap. --- CHANGELOG.md | 2 +- cx/utilities.go | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c373708c8..d51bccf67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ### v0.7.1 (NOT YET RELEASED) * Additions - * ... + * Added a function that prints information about the heap for debugging purposes (`debugHeap` in cx/utilities.go). * Changes * ... * Libraries diff --git a/cx/utilities.go b/cx/utilities.go index b1a9ed160..2dcd6d0d8 100644 --- a/cx/utilities.go +++ b/cx/utilities.go @@ -6,6 +6,7 @@ import ( "os" "runtime/debug" "strconv" + "text/tabwriter" "github.com/amherag/skycoin/src/cipher/encoder" ) @@ -994,3 +995,79 @@ func mustDeserializeRaw(byts []byte, item interface{}) { panic(err) } } + +// debugHeap prints the symbols that are acting as pointers in a CX program at certain point during the execution of the program along with the addresses they are pointing. Additionally, a list of the objects in the heap is printed, which shows their address in the heap, if they are marked as alive or as dead by the garbage collector, the address where they used to live after a garbage collector call, the full size of the object, the object itself as a slice of bytes and the pointers that are pointing to that object. +func debugHeap() { + // symsToAddrs will hold a list of symbols that are pointing to an address. + symsToAddrs := make(map[int32][]string, 0) + + // Processing global variables. Adding the address they are pointing to. + for _, pkg := range PROGRAM.Packages { + for _, glbl := range pkg.Globals { + if glbl.IsPointer || glbl.IsSlice { + var heapOffset int32 + encoder.DeserializeAtomic(PROGRAM.Memory[glbl.Offset:glbl.Offset+TYPE_POINTER_SIZE], &heapOffset) + + symsToAddrs[heapOffset] = append(symsToAddrs[heapOffset], glbl.Name) + } + } + } + + // Processing local variables in every active function call in the `CallStack`. + // Adding the address they are pointing to. + var fp int + for c := 0; c <= PROGRAM.CallCounter; c++ { + op := PROGRAM.CallStack[c].Operator + + // TODO: Some standard library functions "manually" add a function + // call (callbacks) to `PRGRM.CallStack`. These functions do not have an + // operator associated to them. This can be considered as a bug or as an + // undesirable mechanic. + // [2019-06-24 Mon 22:39] Actually, if the GC is triggered in the middle + // of a callback, things will certainly break. + if op == nil { + continue + } + + for _, ptr := range op.ListOfPointers { + var heapOffset int32 + encoder.DeserializeAtomic(PROGRAM.Memory[fp+ptr.Offset:fp+ptr.Offset+TYPE_POINTER_SIZE], &heapOffset) + + symsToAddrs[heapOffset] = append(symsToAddrs[heapOffset], ptr.Name) + } + + fp += op.Size + } + + // Printing all the details. + w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, '.', 0) + + for off, symNames := range symsToAddrs { + addrB := encoder.Serialize(off) + fmt.Fprintln(w, "Addr:\t", addrB, "\tPtr:\t", symNames) + } + + // Just a newline. + fmt.Fprintln(w) + w.Flush() + + w = tabwriter.NewWriter(os.Stdout, 0, 0, 2, '.', 0) + + for c := PROGRAM.HeapStartsAt + NULL_HEAP_ADDRESS_OFFSET; c < PROGRAM.HeapStartsAt+PROGRAM.HeapPointer; { + var objSize int32 + _, err := encoder.DeserializeAtomic(PROGRAM.Memory[c+MARK_SIZE+FORWARDING_ADDRESS_SIZE:c+MARK_SIZE+FORWARDING_ADDRESS_SIZE+OBJECT_SIZE], &objSize) + if err != nil { + panic(err) + } + + addrB := encoder.Serialize(int32(c)) + + fmt.Fprintln(w, "Addr:\t", addrB, "\tMark:\t", PROGRAM.Memory[c:c+MARK_SIZE], "\tFwd:\t", PROGRAM.Memory[c+MARK_SIZE:c+MARK_SIZE+FORWARDING_ADDRESS_SIZE], "\tSize:\t", objSize, "\tObj:\t", PROGRAM.Memory[c+OBJECT_HEADER_SIZE:c + int(objSize)], "\tPtrs:", symsToAddrs[int32(c)]) + + c += int(objSize) + } + + // Just a newline. + fmt.Fprintln(w) + w.Flush() +} From cdc0f7e751f5fd0be6794db91d3c9ab1b8bbb9f4 Mon Sep 17 00:00:00 2001 From: Amaury Hernandez Date: Wed, 26 Jun 2019 01:35:03 -0700 Subject: [PATCH 11/13] Fixed linter errors in cx/utilities.go --- cx/utilities.go | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/cx/utilities.go b/cx/utilities.go index 2dcd6d0d8..11ba97592 100644 --- a/cx/utilities.go +++ b/cx/utilities.go @@ -996,17 +996,20 @@ func mustDeserializeRaw(byts []byte, item interface{}) { } } -// debugHeap prints the symbols that are acting as pointers in a CX program at certain point during the execution of the program along with the addresses they are pointing. Additionally, a list of the objects in the heap is printed, which shows their address in the heap, if they are marked as alive or as dead by the garbage collector, the address where they used to live after a garbage collector call, the full size of the object, the object itself as a slice of bytes and the pointers that are pointing to that object. -func debugHeap() { +// DebugHeap prints the symbols that are acting as pointers in a CX program at certain point during the execution of the program along with the addresses they are pointing. Additionally, a list of the objects in the heap is printed, which shows their address in the heap, if they are marked as alive or as dead by the garbage collector, the address where they used to live after a garbage collector call, the full size of the object, the object itself as a slice of bytes and the pointers that are pointing to that object. +func DebugHeap() { // symsToAddrs will hold a list of symbols that are pointing to an address. - symsToAddrs := make(map[int32][]string, 0) + symsToAddrs := make(map[int32][]string) // Processing global variables. Adding the address they are pointing to. for _, pkg := range PROGRAM.Packages { for _, glbl := range pkg.Globals { if glbl.IsPointer || glbl.IsSlice { var heapOffset int32 - encoder.DeserializeAtomic(PROGRAM.Memory[glbl.Offset:glbl.Offset+TYPE_POINTER_SIZE], &heapOffset) + _, err := encoder.DeserializeAtomic(PROGRAM.Memory[glbl.Offset:glbl.Offset+TYPE_POINTER_SIZE], &heapOffset) + if err != nil { + panic(err) + } symsToAddrs[heapOffset] = append(symsToAddrs[heapOffset], glbl.Name) } @@ -1031,7 +1034,10 @@ func debugHeap() { for _, ptr := range op.ListOfPointers { var heapOffset int32 - encoder.DeserializeAtomic(PROGRAM.Memory[fp+ptr.Offset:fp+ptr.Offset+TYPE_POINTER_SIZE], &heapOffset) + _, err := encoder.DeserializeAtomic(PROGRAM.Memory[fp+ptr.Offset:fp+ptr.Offset+TYPE_POINTER_SIZE], &heapOffset) + if err != nil { + panic(err) + } symsToAddrs[heapOffset] = append(symsToAddrs[heapOffset], ptr.Name) } @@ -1052,7 +1058,7 @@ func debugHeap() { w.Flush() w = tabwriter.NewWriter(os.Stdout, 0, 0, 2, '.', 0) - + for c := PROGRAM.HeapStartsAt + NULL_HEAP_ADDRESS_OFFSET; c < PROGRAM.HeapStartsAt+PROGRAM.HeapPointer; { var objSize int32 _, err := encoder.DeserializeAtomic(PROGRAM.Memory[c+MARK_SIZE+FORWARDING_ADDRESS_SIZE:c+MARK_SIZE+FORWARDING_ADDRESS_SIZE+OBJECT_SIZE], &objSize) @@ -1062,8 +1068,8 @@ func debugHeap() { addrB := encoder.Serialize(int32(c)) - fmt.Fprintln(w, "Addr:\t", addrB, "\tMark:\t", PROGRAM.Memory[c:c+MARK_SIZE], "\tFwd:\t", PROGRAM.Memory[c+MARK_SIZE:c+MARK_SIZE+FORWARDING_ADDRESS_SIZE], "\tSize:\t", objSize, "\tObj:\t", PROGRAM.Memory[c+OBJECT_HEADER_SIZE:c + int(objSize)], "\tPtrs:", symsToAddrs[int32(c)]) - + fmt.Fprintln(w, "Addr:\t", addrB, "\tMark:\t", PROGRAM.Memory[c:c+MARK_SIZE], "\tFwd:\t", PROGRAM.Memory[c+MARK_SIZE:c+MARK_SIZE+FORWARDING_ADDRESS_SIZE], "\tSize:\t", objSize, "\tObj:\t", PROGRAM.Memory[c+OBJECT_HEADER_SIZE:c+int(objSize)], "\tPtrs:", symsToAddrs[int32(c)]) + c += int(objSize) } From 062fea04d97fdfea8d1abdc4ff3e4ca23b675e88 Mon Sep 17 00:00:00 2001 From: Srdjan Radulovic Date: Tue, 18 Jun 2019 15:27:58 +0200 Subject: [PATCH 12/13] Ping CX tracker every 5 min Upon CX application start ping tracker service with current config. --- cxgo/main.go | 272 +++++++++++++++++++++++++++------------------------ 1 file changed, 146 insertions(+), 126 deletions(-) diff --git a/cxgo/main.go b/cxgo/main.go index 5e0073dff..aede79af4 100644 --- a/cxgo/main.go +++ b/cxgo/main.go @@ -1,47 +1,48 @@ package main import ( - "os" - "os/user" - "os/exec" - "fmt" + "bufio" "bytes" - "time" + "encoding/json" + "fmt" "io" "io/ioutil" - "strings" + "os" + "os/exec" + "os/user" "strconv" - "bufio" - "encoding/json" + "strings" + "time" + // "encoding/hex" "runtime" "regexp" - + "flag" "path/filepath" "net" "net/http" - + . "github.com/skycoin/cx/cx" - . "github.com/skycoin/cx/cxgo/parser" . "github.com/skycoin/cx/cxgo/actions" "github.com/skycoin/cx/cxgo/cxgo0" + . "github.com/skycoin/cx/cxgo/parser" "github.com/theherk/viper" "github.com/amherag/skycoin/src/cipher" // "github.com/amherag/skycoin/src/cipher/encoder" + "github.com/amherag/skycoin/src/api" + "github.com/amherag/skycoin/src/cli" "github.com/amherag/skycoin/src/coin" + "github.com/amherag/skycoin/src/fiber" "github.com/amherag/skycoin/src/readable" "github.com/amherag/skycoin/src/skycoin" - "github.com/amherag/skycoin/src/fiber" "github.com/amherag/skycoin/src/util/logging" "github.com/amherag/skycoin/src/visor" - "github.com/amherag/skycoin/src/api" - "github.com/amherag/skycoin/src/cli" "github.com/amherag/skycoin/src/wallet" "errors" @@ -74,9 +75,9 @@ func getJSON(url string, target interface{}) error { return json.NewDecoder(r.Body).Decode(target) } -func initCXBlockchain (initPrgrm []byte, coinname, seckey string) error { +func initCXBlockchain(initPrgrm []byte, coinname, seckey string) error { var err error - + // check that data.db does not exist // if it does, delete it userHome := UserHome() @@ -155,7 +156,7 @@ func initCXBlockchain (initPrgrm []byte, coinname, seckey string) error { // get genesis block err = getJSON(fmt.Sprintf(genesisBlockURL, params.Node.WebInterfacePort), &genesisBlock) - + return } } @@ -266,7 +267,7 @@ func runNode(mode string, options cxCmdFlags) *exec.Cmd { switch mode { case "publisher": return exec.Command("cxcoin", "-enable-all-api-sets", - "-block-publisher=true", + "-block-publisher=true", "-localhost-only", "-disable-default-peers", "-custom-peers-file=localhost-peers.txt", @@ -277,31 +278,31 @@ func runNode(mode string, options cxCmdFlags) *exec.Cmd { fmt.Sprintf("-genesis-signature=%s", options.genesisSignature), fmt.Sprintf("-blockchain-public-key=%s", options.pubKey), "-max-txn-size-unconfirmed=134217728", - "-max-txn-size-create-block=134217728", + "-max-txn-size-create-block=134217728", "-max-block-size=134217728", "-max-in-msg-len=134217929", "-max-out-msg-len=134217929", // I don't know why this value, but the logger stated a value >= than this is needed ) case "peer": - return exec.Command("cxcoin", "-enable-all-api-sets", - "-localhost-only", - "-disable-default-peers", - "-custom-peers-file=localhost-peers.txt", - "-download-peerlist=false", - "-launch-browser=false", - fmt.Sprintf("-genesis-address=%s", options.genesisAddress), - fmt.Sprintf("-genesis-signature=%s", options.genesisSignature), - fmt.Sprintf("-blockchain-public-key=%s", options.pubKey), - // "-web-interface-port=$(expr $2 + 420)", - fmt.Sprintf("-web-interface-port=%d", options.port + 420), - fmt.Sprintf("-port=%d", options.port), - fmt.Sprintf("-data-dir=/tmp/%d", options.port), - "-max-txn-size-unconfirmed=134217728", - "-max-txn-size-create-block=134217728", - "-max-block-size=134217728", - "-max-in-msg-len=134217929", - "-max-out-msg-len=134217929", // I don't know why this value, but the logger stated a value >= than this is needed - ) + return exec.Command("cxcoin", "-enable-all-api-sets", + "-localhost-only", + "-disable-default-peers", + "-custom-peers-file=localhost-peers.txt", + "-download-peerlist=false", + "-launch-browser=false", + fmt.Sprintf("-genesis-address=%s", options.genesisAddress), + fmt.Sprintf("-genesis-signature=%s", options.genesisSignature), + fmt.Sprintf("-blockchain-public-key=%s", options.pubKey), + // "-web-interface-port=$(expr $2 + 420)", + fmt.Sprintf("-web-interface-port=%d", options.port+420), + fmt.Sprintf("-port=%d", options.port), + fmt.Sprintf("-data-dir=/tmp/%d", options.port), + "-max-txn-size-unconfirmed=134217728", + "-max-txn-size-create-block=134217728", + "-max-block-size=134217728", + "-max-in-msg-len=134217929", + "-max-out-msg-len=134217929", // I don't know why this value, but the logger stated a value >= than this is needed + ) default: return nil } @@ -320,7 +321,7 @@ func main() { flag.Parse() // Propagate some options out to other packages - DebugLexer = options.debugLexer // in package parser + DebugLexer = options.debugLexer // in package parser if options.publisherMode || options.peerMode { var cmd *exec.Cmd @@ -352,6 +353,20 @@ func main() { log.Error(scanner.Text()) } }() + + pingTracker() // TODO should we ping on startup or after first period of 5 min is over and we're sure instance is running correctly? + trackerTicker := time.NewTicker(5 * time.Minute) + go func() { + defer trackerTicker.Stop() + + for { + select { + case <-trackerTicker.C: + pingTracker() + } + } + + }() } // Generate a CX chain address. @@ -360,7 +375,7 @@ func main() { seed := cli.MakeAlphanumericSeed() wltOpts := wallet.Options{ Label: "cxcoin", - Seed: seed, + Seed: seed, } // Generate temporary wallet. @@ -381,7 +396,7 @@ func main() { return } - + if options.walletMode { if options.walletSeed == "" { fmt.Println("creating a wallet requires a seed provided with --wallet-seed") @@ -396,9 +411,9 @@ func main() { wltOpts := wallet.Options{ Label: "cxcoin", - Seed: options.walletSeed, + Seed: options.walletSeed, } - + wlt, err := cli.GenerateWallet(options.walletId, wltOpts, 1) if err != nil { panic(err) @@ -416,10 +431,10 @@ func main() { // Printing JSON with wallet information fmt.Println(string(wltJSON)) - + return } - + if options.printHelp { printHelp() return @@ -499,7 +514,7 @@ func main() { w = os.Stdout } else { tokenFilename := options.compileOutput - w, err = os. Create(tokenFilename) + w, err = os.Create(tokenFilename) if err != nil { fmt.Fprintln(os.Stderr, "Error writing:", tokenFilename, err) return @@ -537,12 +552,12 @@ func main() { sPrgrmSH = append(sPrgrmSH, sPrgrm[memOff:]...) // Appending new heap sPrgrmSH = append(sPrgrmSH, make([]byte, INIT_HEAP_SIZE)...) - + // Deserialize(sPrgrm).RunCompiled(0, cxArgs) // bcPrgrm = Deserialize(sPrgrm) // prevMemSize := len(PRGRM.Memory) PRGRM = Deserialize(sPrgrmSH) - // // Adding + // // Adding // PRGRM.Memory = append(make([]byte, STACK_SIZE), PRGRM.Memory...) // PRGRM.Memory // PRGRM.Memory = append(PRGRM.Memory, make([]byte, prevMemSize - len(PRGRM.Memory))...) @@ -567,26 +582,26 @@ func main() { var prePkg *CXPackage parseErrors := 0 - + // We need to traverse the elements by hierarchy first add all the // packages and structs at the same time then add globals, as these // can be of a custom type (and it could be imported) the signatures // of functions and methods are added in the cxgo0.y pass if len(sourceCode) > 0 { - - reMultiCommentOpen := regexp.MustCompile(`/\*`) + + reMultiCommentOpen := regexp.MustCompile(`/\*`) reMultiCommentClose := regexp.MustCompile(`\*/`) reComment := regexp.MustCompile("//") - rePkg := regexp.MustCompile("package") - rePkgName := regexp.MustCompile("(^|[\\s])package\\s+([_a-zA-Z][_a-zA-Z0-9]*)") - reStrct := regexp.MustCompile("type") + rePkg := regexp.MustCompile("package") + rePkgName := regexp.MustCompile("(^|[\\s])package\\s+([_a-zA-Z][_a-zA-Z0-9]*)") + reStrct := regexp.MustCompile("type") reStrctName := regexp.MustCompile("(^|[\\s])type\\s+([_a-zA-Z][_a-zA-Z0-9]*)?\\s") - reGlbl := regexp.MustCompile("var") + reGlbl := regexp.MustCompile("var") reGlblName := regexp.MustCompile("(^|[\\s])var\\s([_a-zA-Z][_a-zA-Z0-9]*)") - reBodyOpen := regexp.MustCompile("{") + reBodyOpen := regexp.MustCompile("{") reBodyClose := regexp.MustCompile("}") // 1. Identify all the packages and structs @@ -628,9 +643,9 @@ func main() { } if match := rePkgName.FindStringSubmatch(string(line)); match != nil { - if pkg, err := cxgo0.PRGRM0.GetPackage(match[len(match) - 1]); err != nil { + if pkg, err := cxgo0.PRGRM0.GetPackage(match[len(match)-1]); err != nil { // then it hasn't been added - newPkg := MakePackage(match[len(match) - 1]) + newPkg := MakePackage(match[len(match)-1]) cxgo0.PRGRM0.AddPackage(newPkg) prePkg = newPkg } else { @@ -651,10 +666,10 @@ func main() { if match := reStrctName.FindStringSubmatch(string(line)); match != nil { if prePkg == nil { println(CompilationError(filename, lineno), - "No package defined") - } else if _, err := cxgo0.PRGRM0.GetStruct(match[len(match) - 1], prePkg.Name); err != nil { + "No package defined") + } else if _, err := cxgo0.PRGRM0.GetStruct(match[len(match)-1], prePkg.Name); err != nil { // then it hasn't been added - strct := MakeStruct(match[len(match) - 1]) + strct := MakeStruct(match[len(match)-1]) prePkg.AddStruct(strct) } } @@ -673,12 +688,12 @@ func main() { scanner := bufio.NewScanner(strings.NewReader(source)) for scanner.Scan() { line := scanner.Bytes() - + // we need to ignore function bodies // it'll also ignore struct declaration's bodies, but this doesn't matter commentLoc := reComment.FindIndex(line) - - multiCommentOpenLoc := reMultiCommentOpen.FindIndex(line) + + multiCommentOpenLoc := reMultiCommentOpen.FindIndex(line) multiCommentCloseLoc := reMultiCommentClose.FindIndex(line) if commentedCode && multiCommentCloseLoc != nil { @@ -702,18 +717,18 @@ func main() { // then it's commented out continue } - + if match := rePkgName.FindStringSubmatch(string(line)); match != nil { - if pkg, err := cxgo0.PRGRM0.GetPackage(match[len(match) - 1]); err != nil { + if pkg, err := cxgo0.PRGRM0.GetPackage(match[len(match)-1]); err != nil { // then it hasn't been added - prePkg = MakePackage(match[len(match) - 1]) + prePkg = MakePackage(match[len(match)-1]) cxgo0.PRGRM0.AddPackage(prePkg) } else { prePkg = pkg } } } - + if locs := reBodyOpen.FindAllIndex(line, -1); locs != nil { for _, loc := range locs { if !(multiCommentCloseLoc != nil && multiCommentCloseLoc[0] > loc[0]) { @@ -745,7 +760,7 @@ func main() { // we could have this situation: {var local i32} // but we don't care about this, as the later passes will throw an error as it's invalid syntax - + if loc := rePkg.FindIndex(line); loc != nil { if (commentLoc != nil && commentLoc[0] < loc[0]) || (multiCommentOpenLoc != nil && multiCommentOpenLoc[0] < loc[0]) || @@ -753,9 +768,9 @@ func main() { // then it's commented out continue } - + if match := rePkgName.FindStringSubmatch(string(line)); match != nil { - if pkg, err := cxgo0.PRGRM0.GetPackage(match[len(match) - 1]); err != nil { + if pkg, err := cxgo0.PRGRM0.GetPackage(match[len(match)-1]); err != nil { // it should be already present panic(err) } else { @@ -775,9 +790,9 @@ func main() { } if match := reGlblName.FindStringSubmatch(string(line)); match != nil { - if _, err := prePkg.GetGlobal(match[len(match) - 1]); err != nil { + if _, err := prePkg.GetGlobal(match[len(match)-1]); err != nil { // then it hasn't been added - arg := MakeArgument(match[len(match) - 1], "", 0) + arg := MakeArgument(match[len(match)-1], "", 0) arg.Offset = -1 arg.Package = prePkg prePkg.AddGlobal(arg) @@ -811,7 +826,6 @@ func main() { arg1 = DeclarationSpecifiers(arg1, 0, DECL_BASIC) arg1 = DeclarationSpecifiers(arg1, 0, DECL_SLICE) - DeclareGlobalInPackage(osPkg, arg0, arg1, nil, false) } @@ -847,7 +861,7 @@ func main() { // adding *init function that initializes all the global variables addInitFunction(PRGRM) - + LineNo = 0 if FoundCompileErrors { @@ -863,28 +877,28 @@ func main() { if err != nil { panic(err) } - + PRGRM.RemovePackage(MAIN_FUNC) - + s := Serialize(PRGRM, 1) s = ExtractBlockchainProgram(s, s) configDir := os.Getenv("GOPATH") + "/src/github.com/skycoin/cx/" configFile := "fiber" - + cmd := exec.Command("go", "install", "./cmd/newcoin/...") cmd.Start() cmd.Wait() - + cmd = exec.Command("newcoin", "createcoin", fmt.Sprintf("--coin=%s", options.programName), fmt.Sprintf("--template-dir=%s%s", os.Getenv("GOPATH"), "/src/github.com/skycoin/cx/template"), - "--config-file=" + configFile + ".toml", - "--config-dir=" + configDir, + "--config-file="+configFile+".toml", + "--config-dir="+configDir, ) cmd.Start() cmd.Wait() - + cmd = exec.Command("go", "install", "./cmd/cxcoin/...") cmd.Start() cmd.Wait() @@ -896,20 +910,20 @@ func main() { fmt.Println("\ngenesis signature:", genesisSignature) viper.SetConfigName(configFile) // name of config file (without extension) - viper.AddConfigPath(".") // optionally look for config in the working directory - err = viper.ReadInConfig() // Find and read the config file - if err != nil { // Handle errors reading the config file + viper.AddConfigPath(".") // optionally look for config in the working directory + err = viper.ReadInConfig() // Find and read the config file + if err != nil { // Handle errors reading the config file panic(err) } viper.Set("node.genesis_signature_str", genesisSignature) viper.WriteConfig() - + cmd = exec.Command("newcoin", "createcoin", fmt.Sprintf("--coin=%s", options.programName), fmt.Sprintf("--template-dir=%s%s", os.Getenv("GOPATH"), "/src/github.com/skycoin/cx/template"), - "--config-file=" + configFile + ".toml", - "--config-dir=" + configDir, + "--config-file="+configFile+".toml", + "--config-dir="+configDir, ) cmd.Start() cmd.Wait() @@ -924,20 +938,20 @@ func main() { dsPrgrm := Deserialize(sPrgrm) PRGRM.StackPointer = 0 PRGRM.HeapPointer = dsPrgrm.HeapPointer - + s := Serialize(PRGRM, 1) txnCode := ExtractTransactionProgram(sPrgrm, s) // All these HTTP requests need to be dropped in favor of calls to calls to functions // from the `cli` or `api` Skycoin packages - addr := fmt.Sprintf("http://127.0.0.1:%d", options.port + 420) + addr := fmt.Sprintf("http://127.0.0.1:%d", options.port+420) skycoinClient := api.NewClient(addr) csrfToken, err := skycoinClient.CSRF() if err != nil { panic(err) } - url := fmt.Sprintf("http://127.0.0.1:%d/api/v1/wallet/transaction", options.port + 420) + url := fmt.Sprintf("http://127.0.0.1:%d/api/v1/wallet/transaction", options.port+420) var dataMap map[string]interface{} dataMap = make(map[string]interface{}, 0) @@ -947,7 +961,6 @@ func main() { dataMap["wallet_id"] = string(options.walletId) dataMap["to"] = []interface{}{map[string]string{"address": "2PBcLADETphmqWV7sujRZdh3UcabssgKAEB", "coins": "1", "hours": "0"}} - jsonStr, err := json.Marshal(dataMap) if err != nil { panic(err) @@ -976,7 +989,7 @@ func main() { return } - url = fmt.Sprintf("http://127.0.0.1:%d/api/v1/injectTransaction", options.port + 420) + url = fmt.Sprintf("http://127.0.0.1:%d/api/v1/injectTransaction", options.port+420) dataMap = make(map[string]interface{}, 0) dataMap["rawtx"] = respBody["encoded_transaction"] @@ -1004,12 +1017,12 @@ func main() { if err != nil { panic(err) } - + if AssertFailed() { os.Exit(CX_ASSERT) } } - + if BaseOutput { //PRGRM.Compile(true) } @@ -1023,12 +1036,11 @@ func main() { } } - // Used for the -heap-initial, -heap-max and -stack-size flags. // This function parses, for example, "1M" to 1048576 (the corresponding number of bytes) // Possible suffixes are: G or g (gigabytes), M or m (megabytes), K or k (kilobytes) -func parseMemoryString (s string) int { - suffix := s[len(s) - 1] +func parseMemoryString(s string) int { + suffix := s[len(s)-1] _, notSuffix := strconv.ParseFloat(string(suffix), 64) if notSuffix == nil { @@ -1049,7 +1061,7 @@ func parseMemoryString (s string) int { // malformed size return -1 } - + switch suffix { case 'G': return int(num * 1073741824) @@ -1065,20 +1077,20 @@ func parseMemoryString (s string) int { // var PRGRM *CXProgram -func unsafeEval (code string) (out string) { +func unsafeEval(code string) (out string) { var lexer *Lexer defer func() { if r := recover(); r != nil { out = fmt.Sprintf("%v", r) lexer.Stop() - } + } }() - + // storing strings sent to standard output old := os.Stdout r, w, _ := os.Pipe() os.Stdout = w - + LineNo = 0 PRGRM = MakeProgram() @@ -1105,7 +1117,7 @@ func unsafeEval (code string) (out string) { io.Copy(&buf, r) outC <- buf.String() }() - + w.Close() os.Stdout = old // restoring the real stdout out = <-outC @@ -1114,12 +1126,12 @@ func unsafeEval (code string) (out string) { return out } -func Eval (code string) string { +func Eval(code string) string { runtime.GOMAXPROCS(2) ch := make(chan string, 1) var result string - + go func() { result = unsafeEval(code) ch <- result @@ -1141,11 +1153,11 @@ type SourceCode struct { Code string } -func ServiceMode () { +func ServiceMode() { host := ":5336" mux := http.NewServeMux() - + mux.Handle("/", http.FileServer(http.Dir("./dist"))) mux.HandleFunc("/eval", func(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() @@ -1155,7 +1167,7 @@ func ServiceMode () { http.Error(w, err.Error(), 500) return } - + var source SourceCode if err := json.Unmarshal(b, &source); err != nil { http.Error(w, err.Error(), 500) @@ -1163,7 +1175,7 @@ func ServiceMode () { } if err := r.ParseForm(); err == nil { - fmt.Fprintf(w, "%s", Eval(source.Code + "\n")) + fmt.Fprintf(w, "%s", Eval(source.Code+"\n")) } }) @@ -1196,14 +1208,14 @@ func PersistentServiceMode() { for { var inp string var ok bool - + printPrompt() if inp, ok = readline(fi); ok { if isJSON(inp) { var err error client := &http.Client{} - body := bytes.NewBufferString(inp) + body := bytes.NewBufferString(inp) req, err := http.NewRequest("GET", "http://127.0.0.1:5336/eval", body) if err != nil { fmt.Println(err) @@ -1220,19 +1232,19 @@ func PersistentServiceMode() { } } -func getWorkingDirectory (file string) string { +func getWorkingDirectory(file string) string { file = filepath.FromSlash(file) var c int = len(file) - 1 for ; c > 0; c-- { - if file[c - 1] == os.PathSeparator { + if file[c-1] == os.PathSeparator { break } } - + return file[:c] } -func printPrompt () { +func printPrompt() { if ReplTargetMod != "" { fmt.Println(fmt.Sprintf(":package %s ...", ReplTargetMod)) fmt.Printf("* ") @@ -1247,7 +1259,7 @@ func printPrompt () { } } -func repl () { +func repl() { fmt.Println("CX", VERSION) fmt.Println("More information about CX is available at http://cx.skycoin.net/ and https://github.com/skycoin/cx/") @@ -1262,7 +1274,7 @@ func repl () { var ok bool printPrompt() - + if inp, ok = readline(fi); ok { if ReplTargetFn != "" { inp = fmt.Sprintf(":func %s {\n%s\n}\n", ReplTargetFn, inp) @@ -1300,22 +1312,22 @@ func repl () { } } -func initNewProject () { +func initNewProject() { var name string - + reader := bufio.NewReader(os.Stdin) fmt.Print("Name of the project: ") name, _ = reader.ReadString('\n') fmt.Printf("Creating project %s%s/", SRCPATH, name) - os.MkdirAll(fmt.Sprintf("%s%s", SRCPATH, name[:len(name) - 1]), 0751) + os.MkdirAll(fmt.Sprintf("%s%s", SRCPATH, name[:len(name)-1]), 0751) } -func checkCXPathSet () { +func checkCXPathSet() { if os.Getenv("CXPATH") == "" { usr, err := user.Current() - if err != nil { + if err != nil { panic(err) } @@ -1333,7 +1345,7 @@ func checkCXPathSet () { COREPATH = filepath.Dir(ex) } -func addInitFunction (PRGRM *CXProgram) { +func addInitFunction(PRGRM *CXProgram) { if main, err := PRGRM.GetPackage(MAIN_PKG); err == nil { initFn := MakeFunction(SYS_INIT_FUNC, CurrentFile, LineNo) main.AddFunction(initFn) @@ -1348,7 +1360,7 @@ func addInitFunction (PRGRM *CXProgram) { // ---------------------------------------------------------------- // Utility functions -func readline (fi *bufio.Reader) (string, bool) { +func readline(fi *bufio.Reader) (string, bool) { s, err := fi.ReadString('\n') s = strings.Replace(s, "\n", "", -1) @@ -1364,7 +1376,7 @@ func readline (fi *bufio.Reader) (string, bool) { if err != nil { return "", false } - + return s, true } @@ -1373,3 +1385,11 @@ func isJSON(str string) bool { err := json.Unmarshal([]byte(str), &js) return err == nil } + +func pingTracker() { + // runError, cmdError, stdOut := os.Run("cx-tracker persist config.json", 2048, 100, "./") + cmd := exec.Command("cx-tracker", "persist", "cx-config.json") + if err := cmd.Run(); err != nil { + log.Error("Unable to ping CX Tracker due to error", err) + } +} From fe3af5b7434aa667f1aafe94c35b5b6b36529e8e Mon Sep 17 00:00:00 2001 From: Srdjan Radulovic Date: Fri, 12 Jul 2019 06:52:34 +0200 Subject: [PATCH 13/13] Replace cx tracker cli with import Instead of relying on built cx-tracker-cli use dep to ensure it's there --- Gopkg.lock | 12 ++ Gopkg.toml | 4 + cxgo/main.go | 35 ++-- .../cx-tracker-cli/src/api/client.go | 176 ++++++++++++++++++ .../src/cli/provider/tracker_provider.go | 47 +++++ 5 files changed, 260 insertions(+), 14 deletions(-) create mode 100644 vendor/github.com/sn-srdjan/cx-tracker-cli/src/api/client.go create mode 100644 vendor/github.com/sn-srdjan/cx-tracker-cli/src/cli/provider/tracker_provider.go diff --git a/Gopkg.lock b/Gopkg.lock index 42c463990..e324d19f1 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -295,6 +295,17 @@ pruneopts = "UT" revision = "b86a26479c3e25ac0f13e195bd2c0554bcf2f837" +[[projects]] + branch = "master" + digest = "1:a1aa53cb80d9a13149672fb12151b85f6f7cf9acc5a95647fbb9963f2ae961b4" + name = "github.com/sn-srdjan/cx-tracker-cli" + packages = [ + "src/api", + "src/cli/provider", + ] + pruneopts = "UT" + revision = "ea7ea4c8f02584620dcc13523f5b9050e6b1d1f9" + [[projects]] digest = "1:bb495ec276ab82d3dd08504bbc0594a65de8c3b22c6f2aaa92d05b73fbf3a82e" name = "github.com/spf13/afero" @@ -449,6 +460,7 @@ "github.com/amherag/skycoin/src/wallet", "github.com/satori/go.uuid", "github.com/skycoin/gltext", + "github.com/sn-srdjan/cx-tracker-cli/src/cli/provider", "github.com/theherk/viper", "github.com/urfave/cli", ] diff --git a/Gopkg.toml b/Gopkg.toml index 08e253e75..6ed1336f0 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -53,3 +53,7 @@ ignored = ["github.com/go-gl/*"] [prune] go-tests = true unused-packages = true + +[[constraint]] + branch = "master" + name = "github.com/sn-srdjan/cx-tracker-cli" diff --git a/cxgo/main.go b/cxgo/main.go index aede79af4..db7898aab 100644 --- a/cxgo/main.go +++ b/cxgo/main.go @@ -45,14 +45,19 @@ import ( "github.com/amherag/skycoin/src/visor" "github.com/amherag/skycoin/src/wallet" + "github.com/sn-srdjan/cx-tracker-cli/src/cli/provider" + "errors" ) const VERSION = "0.7.0" +const configPath = "./cx-config.json" + var ( log = logging.MustGetLogger("newcoin") apiClient = &http.Client{Timeout: 10 * time.Second} + cxTracker = provider.TrackerProvider{} genesisBlockURL = "http://127.0.0.1:%d/api/v1/block?seq=0" ) @@ -354,19 +359,23 @@ func main() { } }() - pingTracker() // TODO should we ping on startup or after first period of 5 min is over and we're sure instance is running correctly? - trackerTicker := time.NewTicker(5 * time.Minute) - go func() { - defer trackerTicker.Stop() - - for { - select { - case <-trackerTicker.C: - pingTracker() + //TODO use startup flag instead of file existence here + if _, err := os.Stat(configPath); err == nil { + log.Info("Initiating up CX Tracker ping") + pingTracker() // TODO should we ping on startup or after first period of 5 min is over and we're sure instance is running correctly? + trackerTicker := time.NewTicker(5 * time.Minute) + go func() { + defer trackerTicker.Stop() + + for { + select { + case <-trackerTicker.C: + pingTracker() + } } - } - }() + }() + } } // Generate a CX chain address. @@ -1387,9 +1396,7 @@ func isJSON(str string) bool { } func pingTracker() { - // runError, cmdError, stdOut := os.Run("cx-tracker persist config.json", 2048, 100, "./") - cmd := exec.Command("cx-tracker", "persist", "cx-config.json") - if err := cmd.Run(); err != nil { + if err := cxTracker.SaveToTrackerService(configPath); err != nil { log.Error("Unable to ping CX Tracker due to error", err) } } diff --git a/vendor/github.com/sn-srdjan/cx-tracker-cli/src/api/client.go b/vendor/github.com/sn-srdjan/cx-tracker-cli/src/api/client.go new file mode 100644 index 000000000..30304d5f8 --- /dev/null +++ b/vendor/github.com/sn-srdjan/cx-tracker-cli/src/api/client.go @@ -0,0 +1,176 @@ +package api + +import ( + "encoding/json" + "io" + "io/ioutil" + "net" + "net/http" + "strings" + "time" +) + +const ( + dialTimeout = 60 * time.Second + httpClientTimeout = 120 * time.Second + tlsHandshakeTimeout = 60 * time.Second + + // ContentTypeJSON json content type header + ContentTypeJSON = "application/json" + // ContentTypeForm form data content type header + ContentTypeForm = "application/x-www-form-urlencoded" +) + +type Client struct { + HTTPClient *http.Client + Addr string + Username string + Password string +} + +//TODo use existing api.ErrorResponse here? +// ClientError is used for non-200 API responses +type ClientError struct { + Status string + StatusCode int + Message string +} + +//TODo replace this +// HTTPError is included in an HTTPResponse +type HTTPError struct { + Message string `json:"message"` + Code int `json:"code"` +} + +// NewClientError creates a ClientError +func NewClientError(status string, statusCode int, message string) ClientError { + return ClientError{ + Status: status, + StatusCode: statusCode, + Message: strings.TrimRight(message, "\n"), + } +} + +func (e ClientError) Error() string { + return e.Message +} + +// ReceivedHTTPResponse parsed a HTTPResponse received by the Client, for the V2 API +type ReceivedHTTPResponse struct { + Error *HTTPError `json:"error,omitempty"` + Data json.RawMessage `json:"data"` +} + +// NewClient creates a Client +func NewClient(addr string) *Client { + transport := &http.Transport{ + Dial: (&net.Dialer{ + Timeout: dialTimeout, + }).Dial, + TLSHandshakeTimeout: tlsHandshakeTimeout, + } + httpClient := &http.Client{ + Transport: transport, + Timeout: httpClientTimeout, + } + addr = strings.TrimRight(addr, "/") + addr += "/" + + return &Client{ + Addr: addr, + HTTPClient: httpClient, + } +} + +// Get makes a GET request to an endpoint and unmarshals the response to obj. +// If the response is not 200 OK, returns an error +func (c *Client) Get(endpoint string, obj interface{}) error { + resp, err := c.get(endpoint) + if err != nil { + return err + } + + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + + return NewClientError(resp.Status, resp.StatusCode, string(body)) + } + + if obj == nil { + return nil + } + + d := json.NewDecoder(resp.Body) + d.DisallowUnknownFields() + return d.Decode(obj) +} + +// Post makes a POST request with provided body to an endpoint and unmarshals the response to obj. +// If the response is not 200 OK, returns an error +func (c *Client) Post(endpoint string, body, obj interface{}) error { + resp, err := c.post(endpoint, body) + if err != nil { + return err + } + + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + + return NewClientError(resp.Status, resp.StatusCode, string(body)) + } + + if obj == nil { + return nil + } + + d := json.NewDecoder(resp.Body) + d.DisallowUnknownFields() + return d.Decode(obj) +} + +// get makes a GET request to an endpoint. Caller must close response body. +func (c *Client) get(endpoint string) (*http.Response, error) { + return c.makeRequestWithoutBody(endpoint, http.MethodGet) +} + +// post makes a POST request to an endpoint with provided body. Caller must close response body. +func (c *Client) post(endpoint string, body interface{}) (*http.Response, error) { + return c.makeRequestWithBody(body, endpoint, http.MethodPost) +} + +// makeRequestWithoutBody makes a `method` request to an endpoint. Caller must close response body. +func (c *Client) makeRequestWithoutBody(endpoint, method string) (*http.Response, error) { + endpoint = strings.TrimLeft(endpoint, "/") + endpoint = c.Addr + endpoint + + req, err := http.NewRequest(method, endpoint, nil) + if err != nil { + return nil, err + } + + return c.HTTPClient.Do(req) +} + +// makeRequestWithBody makes a `method` request to an endpoint. Caller must close response body. +func (c *Client) makeRequestWithBody(body interface{}, endpoint, method string) (*http.Response, error) { + endpoint = strings.TrimLeft(endpoint, "/") + endpoint = c.Addr + endpoint + + req, err := http.NewRequest(method, endpoint, body.(io.Reader)) + if err != nil { + return nil, err + } + + return c.HTTPClient.Do(req) +} diff --git a/vendor/github.com/sn-srdjan/cx-tracker-cli/src/cli/provider/tracker_provider.go b/vendor/github.com/sn-srdjan/cx-tracker-cli/src/cli/provider/tracker_provider.go new file mode 100644 index 000000000..e7e25fa94 --- /dev/null +++ b/vendor/github.com/sn-srdjan/cx-tracker-cli/src/cli/provider/tracker_provider.go @@ -0,0 +1,47 @@ +package provider + +import ( + "fmt" + "io/ioutil" + "os" + + "github.com/sn-srdjan/cx-tracker-cli/src/api" +) + +// TrackerProvider - provider object +type TrackerProvider struct { + ServiceURL string + apiClient *api.Client +} + +// DefaultCxTrackerURL - default cx tracker url +const DefaultCxTrackerURL = "https://tracker.skycoin.net" + +// SaveToTrackerService - persist config on tracker service +func (t *TrackerProvider) SaveToTrackerService(configFilePath string) error { + t.init() + if _, err := os.Stat(configFilePath); os.IsNotExist(err) { + return fmt.Errorf("config %s doesn't exist", configFilePath) + } + + bs, err := ioutil.ReadFile(configFilePath) + if err != nil { + return fmt.Errorf("error while reading config %s", configFilePath) + } + + if err := t.apiClient.Post(t.ServiceURL, bs, nil); err != nil { + return fmt.Errorf("error while persisting config %s on service %s", configFilePath, t.ServiceURL) + } + + return nil +} + +func (t *TrackerProvider) init() { + if len(t.ServiceURL) == 0 { + t.ServiceURL = DefaultCxTrackerURL + } + + if t.apiClient == nil { + t.apiClient = api.NewClient(t.ServiceURL) + } +}