DERO-HE STARGATE Mainnet Release47

This commit is contained in:
Captain 2022-03-03 10:49:59 +00:00
parent c2113b6cae
commit fa5060291a
No known key found for this signature in database
GPG Key ID: 18CDB3ED5E85D2D4
27 changed files with 386 additions and 139 deletions

View File

@ -1503,6 +1503,7 @@ func (chain *Blockchain) get_ordered_past(tip crypto.Hash, tillheight int64) (or
// this will flip chain top, depending on which block has more work // this will flip chain top, depending on which block has more work
// more worked block is normally identified in < 2 secs // more worked block is normally identified in < 2 secs
func (chain *Blockchain) flip_top() { func (chain *Blockchain) flip_top() {
return
chain.Lock() chain.Lock()
defer chain.Unlock() defer chain.Unlock()

View File

@ -1,4 +1,4 @@
// Copyright 2017-2021 DERO Project. All rights reserved. // Copyright 2017-2022 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license. // Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file. // license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 // GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
@ -18,30 +18,8 @@ package blockchain
// this file installs hard coded contracts // this file installs hard coded contracts
//import "fmt"
import _ "embed" import _ "embed"
/*
import "strings"
import "strconv"
import "encoding/hex"
import "encoding/binary"
import "math/big"
import "golang.org/x/xerrors"
import "github.com/deroproject/derohe/cryptography/bn256"
import "github.com/deroproject/derohe/transaction"
import "github.com/deroproject/derohe/config"
import "github.com/deroproject/derohe/premine"
import "github.com/deroproject/derohe/globals"
import "github.com/deroproject/derohe/block"
import "github.com/deroproject/derohe/rpc"
*/
import "github.com/deroproject/graviton" import "github.com/deroproject/graviton"
import "github.com/deroproject/derohe/dvm" import "github.com/deroproject/derohe/dvm"
import "github.com/deroproject/derohe/cryptography/crypto" import "github.com/deroproject/derohe/cryptography/crypto"
@ -49,28 +27,45 @@ import "github.com/deroproject/derohe/cryptography/crypto"
//go:embed hardcoded_sc/nameservice.bas //go:embed hardcoded_sc/nameservice.bas
var source_nameservice string var source_nameservice string
//go:embed hardcoded_sc/nameservice_updateable.bas
var source_nameservice_updateable string
// process the miner tx, giving fees, miner rewatd etc // process the miner tx, giving fees, miner rewatd etc
func (chain *Blockchain) install_hardcoded_contracts(cache map[crypto.Hash]*graviton.Tree, ss *graviton.Snapshot, balance_tree *graviton.Tree, sc_tree *graviton.Tree, height uint64) (err error) { func (chain *Blockchain) install_hardcoded_contracts(cache map[crypto.Hash]*graviton.Tree, ss *graviton.Snapshot, balance_tree *graviton.Tree, sc_tree *graviton.Tree, height uint64) (err error) {
if height != 0 { if height == 0 {
if _, _, err = dvm.ParseSmartContract(source_nameservice); err != nil {
logger.Error(err, "error Parsing hard coded sc")
panic(err)
return
}
var name crypto.Hash
name[31] = 1
if err = chain.install_hardcoded_sc(cache, ss, balance_tree, sc_tree, source_nameservice, name); err != nil {
panic(err)
return
}
return return
} }
if _, _, err = dvm.ParseSmartContract(source_nameservice); err != nil { if height == 21480 { // update SC at specific height
logger.Error(err, "error Parsing hard coded sc") if _, _, err = dvm.ParseSmartContract(source_nameservice_updateable); err != nil {
panic(err) logger.Error(err, "error Parsing hard coded sc")
return panic(err)
} return
}
var name crypto.Hash var name crypto.Hash
name[31] = 1 name[31] = 1
if err = chain.install_hardcoded_sc(cache, ss, balance_tree, sc_tree, source_nameservice, name); err != nil { if err = chain.install_hardcoded_sc(cache, ss, balance_tree, sc_tree, source_nameservice_updateable, name); err != nil {
panic(err) panic(err)
return return
}
} }
//fmt.Printf("source code embedded %s\n",source_nameservice)
return return
} }

View File

@ -0,0 +1,54 @@
/* Name Service SMART CONTRACT in DVM-BASIC.
Allows a user to register names which could be looked by wallets for easy to use name while transfer
*/
// This function is used to initialize parameters during install time
Function Initialize() Uint64
10 RETURN 0
End Function
// Register a name, limit names of 5 or less length
Function Register(name String) Uint64
10 IF EXISTS(name) THEN GOTO 50 // if name is already used, it cannot reregistered
15 IF STRLEN(name) >= 64 THEN GOTO 50 // skip names misuse
20 IF STRLEN(name) >= 6 THEN GOTO 40
30 IF SIGNER() == address_raw("deto1qyvyeyzrcm2fzf6kyq7egkes2ufgny5xn77y6typhfx9s7w3mvyd5qqynr5hx") THEN GOTO 40
35 IF SIGNER() != address_raw("deto1qy0ehnqjpr0wxqnknyc66du2fsxyktppkr8m8e6jvplp954klfjz2qqdzcd8p") THEN GOTO 50
40 STORE(name,SIGNER())
50 RETURN 0
End Function
// This function is used to change owner of Name is an string form of address
Function TransferOwnership(name String,newowner String) Uint64
10 IF LOAD(name) != SIGNER() THEN GOTO 30
20 STORE(name,ADDRESS_RAW(newowner))
30 RETURN 0
End Function
// This function is used to change SC owner
Function TransferSCOwnership(newowner String) Uint64
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
20 RETURN 1
30 STORE("own1",ADDRESS_RAW(newowner))
40 RETURN 0
End Function
// Until the new owner claims ownership, existing owner remains owner
Function ClaimSCOwnership() Uint64
10 IF LOAD("own1") == SIGNER() THEN GOTO 30
20 RETURN 1
30 STORE("owner",SIGNER()) // ownership claim successful
40 RETURN 0
End Function
// If signer is owner, provide him rights to update code anytime
// make sure update is always available to SC
Function UpdateCode(SC_CODE String) Uint64
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
20 RETURN 1
30 UPDATE_SC_CODE(SC_CODE)
40 RETURN 0
End Function

View File

@ -46,7 +46,7 @@ var mainnet_hard_forks = []Hard_fork{
// {1, 0,0,0,0,true}, // dummy entry so as we can directly use the fork index into this entry // {1, 0,0,0,0,true}, // dummy entry so as we can directly use the fork index into this entry
{1, 0, 0, 0, 0, true}, // version 1 hard fork where genesis block landed and chain migration occurs {1, 0, 0, 0, 0, true}, // version 1 hard fork where genesis block landed and chain migration occurs
// version 1 has difficulty hardcoded to 1 // version 1 has difficulty hardcoded to 1
//{2, 95551, 0, 0, 0, true}, // version 2 hard fork where Atlantis bootstraps , it's mandatory //{2, 10, 0, 0, 0, true}, // version 2 hard fork where SC gets update functionality , it's mandatory
// {3, 721000, 0, 0, 0, true}, // version 3 hard fork emission fix, it's mandatory // {3, 721000, 0, 0, 0, true}, // version 3 hard fork emission fix, it's mandatory
} }

View File

@ -91,6 +91,8 @@ func (s *storetopofs) Write(index int64, blid [32]byte, state_version uint64, he
_, err = s.topomapping.WriteAt(buf[:], index*TOPORECORD_SIZE) _, err = s.topomapping.WriteAt(buf[:], index*TOPORECORD_SIZE)
s.topomapping.Sync() // looks like this is the cause of corruption
return err return err
} }

View File

@ -17,7 +17,7 @@ bash $ABSDIR/build_package.sh "./cmd/explorer"
bash $ABSDIR/build_package.sh "./cmd/dero-wallet-cli" bash $ABSDIR/build_package.sh "./cmd/dero-wallet-cli"
bash $ABSDIR/build_package.sh "./cmd/dero-miner" bash $ABSDIR/build_package.sh "./cmd/dero-miner"
#bash $ABSDIR/build_package.sh "./cmd/simulator" #bash $ABSDIR/build_package.sh "./cmd/simulator"
bash $ABSDIR/build_package.sh "./cmd/rpc_examples/pong_server" #bash $ABSDIR/build_package.sh "./cmd/rpc_examples/pong_server"
for d in build/*; do cp Start.md "$d"; done for d in build/*; do cp Start.md "$d"; done

View File

@ -895,7 +895,6 @@ func usage(w io.Writer) {
io.WriteString(w, "\t\033[1mhelp\033[0m\t\tthis help\n") io.WriteString(w, "\t\033[1mhelp\033[0m\t\tthis help\n")
io.WriteString(w, "\t\033[1maddress\033[0m\t\tDisplay user address\n") io.WriteString(w, "\t\033[1maddress\033[0m\t\tDisplay user address\n")
io.WriteString(w, "\t\033[1mbalance\033[0m\t\tDisplay user balance\n") io.WriteString(w, "\t\033[1mbalance\033[0m\t\tDisplay user balance\n")
io.WriteString(w, "\t\033[1mget_tx_key\033[0m\tDisplay tx proof to prove receiver for specific transaction\n")
io.WriteString(w, "\t\033[1mintegrated_address\033[0m\tDisplay random integrated address (with encrypted payment ID)\n") io.WriteString(w, "\t\033[1mintegrated_address\033[0m\tDisplay random integrated address (with encrypted payment ID)\n")
io.WriteString(w, "\t\033[1mmenu\033[0m\t\tEnable menu mode\n") io.WriteString(w, "\t\033[1mmenu\033[0m\t\tEnable menu mode\n")
io.WriteString(w, "\t\033[1mrescan_bc\033[0m\tRescan blockchain to re-obtain transaction history \n") io.WriteString(w, "\t\033[1mrescan_bc\033[0m\tRescan blockchain to re-obtain transaction history \n")
@ -909,7 +908,6 @@ func usage(w io.Writer) {
io.WriteString(w, "\t\033[1mtransfer\033[0m\tTransfer/Send DERO to another address\n") io.WriteString(w, "\t\033[1mtransfer\033[0m\tTransfer/Send DERO to another address\n")
io.WriteString(w, "\t\t\tEg. transfer <address> <amount>\n") io.WriteString(w, "\t\t\tEg. transfer <address> <amount>\n")
io.WriteString(w, "\t\033[1mtransfer_all\033[0m\tTransfer everything to another address\n") io.WriteString(w, "\t\033[1mtransfer_all\033[0m\tTransfer everything to another address\n")
io.WriteString(w, "\t\033[1mflush\033[0m\tFlush local wallet pool (for testing purposes)\n")
io.WriteString(w, "\t\033[1mversion\033[0m\t\tShow version\n") io.WriteString(w, "\t\033[1mversion\033[0m\t\tShow version\n")
io.WriteString(w, "\t\033[1mbye\033[0m\t\tQuit wallet\n") io.WriteString(w, "\t\033[1mbye\033[0m\t\tQuit wallet\n")
io.WriteString(w, "\t\033[1mexit\033[0m\t\tQuit wallet\n") io.WriteString(w, "\t\033[1mexit\033[0m\t\tQuit wallet\n")

View File

@ -223,6 +223,42 @@ func main() {
p2p.Broadcast_MiniBlock(mbl, peerid) p2p.Broadcast_MiniBlock(mbl, peerid)
} }
{
current_blid, err := chain.Load_Block_Topological_order_at_index(17600)
if err == nil {
current_blid := current_blid
for {
height := chain.Load_Height_for_BL_ID(current_blid)
if height < 17500 {
break
}
r, err := chain.Store.Topo_store.Read(int64(height))
if err != nil {
panic(err)
}
if r.BLOCK_ID != current_blid {
fmt.Printf("Fixing corruption r %+v , current_blid %s current_blid_height %d\n", r, current_blid, height)
fix_commit_version, err := chain.ReadBlockSnapshotVersion(current_blid)
if err != nil {
panic(err)
}
chain.Store.Topo_store.Write(int64(height), current_blid, fix_commit_version, int64(height))
}
fix_bl, err := chain.Load_BL_FROM_ID(current_blid)
if err != nil {
panic(err)
}
current_blid = fix_bl.Tips[0]
}
}
}
globals.Cron.Start() // start cron jobs globals.Cron.Start() // start cron jobs
// This tiny goroutine continuously updates status as required // This tiny goroutine continuously updates status as required
@ -624,6 +660,50 @@ restart_loop:
err, _ = chain.Add_Complete_Block(cbl) err, _ = chain.Add_Complete_Block(cbl)
fmt.Printf("err adding block %s\n", err) fmt.Printf("err adding block %s\n", err)
case command == "fix":
tips := chain.Get_TIPS()
current_blid := tips[0]
for {
height := chain.Load_Height_for_BL_ID(current_blid)
//fmt.Printf("checking height %d\n", height)
if height < 1 {
break
}
r, err := chain.Store.Topo_store.Read(int64(height))
if err != nil {
panic(err)
}
if r.BLOCK_ID != current_blid {
fmt.Printf("corruption due to XYZ r %+v , current_blid %s current_blid_height\n", r, current_blid, height)
fix_commit_version, err := chain.ReadBlockSnapshotVersion(current_blid)
if err != nil {
panic(err)
}
chain.Store.Topo_store.Write(int64(height), current_blid, fix_commit_version, int64(height))
}
fix_bl, err := chain.Load_BL_FROM_ID(current_blid)
if err != nil {
panic(err)
}
current_blid = fix_bl.Tips[0]
/* fix_commit_version, err = chain.ReadBlockSnapshotVersion(current_block_id)
if err != nil {
panic(err)
}
*/
}
case command == "print_block": case command == "print_block":
fmt.Printf("printing block\n") fmt.Printf("printing block\n")

View File

@ -75,11 +75,8 @@ func SendJob() {
var params rpc.GetBlockTemplate_Result var params rpc.GetBlockTemplate_Result
var buf bytes.Buffer
encoder := json.NewEncoder(&buf)
// get a block template, and then we will fill the address here as optimization // get a block template, and then we will fill the address here as optimization
bl, mbl, _, _, err := chain.Create_new_block_template_mining(chain.IntegratorAddress()) bl, mbl_main, _, _, err := chain.Create_new_block_template_mining(chain.IntegratorAddress())
if err != nil { if err != nil {
return return
} }
@ -94,7 +91,7 @@ func SendJob() {
params.Height = bl.Height params.Height = bl.Height
params.Prev_Hash = prev_hash params.Prev_Hash = prev_hash
if mbl.HighDiff { if mbl_main.HighDiff {
diff.Mul(diff, new(big.Int).SetUint64(config.MINIBLOCK_HIGHDIFF)) diff.Mul(diff, new(big.Int).SetUint64(config.MINIBLOCK_HIGHDIFF))
} }
params.Difficultyuint64 = diff.Uint64() params.Difficultyuint64 = diff.Uint64()
@ -102,33 +99,44 @@ func SendJob() {
client_list_mutex.Lock() client_list_mutex.Lock()
defer client_list_mutex.Unlock() defer client_list_mutex.Unlock()
for k, v := range client_list { for rk, rv := range client_list {
if !mbl.Final { //write miners address only if possible
copy(mbl.KeyHash[:], v.address_sum[:])
}
for i := range mbl.Nonce { // give each user different work go func(k *websocket.Conn, v *user_session) {
mbl.Nonce[i] = globals.Global_Random.Uint32() // fill with randomness defer globals.Recover(2)
} var buf bytes.Buffer
encoder := json.NewEncoder(&buf)
if v.lasterr != "" { mbl := mbl_main
params.LastError = v.lasterr
v.lasterr = ""
}
if !v.valid_address && !chain.IsAddressHashValid(false, v.address_sum) { if !mbl.Final { //write miners address only if possible
params.LastError = "unregistered miner or you need to wait 15 mins" copy(mbl.KeyHash[:], v.address_sum[:])
} else { }
params.LastError = ""
v.valid_address = true
}
params.Blockhashing_blob = fmt.Sprintf("%x", mbl.Serialize())
params.Blocks = v.blocks
params.MiniBlocks = v.miniblocks
encoder.Encode(params) for i := range mbl.Nonce { // give each user different work
k.WriteMessage(websocket.TextMessage, buf.Bytes()) mbl.Nonce[i] = globals.Global_Random.Uint32() // fill with randomness
buf.Reset() }
if v.lasterr != "" {
params.LastError = v.lasterr
v.lasterr = ""
}
if !v.valid_address && !chain.IsAddressHashValid(false, v.address_sum) {
params.LastError = "unregistered miner or you need to wait 15 mins"
} else {
params.LastError = ""
v.valid_address = true
}
params.Blockhashing_blob = fmt.Sprintf("%x", mbl.Serialize())
params.Blocks = v.blocks
params.MiniBlocks = v.miniblocks
encoder.Encode(params)
k.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
k.WriteMessage(websocket.TextMessage, buf.Bytes())
buf.Reset()
}(rk, rv)
} }
@ -139,7 +147,7 @@ func newUpgrader() *websocket.Upgrader {
u.OnMessage(func(c *websocket.Conn, messageType websocket.MessageType, data []byte) { u.OnMessage(func(c *websocket.Conn, messageType websocket.MessageType, data []byte) {
// echo // echo
c.WriteMessage(messageType, data) //c.WriteMessage(messageType, data)
if messageType != websocket.TextMessage { if messageType != websocket.TextMessage {
return return
@ -148,7 +156,7 @@ func newUpgrader() *websocket.Upgrader {
sess := c.Session().(*user_session) sess := c.Session().(*user_session)
client_list_mutex.Lock() client_list_mutex.Lock()
client_list_mutex.Unlock() defer client_list_mutex.Unlock()
var p rpc.SubmitBlock_Params var p rpc.SubmitBlock_Params
@ -180,8 +188,9 @@ func newUpgrader() *websocket.Upgrader {
}) })
u.OnClose(func(c *websocket.Conn, err error) { u.OnClose(func(c *websocket.Conn, err error) {
client_list_mutex.Lock() client_list_mutex.Lock()
defer client_list_mutex.Unlock()
delete(client_list, c) delete(client_list, c)
client_list_mutex.Unlock()
}) })
return u return u
@ -213,8 +222,9 @@ func onWebsocket(w http.ResponseWriter, r *http.Request) {
wsConn.SetSession(&session) wsConn.SetSession(&session)
client_list_mutex.Lock() client_list_mutex.Lock()
defer client_list_mutex.Unlock()
client_list[wsConn] = &session client_list[wsConn] = &session
client_list_mutex.Unlock()
} }
func Getwork_server() { func Getwork_server() {

View File

@ -20,4 +20,4 @@ import "github.com/blang/semver/v4"
// right now it has to be manually changed // right now it has to be manually changed
// do we need to include git commitsha?? // do we need to include git commitsha??
var Version = semver.MustParse("3.4.123-0.DEROHE.STARGATE+26022022") var Version = semver.MustParse("3.4.130-0.DEROHE.STARGATE+26022022")

View File

@ -71,6 +71,8 @@ var ClockOffset time.Duration //Clock Offset related to all the peer2 connected
var backoff = map[string]int64{} // if server receives a connection, then it will not initiate connection to that ip for another 60 secs var backoff = map[string]int64{} // if server receives a connection, then it will not initiate connection to that ip for another 60 secs
var backoff_mutex = sync.Mutex{} var backoff_mutex = sync.Mutex{}
var Min_Peers = int64(31) // we need to expose this to be modifieable at runtime without taking daemon offline
// return true if we should back off else we can connect // return true if we should back off else we can connect
func shouldwebackoff(ip string) bool { func shouldwebackoff(ip string) bool {
backoff_mutex.Lock() backoff_mutex.Lock()
@ -250,7 +252,7 @@ func P2P_engine() {
func tunekcp(conn *kcp.UDPSession) { func tunekcp(conn *kcp.UDPSession) {
conn.SetACKNoDelay(true) conn.SetACKNoDelay(true)
conn.SetNoDelay(1, 10, 2, 1) // tuning paramters for local stack conn.SetNoDelay(0, 40, 0, 0) // tuning paramters for local stack
} }
// will try to connect with given endpoint // will try to connect with given endpoint
@ -396,7 +398,6 @@ func maintain_seed_node_connection() {
// keep building connections to network, we are talking outgoing connections // keep building connections to network, we are talking outgoing connections
func maintain_connection_to_peers() { func maintain_connection_to_peers() {
Min_Peers := int64(31) // we need to expose this to be modifieable at runtime without taking daemon offline
// check how many connections are active // check how many connections are active
if _, ok := globals.Arguments["--min-peers"]; ok && globals.Arguments["--min-peers"] != nil { // user specified a limit, use it if possible if _, ok := globals.Arguments["--min-peers"]; ok && globals.Arguments["--min-peers"] != nil { // user specified a limit, use it if possible
i, err := strconv.ParseInt(globals.Arguments["--min-peers"].(string), 10, 64) i, err := strconv.ParseInt(globals.Arguments["--min-peers"].(string), 10, 64)
@ -469,6 +470,13 @@ func P2P_Server_v2() {
connection := &Connection{Client: c, Conn: conn, ConnTls: tlsconn, Addr: remote_addr, State: HANDSHAKE_PENDING, Incoming: true} connection := &Connection{Client: c, Conn: conn, ConnTls: tlsconn, Addr: remote_addr, State: HANDSHAKE_PENDING, Incoming: true}
connection.logger = logger.WithName("incoming").WithName(remote_addr.String()) connection.logger = logger.WithName("incoming").WithName(remote_addr.String())
in, out := Peer_Direction_Count()
if int64(in+out) > Min_Peers { // do not allow incoming ddos
connection.exit()
return
}
c.State.Set("c", connection) // set pointer to connection c.State.Set("c", connection) // set pointer to connection
//connection.logger.Info("connected OnConnect") //connection.logger.Info("connected OnConnect")

View File

@ -323,3 +323,21 @@ func get_peer_list() (peers []Peer_Info) {
} }
return return
} }
func get_peer_list_specific(addr string) (peers []Peer_Info) {
plist := get_peer_list()
sort.SliceStable(plist, func(i, j int) bool { return plist[i].Addr < plist[j].Addr })
if len(plist) <= 7 {
peers = plist
} else {
index := sort.Search(len(plist), func(i int) bool { return plist[i].Addr < addr })
for i := range plist {
peers = append(peers, plist[(i+index)%len(plist)])
if len(peers) >= 7 {
break
}
}
}
return peers
}

View File

@ -45,8 +45,6 @@ func (handshake *Handshake_Struct) Fill() {
// handshake.Flags = // add any flags necessary // handshake.Flags = // add any flags necessary
//scan our peer list and send peers which have been recently communicated
handshake.PeerList = get_peer_list()
copy(handshake.Network_ID[:], globals.Config.Network_ID[:]) copy(handshake.Network_ID[:], globals.Config.Network_ID[:])
} }
@ -57,6 +55,9 @@ func (connection *Connection) dispatch_test_handshake() {
var request, response Handshake_Struct var request, response Handshake_Struct
request.Fill() request.Fill()
//scan our peer list and send peers which have been recently communicated
request.PeerList = get_peer_list_specific(Address(connection))
ctx, _ := context.WithTimeout(context.Background(), 4*time.Second) ctx, _ := context.WithTimeout(context.Background(), 4*time.Second)
if err := connection.Client.CallWithContext(ctx, "Peer.Handshake", request, &response); err != nil { if err := connection.Client.CallWithContext(ctx, "Peer.Handshake", request, &response); err != nil {
connection.logger.V(4).Error(err, "cannot handshake") connection.logger.V(4).Error(err, "cannot handshake")

View File

@ -0,0 +1,22 @@
name: Close inactive issues
on:
schedule:
- cron: "30 1 * * *"
jobs:
close-issues:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v3
with:
days-before-issue-stale: 30
days-before-issue-close: 14
stale-issue-label: "stale"
stale-issue-message: "This issue is stale because it has been open for 30 days with no activity."
close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale."
days-before-pr-stale: -1
days-before-pr-close: -1
repo-token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -61,16 +61,17 @@
## Features ## Features
- [x] linux: epoll - [x] linux: epoll, both ET/LT(default) supported
- [x] macos(bsd): kqueue - [x] macos(bsd): kqueue
- [x] windows: golang std net - [x] windows: golang std net
- [x] nbio.Conn implements a non-blocking net.Conn(except windows) - [x] nbio.Conn implements a non-blocking net.Conn(except windows)
- [x] writev supported - [x] writev supported
- [x] least dependency - [x] concurrent write/close supported(both nbio.Conn and nbio/nbhttp/websocket.Conn)
- [x] TLS supported - [x] TLS supported
- [x] HTTP/HTTPS 1.x - [x] HTTP/HTTPS 1.x
- [x] Websocket, [Passes the Autobahn Test Suite](https://lesismal.github.io/nbio/websocket) - [x] Websocket, [Passes the Autobahn Test Suite](https://lesismal.github.io/nbio/websocket), `OnOpen/OnMessage/OnClose` order guaranteed
- [ ] HTTP 2.0 - [ ] HTTP 2.0(no plans, 2.0 is not good enough)
## Installation ## Installation

View File

@ -240,7 +240,7 @@ func min(a, b int) int {
func handlerIndex() func(w http.ResponseWriter, r *http.Request) { func handlerIndex() func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
if *verbose { if *verbose {
log.Printf("reqeust to %s", r.URL) log.Printf("reqeust to %s", r.URL.Path)
} }
if r.URL.Path != "/" { if r.URL.Path != "/" {
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)

View File

@ -61,9 +61,9 @@ func (c *Conn) Read(b []byte) (int, error) {
c.mux.Unlock() c.mux.Unlock()
return 0, errClosed return 0, errClosed
} }
c.mux.Unlock()
n, err := syscall.Read(c.fd, b) n, err := syscall.Read(c.fd, b)
c.mux.Unlock()
if err == nil { if err == nil {
c.g.afterRead(c) c.g.afterRead(c)
} }

View File

@ -6,6 +6,7 @@ package nbio
import ( import (
"container/heap" "container/heap"
"context"
"net" "net"
"runtime" "runtime"
"sync" "sync"
@ -78,7 +79,7 @@ type Config struct {
LockPoller bool LockPoller bool
// EpollMod sets the epoll mod, EPOLLLT by default. // EpollMod sets the epoll mod, EPOLLLT by default.
EpollMod int EpollMod uint32
} }
// Gopher is a manager of poller. // Gopher is a manager of poller.
@ -87,6 +88,8 @@ type Gopher struct {
mux sync.Mutex mux sync.Mutex
tmux sync.Mutex tmux sync.Mutex
wgConn sync.WaitGroup
Name string Name string
network string network string
@ -97,7 +100,7 @@ type Gopher struct {
maxWriteBufferSize int maxWriteBufferSize int
maxReadTimesPerEventLoop int maxReadTimesPerEventLoop int
minConnCacheSize int minConnCacheSize int
epollMod int epollMod uint32
lockListener bool lockListener bool
lockPoller bool lockPoller bool
@ -130,40 +133,68 @@ type Gopher struct {
Execute func(f func()) Execute func(f func())
} }
// Stop pollers. // Stop closes listeners/pollers/conns/timer.
func (g *Gopher) Stop() { func (g *Gopher) Stop() {
g.onStop()
g.trigger.Stop()
close(g.chTimer)
for _, l := range g.listeners { for _, l := range g.listeners {
l.stop() l.stop()
} }
for i := 0; i < g.pollerNum; i++ {
g.pollers[i].stop()
}
g.mux.Lock() g.mux.Lock()
conns := g.connsStd conns := g.connsStd
g.connsStd = map[*Conn]struct{}{} g.connsStd = map[*Conn]struct{}{}
connsUnix := g.connsUnix connsUnix := g.connsUnix
g.mux.Unlock() g.mux.Unlock()
g.wgConn.Done()
for c := range conns { for c := range conns {
if c != nil { if c != nil {
c.Close() cc := c
g.atOnce(func() {
cc.Close()
})
} }
} }
for _, c := range connsUnix { for _, c := range connsUnix {
if c != nil { if c != nil {
go c.Close() cc := c
g.atOnce(func() {
cc.Close()
})
} }
} }
g.wgConn.Wait()
time.Sleep(time.Second / 5)
g.onStop()
g.trigger.Stop()
close(g.chTimer)
for i := 0; i < g.pollerNum; i++ {
g.pollers[i].stop()
}
g.Wait() g.Wait()
logging.Info("Gopher[%v] stop", g.Name) logging.Info("Gopher[%v] stop", g.Name)
} }
// Shutdown stops Gopher gracefully with context.
func (g *Gopher) Shutdown(ctx context.Context) error {
ch := make(chan struct{})
go func() {
g.Stop()
close(ch)
}()
select {
case <-ch:
case <-ctx.Done():
return ctx.Err()
}
return nil
}
// AddConn adds conn to a poller. // AddConn adds conn to a poller.
func (g *Gopher) AddConn(conn net.Conn) (*Conn, error) { func (g *Gopher) AddConn(conn net.Conn) (*Conn, error) {
c, err := NBConn(conn) c, err := NBConn(conn)
@ -179,7 +210,10 @@ func (g *Gopher) OnOpen(h func(c *Conn)) {
if h == nil { if h == nil {
panic("invalid nil handler") panic("invalid nil handler")
} }
g.onOpen = h g.onOpen = func(c *Conn) {
g.wgConn.Add(1)
h(c)
}
} }
// OnClose registers callback for disconnected. // OnClose registers callback for disconnected.
@ -188,9 +222,10 @@ func (g *Gopher) OnClose(h func(c *Conn, err error)) {
panic("invalid nil handler") panic("invalid nil handler")
} }
g.onClose = func(c *Conn, err error) { g.onClose = func(c *Conn, err error) {
g.atOnce(func() { // g.atOnce(func() {
h(c, err) defer g.wgConn.Done()
}) h(c, err)
// })
} }
} }
@ -425,6 +460,7 @@ func (g *Gopher) PollerBuffer(c *Conn) []byte {
} }
func (g *Gopher) initHandlers() { func (g *Gopher) initHandlers() {
g.wgConn.Add(1)
g.OnOpen(func(c *Conn) {}) g.OnOpen(func(c *Conn) {})
g.OnClose(func(c *Conn, err error) {}) g.OnClose(func(c *Conn, err error) {})
// g.OnRead(func(c *Conn, b []byte) ([]byte, error) { // g.OnRead(func(c *Conn, b []byte) ([]byte, error) {

View File

@ -173,9 +173,7 @@ func (c *Client) Do(req *http.Request, handler func(res *http.Response, conn net
handler(nil, nil, err) handler(nil, nil, err)
return return
} }
if hc.closed { hc.Reset()
hc.Reset()
}
hc.Do(req, func(res *http.Response, conn net.Conn, err error) { hc.Do(req, func(res *http.Response, conn net.Conn, err error) {
hcs.releaseConn(hc) hcs.releaseConn(hc)
handler(res, conn, err) handler(res, conn, err)

View File

@ -50,9 +50,13 @@ type ClientConn struct {
// Reset . // Reset .
func (c *ClientConn) Reset() { func (c *ClientConn) Reset() {
c.conn = nil c.mux.Lock()
c.handlers = nil if c.closed {
c.closed = false c.conn = nil
c.handlers = nil
c.closed = false
}
c.mux.Unlock()
} }
// OnClose . // OnClose .
@ -78,21 +82,24 @@ func (c *ClientConn) Close() {
// CloseWithError . // CloseWithError .
func (c *ClientConn) CloseWithError(err error) { func (c *ClientConn) CloseWithError(err error) {
c.mux.Lock() c.mux.Lock()
closed := c.closed defer c.mux.Unlock()
c.closed = true if !c.closed {
c.mux.Unlock() c.closed = true
if !closed {
c.closeWithErrorWithoutLock(err) c.closeWithErrorWithoutLock(err)
} }
} }
func (c *ClientConn) closeWithErrorWithoutLock(err error) { func (c *ClientConn) closeWithErrorWithoutLock(err error) {
if err == nil {
err = io.EOF
}
for _, h := range c.handlers { for _, h := range c.handlers {
h.h(nil, c.conn, err) h.h(nil, c.conn, err)
} }
c.handlers = nil c.handlers = nil
if c.conn != nil { if c.conn != nil {
c.conn.Close() c.conn.Close()
c.conn = nil
} }
if c.onClose != nil { if c.onClose != nil {
c.onClose() c.onClose()

View File

@ -329,12 +329,16 @@ func (e *Engine) stopListeners() {
// Start . // Start .
func (e *Engine) Start() error { func (e *Engine) Start() error {
err := e.startListeners() err := e.Gopher.Start()
if err != nil { if err != nil {
return err return err
} }
err = e.startListeners()
return e.Gopher.Start() if err != nil {
e.Gopher.Stop()
return err
}
return err
} }
// Stop . // Stop .
@ -387,9 +391,9 @@ func (e *Engine) Shutdown(ctx context.Context) error {
} }
Exit: Exit:
e.Stop() err := e.Shutdown(ctx)
logging.Info("Gopher[%v] shutdown", e.Gopher.Name) logging.Info("Gopher[%v] shutdown", e.Gopher.Name)
return nil return err
} }
// InitTLSBuffers . // InitTLSBuffers .

View File

@ -47,5 +47,7 @@ func NewServerTLS(conf Config, v ...interface{}) *Server {
conf.TLSConfig = tlsConfig conf.TLSConfig = tlsConfig
} }
} }
conf.AddrsTLS = append(conf.AddrsTLS, conf.Addrs...)
conf.Addrs = nil
return &Server{Engine: NewEngine(conf)} return &Server{Engine: NewEngine(conf)}
} }

View File

@ -40,11 +40,11 @@ func dupStdConn(conn net.Conn) (*Conn, error) {
conn.Close() conn.Close()
err = syscall.SetNonblock(newFd, true) // err = syscall.SetNonblock(newFd, true)
if err != nil { // if err != nil {
syscall.Close(newFd) // syscall.Close(newFd)
return nil, err // return nil, err
} // }
return &Conn{ return &Conn{
fd: newFd, fd: newFd,

View File

@ -28,13 +28,9 @@ const (
) )
const ( const (
epollEventsRead = syscall.EPOLLPRI | syscall.EPOLLIN epollEventsRead = syscall.EPOLLPRI | syscall.EPOLLIN
epollEventsWrite = syscall.EPOLLOUT epollEventsWrite = syscall.EPOLLOUT
epollEventsReadWrite = syscall.EPOLLPRI | syscall.EPOLLIN | syscall.EPOLLOUT epollEventsError = syscall.EPOLLERR | syscall.EPOLLHUP | syscall.EPOLLRDHUP
epollEventsError = syscall.EPOLLERR | syscall.EPOLLHUP | syscall.EPOLLRDHUP
epollEventsReadET = syscall.EPOLLPRI | syscall.EPOLLIN | EPOLLET
epollEventsReadWriteET = syscall.EPOLLPRI | syscall.EPOLLIN | syscall.EPOLLOUT | EPOLLET
) )
type poller struct { type poller struct {
@ -142,7 +138,7 @@ func (p *poller) readWriteLoop() {
msec := -1 msec := -1
events := make([]syscall.EpollEvent, 1024) events := make([]syscall.EpollEvent, 1024)
if p.g.onRead == nil && p.g.epollMod == syscall.EPOLLET { if p.g.onRead == nil && p.g.epollMod == EPOLLET {
p.g.maxReadTimesPerEventLoop = 1<<31 - 1 p.g.maxReadTimesPerEventLoop = 1<<31 - 1
} }
@ -192,7 +188,7 @@ func (p *poller) readWriteLoop() {
if errors.Is(err, syscall.EAGAIN) { if errors.Is(err, syscall.EAGAIN) {
break break
} }
if err != nil || n == 0 { if err != nil {
c.closeWithError(err) c.closeWithError(err)
} }
if n < len(buffer) { if n < len(buffer) {
@ -224,11 +220,11 @@ func (p *poller) stop() {
} }
func (p *poller) addRead(fd int) error { func (p *poller) addRead(fd int) error {
switch int64(p.g.epollMod) { switch p.g.epollMod {
case int64(EPOLLET): case EPOLLET:
return syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_ADD, fd, &syscall.EpollEvent{Fd: int32(fd), Events: epollEventsReadET}) return syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_ADD, fd, &syscall.EpollEvent{Fd: int32(fd), Events: syscall.EPOLLERR | syscall.EPOLLHUP | syscall.EPOLLRDHUP | syscall.EPOLLPRI | syscall.EPOLLIN | EPOLLET})
default: default:
return syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_ADD, fd, &syscall.EpollEvent{Fd: int32(fd), Events: epollEventsRead}) return syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_ADD, fd, &syscall.EpollEvent{Fd: int32(fd), Events: syscall.EPOLLERR | syscall.EPOLLHUP | syscall.EPOLLRDHUP | syscall.EPOLLPRI | syscall.EPOLLIN})
} }
} }
@ -237,11 +233,11 @@ func (p *poller) addRead(fd int) error {
// } // }
func (p *poller) modWrite(fd int) error { func (p *poller) modWrite(fd int) error {
switch int64(p.g.epollMod) { switch p.g.epollMod {
case int64(EPOLLET): case EPOLLET:
return syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_ADD, fd, &syscall.EpollEvent{Fd: int32(fd), Events: epollEventsReadWriteET}) return syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_ADD, fd, &syscall.EpollEvent{Fd: int32(fd), Events: syscall.EPOLLERR | syscall.EPOLLHUP | syscall.EPOLLRDHUP | syscall.EPOLLPRI | syscall.EPOLLIN | syscall.EPOLLOUT | EPOLLET})
default: default:
return syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_MOD, fd, &syscall.EpollEvent{Fd: int32(fd), Events: epollEventsReadWrite}) return syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_MOD, fd, &syscall.EpollEvent{Fd: int32(fd), Events: syscall.EPOLLERR | syscall.EPOLLHUP | syscall.EPOLLRDHUP | syscall.EPOLLPRI | syscall.EPOLLIN | syscall.EPOLLOUT})
} }
} }

View File

@ -20,6 +20,7 @@ import "fmt"
import "sync" import "sync"
import "context" import "context"
import "runtime/debug" import "runtime/debug"
import "encoding/base64"
import "github.com/deroproject/derohe/rpc" import "github.com/deroproject/derohe/rpc"
import "github.com/deroproject/derohe/transaction" import "github.com/deroproject/derohe/transaction"
import "github.com/deroproject/derohe/cryptography/crypto" import "github.com/deroproject/derohe/cryptography/crypto"
@ -54,7 +55,13 @@ func Transfer(ctx context.Context, p rpc.Transfer_Params) (result rpc.Transfer_R
//fmt.Printf("incoming transfer params %+v\n", p) //fmt.Printf("incoming transfer params %+v\n", p)
if p.SC_Code != "" { if len(p.SC_Code) >= 1 { // decode SC from base64 if possible, since json has limitations
if sc, err := base64.StdEncoding.DecodeString(p.SC_Code); err == nil {
p.SC_Code = string(sc)
}
}
if p.SC_Code != "" && p.SC_ID == "" {
p.SC_RPC = append(p.SC_RPC, rpc.Argument{Name: rpc.SCACTION, DataType: rpc.DataUint64, Value: uint64(rpc.SC_INSTALL)}) p.SC_RPC = append(p.SC_RPC, rpc.Argument{Name: rpc.SCACTION, DataType: rpc.DataUint64, Value: uint64(rpc.SC_INSTALL)})
p.SC_RPC = append(p.SC_RPC, rpc.Argument{Name: rpc.SCCODE, DataType: rpc.DataString, Value: p.SC_Code}) p.SC_RPC = append(p.SC_RPC, rpc.Argument{Name: rpc.SCCODE, DataType: rpc.DataString, Value: p.SC_Code})
} }
@ -62,6 +69,9 @@ func Transfer(ctx context.Context, p rpc.Transfer_Params) (result rpc.Transfer_R
if p.SC_ID != "" { if p.SC_ID != "" {
p.SC_RPC = append(p.SC_RPC, rpc.Argument{Name: rpc.SCACTION, DataType: rpc.DataUint64, Value: uint64(rpc.SC_CALL)}) p.SC_RPC = append(p.SC_RPC, rpc.Argument{Name: rpc.SCACTION, DataType: rpc.DataUint64, Value: uint64(rpc.SC_CALL)})
p.SC_RPC = append(p.SC_RPC, rpc.Argument{Name: rpc.SCID, DataType: rpc.DataHash, Value: crypto.HashHexToHash(p.SC_ID)}) p.SC_RPC = append(p.SC_RPC, rpc.Argument{Name: rpc.SCID, DataType: rpc.DataHash, Value: crypto.HashHexToHash(p.SC_ID)})
if p.SC_Code != "" {
p.SC_RPC = append(p.SC_RPC, rpc.Argument{Name: rpc.SCCODE, DataType: rpc.DataString, Value: p.SC_Code})
}
} }
var tx *transaction.Transaction var tx *transaction.Transaction

View File

@ -63,6 +63,10 @@ func (w *Wallet_Memory) TransferPayload0(transfers []rpc.Transfer, ringsize uint
w.transfer_mutex.Lock() w.transfer_mutex.Lock()
defer w.transfer_mutex.Unlock() defer w.transfer_mutex.Unlock()
//if len(transfers) == 0 {
// return nil, fmt.Error("transfers is nil, cannot send.")
//}
if ringsize == 0 { if ringsize == 0 {
ringsize = uint64(w.account.Ringsize) // use wallet ringsize, if ringsize not provided ringsize = uint64(w.account.Ringsize) // use wallet ringsize, if ringsize not provided
} else { // we need to use supplied ringsize } else { // we need to use supplied ringsize